diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h
--- a/clang/lib/Format/FormatToken.h
+++ b/clang/lib/Format/FormatToken.h
@@ -143,6 +143,8 @@
   TYPE(VerilogDimensionedTypeName)                                             \
   /* for the base in a number literal, not including the quote */              \
   TYPE(VerilogNumberBase)                                                      \
+  /* Things inside the table in user-defined primitives. */                    \
+  TYPE(VerilogTableItem)                                                       \
   TYPE(Unknown)
 
 /// Determines the semantic type of a syntactic token, e.g. whether "<" is a
diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp
--- a/clang/lib/Format/TokenAnnotator.cpp
+++ b/clang/lib/Format/TokenAnnotator.cpp
@@ -917,6 +917,10 @@
   bool consumeToken() {
     FormatToken *Tok = CurrentToken;
     next();
+    // In Verilog primitives' state tables, `:`, `?`, and `-` aren't normal
+    // operators.
+    if (Tok->is(TT_VerilogTableItem))
+      return true;
     switch (Tok->Tok.getKind()) {
     case tok::plus:
     case tok::minus:
@@ -3996,8 +4000,16 @@
       return true;
     }
   } else if (Style.isVerilog()) {
+    // Add space between things in a primitive's state table unless in a
+    // transition like `(0?)`.
+    if ((Left.is(TT_VerilogTableItem) &&
+         !Right.isOneOf(tok::r_paren, tok::semi)) ||
+        (Right.is(TT_VerilogTableItem) && Left.isNot(tok::l_paren))) {
+      const FormatToken *Next = Right.getNextNonComment();
+      return !(Next && Next->is(tok::r_paren));
+    }
     // Don't add space within a delay like `#0`.
-    if (!Left.is(TT_BinaryOperator) &&
+    if (Left.isNot(TT_BinaryOperator) &&
         Left.isOneOf(Keywords.kw_verilogHash, Keywords.kw_verilogHashHash)) {
       return false;
     }
diff --git a/clang/lib/Format/UnwrappedLineParser.h b/clang/lib/Format/UnwrappedLineParser.h
--- a/clang/lib/Format/UnwrappedLineParser.h
+++ b/clang/lib/Format/UnwrappedLineParser.h
@@ -183,6 +183,7 @@
   // Returns the number of levels of indentation in addition to the normal 1
   // level for a block, used for indenting case labels.
   unsigned parseVerilogHierarchyHeader();
+  void parseVerilogTable();
 
   // Used by addUnwrappedLine to denote whether to keep or remove a level
   // when resetting the line state.
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp
--- a/clang/lib/Format/UnwrappedLineParser.cpp
+++ b/clang/lib/Format/UnwrappedLineParser.cpp
@@ -1913,6 +1913,10 @@
       }
 
       if (Style.isVerilog()) {
+        if (FormatTok->is(Keywords.kw_table)) {
+          parseVerilogTable();
+          return;
+        }
         if (Keywords.isVerilogBegin(*FormatTok) ||
             Keywords.isVerilogHierarchy(*FormatTok)) {
           parseBlock();
@@ -4039,7 +4043,8 @@
 }
 
 void UnwrappedLineParser::parseVerilogSensitivityList() {
-  assert(FormatTok->is(tok::at));
+  if (!FormatTok->is(tok::at))
+    return;
   nextToken();
   // A block event expression has 2 at signs.
   if (FormatTok->is(tok::at))
@@ -4064,15 +4069,13 @@
     nextToken();
     if (Keywords.isVerilogIdentifier(*FormatTok))
       nextToken();
-    if (FormatTok->is(tok::at))
-      parseVerilogSensitivityList();
+    parseVerilogSensitivityList();
     if (FormatTok->is(tok::semi))
       nextToken();
   } else if (FormatTok->isOneOf(tok::kw_case, Keywords.kw_casex,
                                 Keywords.kw_casez, Keywords.kw_randcase,
                                 Keywords.kw_randsequence)) {
-    if (Style.IndentCaseLabels)
-      ++AddLevels;
+    AddLevels += Style.IndentCaseLabels;
     nextToken();
     if (FormatTok->is(tok::l_paren))
       parseParens();
@@ -4154,6 +4157,25 @@
   return AddLevels;
 }
 
+void UnwrappedLineParser::parseVerilogTable() {
+  assert(FormatTok->is(Keywords.kw_table));
+  nextToken(/*LevelDifference=*/1);
+  addUnwrappedLine();
+
+  auto InitialLevel = Line->Level++;
+  while (!eof() && !Keywords.isVerilogEnd(*FormatTok)) {
+    FormatToken *Tok = FormatTok;
+    nextToken();
+    if (Tok->is(tok::semi))
+      addUnwrappedLine();
+    else if (Tok->isOneOf(tok::star, tok::colon, tok::question, tok::minus))
+      Tok->setFinalizedType(TT_VerilogTableItem);
+  }
+  Line->Level = InitialLevel;
+  nextToken(/*LevelDifference=*/-1);
+  addUnwrappedLine();
+}
+
 LLVM_ATTRIBUTE_UNUSED static void printDebugInfo(const UnwrappedLine &Line,
                                                  StringRef Prefix = "") {
   llvm::dbgs() << Prefix << "Line(" << Line.Level
diff --git a/clang/unittests/Format/FormatTestVerilog.cpp b/clang/unittests/Format/FormatTestVerilog.cpp
--- a/clang/unittests/Format/FormatTestVerilog.cpp
+++ b/clang/unittests/Format/FormatTestVerilog.cpp
@@ -441,5 +441,46 @@
   }
 }
 
+TEST_F(FormatTestVerilog, Primitive) {
+  verifyFormat("primitive multiplexer\n"
+               "    (mux, control, dataA, dataB);\n"
+               "  output mux;\n"
+               "  input control, dataA, dataB;\n"
+               "  table\n"
+               "    0 1 ? : 1;\n"
+               "    0 0 ? : 0;\n"
+               "    1 ? 1 : 1;\n"
+               "    1 ? 0 : 0;\n"
+               "    x 0 0 : 0;\n"
+               "    x 1 1 : 1;\n"
+               "  endtable\n"
+               "endprimitive");
+  verifyFormat("primitive latch\n"
+               "    (q, ena_, data);\n"
+               "  output q;\n"
+               "  reg q;\n"
+               "  input ena_, data;\n"
+               "  table\n"
+               "    0 1 : ? : 1;\n"
+               "    0 0 : ? : 0;\n"
+               "    1 ? : ? : -;\n"
+               "    ? * : ? : -;\n"
+               "  endtable\n"
+               "endprimitive");
+  verifyFormat("primitive d\n"
+               "    (q, clock, data);\n"
+               "  output q;\n"
+               "  reg q;\n"
+               "  input clock, data;\n"
+               "  table\n"
+               "    (01) 0 : ? : 0;\n"
+               "    (01) 1 : ? : 1;\n"
+               "    (0?) 1 : 1 : 1;\n"
+               "    (0?) 0 : 0 : 0;\n"
+               "    (?0) ? : ? : -;\n"
+               "    (?\?) ? : ? : -;\n"
+               "  endtable\n"
+               "endprimitive");
+}
 } // namespace format
 } // end namespace clang