sammccall updated this revision to Diff 447675.
sammccall marked an inline comment as done.
sammccall added a comment.

address comments


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D130414/new/

https://reviews.llvm.org/D130414

Files:
  clang-tools-extra/pseudo/gen/Main.cpp
  clang-tools-extra/pseudo/include/clang-pseudo/cxx/CXX.h
  clang-tools-extra/pseudo/include/clang-pseudo/grammar/Grammar.h
  clang-tools-extra/pseudo/lib/cxx/CXX.cpp
  clang-tools-extra/pseudo/lib/grammar/Grammar.cpp
  clang-tools-extra/pseudo/unittests/GrammarTest.cpp

Index: clang-tools-extra/pseudo/unittests/GrammarTest.cpp
===================================================================
--- clang-tools-extra/pseudo/unittests/GrammarTest.cpp
+++ clang-tools-extra/pseudo/unittests/GrammarTest.cpp
@@ -113,15 +113,16 @@
   build(R"bnf(
     _ := declaration
 
-    declaration := ptr-declarator ;
+    declaration := cv-qualifier ptr-declarator ;
     ptr-declarator := * IDENTIFIER
+    cv-qualifier := CONST
 
   )bnf");
   ASSERT_TRUE(Diags.empty());
   EXPECT_EQ(G.mangleRule(ruleFor("declaration")),
-            "declaration_0ptr_declarator_1semi");
-  EXPECT_EQ(G.mangleRule(ruleFor("ptr-declarator")),
-            "ptr_declarator_0star_1identifier");
+            "cv_qualifier__ptr_declarator__semi");
+  EXPECT_EQ(G.mangleRule(ruleFor("ptr-declarator")), "star__identifier");
+  EXPECT_EQ(G.mangleRule(ruleFor("cv-qualifier")), "CONST");
 }
 
 TEST_F(GrammarTest, Diagnostics) {
Index: clang-tools-extra/pseudo/lib/grammar/Grammar.cpp
===================================================================
--- clang-tools-extra/pseudo/lib/grammar/Grammar.cpp
+++ clang-tools-extra/pseudo/lib/grammar/Grammar.cpp
@@ -45,28 +45,6 @@
   return T->Nonterminals[SID].Name;
 }
 
-std::string Grammar::mangleSymbol(SymbolID SID) const {
-  static const char *const TokNames[] = {
-#define TOK(X) #X,
-#define KEYWORD(X, Y) #X,
-#include "clang/Basic/TokenKinds.def"
-      nullptr};
-  if (clang::pseudo::isToken(SID))
-    return TokNames[clang::pseudo::symbolToToken(SID)];
-  std::string Name = symbolName(SID).str();
-  // translation-unit -> translation_unit
-  std::replace(Name.begin(), Name.end(), '-', '_');
-  return Name;
-}
-
-std::string Grammar::mangleRule(RuleID RID) const {
-  const auto &R = lookupRule(RID);
-  std::string MangleName = mangleSymbol(R.Target);
-  for (size_t I = 0; I < R.seq().size(); ++I)
-    MangleName += llvm::formatv("_{0}{1}", I, mangleSymbol(R.seq()[I]));
-  return MangleName;
-}
-
 llvm::Optional<SymbolID> Grammar::findNonterminal(llvm::StringRef Name) const {
   auto It = llvm::partition_point(
       T->Nonterminals,
Index: clang-tools-extra/pseudo/lib/cxx/CXX.cpp
===================================================================
--- clang-tools-extra/pseudo/lib/cxx/CXX.cpp
+++ clang-tools-extra/pseudo/lib/cxx/CXX.cpp
@@ -111,42 +111,41 @@
 }
 
 bool isFunctionDeclarator(const ForestNode *Declarator) {
-  assert(Declarator->symbol() == (SymbolID)(cxx::Symbol::declarator));
+  assert(Declarator->symbol() == cxx::Symbol::declarator);
   bool IsFunction = false;
-  using cxx::Rule;
   while (true) {
     // not well-formed code, return the best guess.
     if (Declarator->kind() != ForestNode::Sequence)
       return IsFunction;
 
-    switch ((cxx::Rule)Declarator->rule()) {
-    case Rule::noptr_declarator_0declarator_id: // reached the bottom
+    switch (Declarator->rule()) {
+    case rule::noptr_declarator::declarator_id: // reached the bottom
       return IsFunction;
     // *X is a nonfunction (unless X is a function).
-    case Rule::ptr_declarator_0ptr_operator_1ptr_declarator:
+    case rule::ptr_declarator::ptr_operator__ptr_declarator:
       Declarator = Declarator->elements()[1];
       IsFunction = false;
       continue;
     // X() is a function (unless X is a pointer or similar).
-    case Rule::
-        declarator_0noptr_declarator_1parameters_and_qualifiers_2trailing_return_type:
-    case Rule::noptr_declarator_0noptr_declarator_1parameters_and_qualifiers:
+    case rule::declarator::
+        noptr_declarator__parameters_and_qualifiers__trailing_return_type:
+    case rule::noptr_declarator::noptr_declarator__parameters_and_qualifiers:
       Declarator = Declarator->elements()[0];
       IsFunction = true;
       continue;
     // X[] is an array (unless X is a pointer or function).
-    case Rule::
-        noptr_declarator_0noptr_declarator_1l_square_2constant_expression_3r_square:
-    case Rule::noptr_declarator_0noptr_declarator_1l_square_2r_square:
+    case rule::noptr_declarator::
+        noptr_declarator__l_square__constant_expression__r_square:
+    case rule::noptr_declarator::noptr_declarator__l_square__r_square:
       Declarator = Declarator->elements()[0];
       IsFunction = false;
       continue;
     // (X) is whatever X is.
-    case Rule::noptr_declarator_0l_paren_1ptr_declarator_2r_paren:
+    case rule::noptr_declarator::l_paren__ptr_declarator__r_paren:
       Declarator = Declarator->elements()[1];
       continue;
-    case Rule::ptr_declarator_0noptr_declarator:
-    case Rule::declarator_0ptr_declarator:
+    case rule::ptr_declarator::noptr_declarator:
+    case rule::declarator::ptr_declarator:
       Declarator = Declarator->elements()[0];
       continue;
 
@@ -173,13 +172,13 @@
   // FIXME: every time we apply this check, we walk the whole subtree.
   // Add per-node caching instead.
   while (true) {
-    assert(N->symbol() == (SymbolID)Symbol::decl_specifier_seq ||
-           N->symbol() == (SymbolID)Symbol::type_specifier_seq ||
-           N->symbol() == (SymbolID)Symbol::defining_type_specifier_seq ||
-           N->symbol() == (SymbolID)Symbol::decl_specifier ||
-           N->symbol() == (SymbolID)Symbol::type_specifier ||
-           N->symbol() == (SymbolID)Symbol::defining_type_specifier ||
-           N->symbol() == (SymbolID)Symbol::simple_type_specifier);
+    assert(N->symbol() == Symbol::decl_specifier_seq ||
+           N->symbol() == Symbol::type_specifier_seq ||
+           N->symbol() == Symbol::defining_type_specifier_seq ||
+           N->symbol() == Symbol::decl_specifier ||
+           N->symbol() == Symbol::type_specifier ||
+           N->symbol() == Symbol::defining_type_specifier ||
+           N->symbol() == Symbol::simple_type_specifier);
     if (N->kind() == ForestNode::Opaque)
       return false; // conservative
     if (N->kind() == ForestNode::Ambiguous)
@@ -188,66 +187,66 @@
     assert(N->kind() == ForestNode::Sequence);
     switch (N->rule()) {
       // seq := element seq: check element then continue into seq
-      case (RuleID)Rule::decl_specifier_seq_0decl_specifier_1decl_specifier_seq:
-      case (RuleID)Rule::defining_type_specifier_seq_0defining_type_specifier_1defining_type_specifier_seq:
-      case (RuleID)Rule::type_specifier_seq_0type_specifier_1type_specifier_seq:
+      case rule::decl_specifier_seq::decl_specifier__decl_specifier_seq:
+      case rule::defining_type_specifier_seq::defining_type_specifier__defining_type_specifier_seq:
+      case rule::type_specifier_seq::type_specifier__type_specifier_seq:
         if (hasExclusiveType(N->children()[0]))
           return true;
         N = N->children()[1];
         continue;
       // seq := element: continue into element
-      case (RuleID)Rule::decl_specifier_seq_0decl_specifier:
-      case (RuleID)Rule::type_specifier_seq_0type_specifier:
-      case (RuleID)Rule::defining_type_specifier_seq_0defining_type_specifier:
+      case rule::decl_specifier_seq::decl_specifier:
+      case rule::type_specifier_seq::type_specifier:
+      case rule::defining_type_specifier_seq::defining_type_specifier:
         N = N->children()[0];
         continue;
 
       // defining-type-specifier
-      case (RuleID)Rule::defining_type_specifier_0type_specifier:
+      case rule::defining_type_specifier::type_specifier:
         N = N->children()[0];
         continue;
-      case (RuleID)Rule::defining_type_specifier_0class_specifier:
-      case (RuleID)Rule::defining_type_specifier_0enum_specifier:
+      case rule::defining_type_specifier::class_specifier:
+      case rule::defining_type_specifier::enum_specifier:
         return true;
 
       // decl-specifier
-      case (RuleID)Rule::decl_specifier_0defining_type_specifier:
+      case rule::decl_specifier::defining_type_specifier:
         N = N->children()[0];
         continue;
-      case (RuleID)Rule::decl_specifier_0consteval:
-      case (RuleID)Rule::decl_specifier_0constexpr:
-      case (RuleID)Rule::decl_specifier_0constinit:
-      case (RuleID)Rule::decl_specifier_0inline:
-      case (RuleID)Rule::decl_specifier_0friend:
-      case (RuleID)Rule::decl_specifier_0storage_class_specifier:
-      case (RuleID)Rule::decl_specifier_0typedef:
-      case (RuleID)Rule::decl_specifier_0function_specifier:
+      case rule::decl_specifier::CONSTEVAL:
+      case rule::decl_specifier::CONSTEXPR:
+      case rule::decl_specifier::CONSTINIT:
+      case rule::decl_specifier::INLINE:
+      case rule::decl_specifier::FRIEND:
+      case rule::decl_specifier::storage_class_specifier:
+      case rule::decl_specifier::TYPEDEF:
+      case rule::decl_specifier::function_specifier:
         return false;
 
       // type-specifier
-      case (RuleID)Rule::type_specifier_0elaborated_type_specifier:
-      case (RuleID)Rule::type_specifier_0typename_specifier:
+      case rule::type_specifier::elaborated_type_specifier:
+      case rule::type_specifier::typename_specifier:
         return true;
-      case (RuleID)Rule::type_specifier_0simple_type_specifier:
+      case rule::type_specifier::simple_type_specifier:
         N = N->children()[0];
         continue;
-      case (RuleID)Rule::type_specifier_0cv_qualifier:
+      case rule::type_specifier::cv_qualifier:
         return false;
 
       // simple-type-specifier
-      case (RuleID)Rule::simple_type_specifier_0type_name:
-      case (RuleID)Rule::simple_type_specifier_0template_name:
-      case (RuleID)Rule::simple_type_specifier_0builtin_type:
-      case (RuleID)Rule::simple_type_specifier_0nested_name_specifier_1template_2simple_template_id:
-      case (RuleID)Rule::simple_type_specifier_0nested_name_specifier_1template_name:
-      case (RuleID)Rule::simple_type_specifier_0nested_name_specifier_1type_name:
-      case (RuleID)Rule::simple_type_specifier_0decltype_specifier:
-      case (RuleID)Rule::simple_type_specifier_0placeholder_type_specifier:
+      case rule::simple_type_specifier::type_name:
+      case rule::simple_type_specifier::template_name:
+      case rule::simple_type_specifier::builtin_type:
+      case rule::simple_type_specifier::nested_name_specifier__TEMPLATE__simple_template_id:
+      case rule::simple_type_specifier::nested_name_specifier__template_name:
+      case rule::simple_type_specifier::nested_name_specifier__type_name:
+      case rule::simple_type_specifier::decltype_specifier:
+      case rule::simple_type_specifier::placeholder_type_specifier:
         return true;
-      case (RuleID)Rule::simple_type_specifier_0long:
-      case (RuleID)Rule::simple_type_specifier_0short:
-      case (RuleID)Rule::simple_type_specifier_0signed:
-      case (RuleID)Rule::simple_type_specifier_0unsigned:
+      case rule::simple_type_specifier::LONG:
+      case rule::simple_type_specifier::SHORT:
+      case rule::simple_type_specifier::SIGNED:
+      case rule::simple_type_specifier::UNSIGNED:
         return false;
 
       default:
@@ -269,96 +268,95 @@
   }
 #define SYMBOL_GUARD(kind, cond)                                               \
   [](const GuardParams& P) {                                                   \
-    const ForestNode &N = onlySymbol((SymbolID)Symbol::kind, P.RHS, P.Tokens); \
+    const ForestNode &N = onlySymbol(Symbol::kind, P.RHS, P.Tokens); \
     return cond;                                                               \
   }
   return {
-      {(RuleID)Rule::function_declarator_0declarator,
+      {rule::function_declarator::declarator,
        SYMBOL_GUARD(declarator, isFunctionDeclarator(&N))},
-      {(RuleID)Rule::non_function_declarator_0declarator,
+      {rule::non_function_declarator::declarator,
        SYMBOL_GUARD(declarator, !isFunctionDeclarator(&N))},
 
       // A {decl,type,defining-type}-specifier-sequence cannot have multiple
       // "exclusive" types (like class names): a value has only one type.
-      {(RuleID)Rule::
-           defining_type_specifier_seq_0defining_type_specifier_1defining_type_specifier_seq,
+      {rule::defining_type_specifier_seq::
+           defining_type_specifier__defining_type_specifier_seq,
        GUARD(!hasExclusiveType(P.RHS[0]) || !hasExclusiveType(P.RHS[1]))},
-      {(RuleID)Rule::type_specifier_seq_0type_specifier_1type_specifier_seq,
+      {rule::type_specifier_seq::type_specifier__type_specifier_seq,
        GUARD(!hasExclusiveType(P.RHS[0]) || !hasExclusiveType(P.RHS[1]))},
-      {(RuleID)Rule::decl_specifier_seq_0decl_specifier_1decl_specifier_seq,
+      {rule::decl_specifier_seq::decl_specifier__decl_specifier_seq,
        GUARD(!hasExclusiveType(P.RHS[0]) || !hasExclusiveType(P.RHS[1]))},
 
-      {(RuleID)Rule::contextual_override_0identifier,
+      {rule::contextual_override::identifier,
        TOKEN_GUARD(identifier, Tok.text() == "override")},
-      {(RuleID)Rule::contextual_final_0identifier,
+      {rule::contextual_final::identifier,
        TOKEN_GUARD(identifier, Tok.text() == "final")},
-      {(RuleID)Rule::import_keyword_0identifier,
+      {rule::import_keyword::identifier,
        TOKEN_GUARD(identifier, Tok.text() == "import")},
-      {(RuleID)Rule::export_keyword_0identifier,
+      {rule::export_keyword::identifier,
        TOKEN_GUARD(identifier, Tok.text() == "export")},
-      {(RuleID)Rule::module_keyword_0identifier,
+      {rule::module_keyword::identifier,
        TOKEN_GUARD(identifier, Tok.text() == "module")},
-      {(RuleID)Rule::contextual_zero_0numeric_constant,
+      {rule::contextual_zero::numeric_constant,
        TOKEN_GUARD(numeric_constant, Tok.text() == "0")},
 
-      {(RuleID)Rule::
-           selection_statement_0if_1l_paren_2condition_3r_paren_4statement,
+      {rule::selection_statement::IF__l_paren__condition__r_paren__statement,
        guardNextTokenNotElse},
-      {(RuleID)Rule::
-           selection_statement_0if_1constexpr_2l_paren_3condition_4r_paren_5statement,
+      {rule::selection_statement::
+           IF__CONSTEXPR__l_paren__condition__r_paren__statement,
        guardNextTokenNotElse},
 
       // The grammar distinguishes (only) user-defined vs plain string literals,
       // where the clang lexer distinguishes (only) encoding types.
-      {(RuleID)Rule::user_defined_string_literal_chunk_0string_literal,
+      {rule::user_defined_string_literal_chunk::string_literal,
        TOKEN_GUARD(string_literal, isStringUserDefined(Tok))},
-      {(RuleID)Rule::user_defined_string_literal_chunk_0utf8_string_literal,
+      {rule::user_defined_string_literal_chunk::utf8_string_literal,
        TOKEN_GUARD(utf8_string_literal, isStringUserDefined(Tok))},
-      {(RuleID)Rule::user_defined_string_literal_chunk_0utf16_string_literal,
+      {rule::user_defined_string_literal_chunk::utf16_string_literal,
        TOKEN_GUARD(utf16_string_literal, isStringUserDefined(Tok))},
-      {(RuleID)Rule::user_defined_string_literal_chunk_0utf32_string_literal,
+      {rule::user_defined_string_literal_chunk::utf32_string_literal,
        TOKEN_GUARD(utf32_string_literal, isStringUserDefined(Tok))},
-      {(RuleID)Rule::user_defined_string_literal_chunk_0wide_string_literal,
+      {rule::user_defined_string_literal_chunk::wide_string_literal,
        TOKEN_GUARD(wide_string_literal, isStringUserDefined(Tok))},
-      {(RuleID)Rule::string_literal_chunk_0string_literal,
+      {rule::string_literal_chunk::string_literal,
        TOKEN_GUARD(string_literal, !isStringUserDefined(Tok))},
-      {(RuleID)Rule::string_literal_chunk_0utf8_string_literal,
+      {rule::string_literal_chunk::utf8_string_literal,
        TOKEN_GUARD(utf8_string_literal, !isStringUserDefined(Tok))},
-      {(RuleID)Rule::string_literal_chunk_0utf16_string_literal,
+      {rule::string_literal_chunk::utf16_string_literal,
        TOKEN_GUARD(utf16_string_literal, !isStringUserDefined(Tok))},
-      {(RuleID)Rule::string_literal_chunk_0utf32_string_literal,
+      {rule::string_literal_chunk::utf32_string_literal,
        TOKEN_GUARD(utf32_string_literal, !isStringUserDefined(Tok))},
-      {(RuleID)Rule::string_literal_chunk_0wide_string_literal,
+      {rule::string_literal_chunk::wide_string_literal,
        TOKEN_GUARD(wide_string_literal, !isStringUserDefined(Tok))},
       // And the same for chars.
-      {(RuleID)Rule::user_defined_character_literal_0char_constant,
+      {rule::user_defined_character_literal::char_constant,
        TOKEN_GUARD(char_constant, isCharUserDefined(Tok))},
-      {(RuleID)Rule::user_defined_character_literal_0utf8_char_constant,
+      {rule::user_defined_character_literal::utf8_char_constant,
        TOKEN_GUARD(utf8_char_constant, isCharUserDefined(Tok))},
-      {(RuleID)Rule::user_defined_character_literal_0utf16_char_constant,
+      {rule::user_defined_character_literal::utf16_char_constant,
        TOKEN_GUARD(utf16_char_constant, isCharUserDefined(Tok))},
-      {(RuleID)Rule::user_defined_character_literal_0utf32_char_constant,
+      {rule::user_defined_character_literal::utf32_char_constant,
        TOKEN_GUARD(utf32_char_constant, isCharUserDefined(Tok))},
-      {(RuleID)Rule::user_defined_character_literal_0wide_char_constant,
+      {rule::user_defined_character_literal::wide_char_constant,
        TOKEN_GUARD(wide_char_constant, isCharUserDefined(Tok))},
-      {(RuleID)Rule::character_literal_0char_constant,
+      {rule::character_literal::char_constant,
        TOKEN_GUARD(char_constant, !isCharUserDefined(Tok))},
-      {(RuleID)Rule::character_literal_0utf8_char_constant,
+      {rule::character_literal::utf8_char_constant,
        TOKEN_GUARD(utf8_char_constant, !isCharUserDefined(Tok))},
-      {(RuleID)Rule::character_literal_0utf16_char_constant,
+      {rule::character_literal::utf16_char_constant,
        TOKEN_GUARD(utf16_char_constant, !isCharUserDefined(Tok))},
-      {(RuleID)Rule::character_literal_0utf32_char_constant,
+      {rule::character_literal::utf32_char_constant,
        TOKEN_GUARD(utf32_char_constant, !isCharUserDefined(Tok))},
-      {(RuleID)Rule::character_literal_0wide_char_constant,
+      {rule::character_literal::wide_char_constant,
        TOKEN_GUARD(wide_char_constant, !isCharUserDefined(Tok))},
       // clang just has one NUMERIC_CONSTANT token for {ud,plain}x{float,int}
-      {(RuleID)Rule::user_defined_integer_literal_0numeric_constant,
+      {rule::user_defined_integer_literal::numeric_constant,
        TOKEN_GUARD(numeric_constant, numKind(Tok) == (Integer | UserDefined))},
-      {(RuleID)Rule::user_defined_floating_point_literal_0numeric_constant,
+      {rule::user_defined_floating_point_literal::numeric_constant,
        TOKEN_GUARD(numeric_constant, numKind(Tok) == (Floating | UserDefined))},
-      {(RuleID)Rule::integer_literal_0numeric_constant,
+      {rule::integer_literal::numeric_constant,
        TOKEN_GUARD(numeric_constant, numKind(Tok) == Integer)},
-      {(RuleID)Rule::floating_point_literal_0numeric_constant,
+      {rule::floating_point_literal::numeric_constant,
        TOKEN_GUARD(numeric_constant, numKind(Tok) == Floating)},
   };
 #undef TOKEN_GUARD
@@ -379,7 +377,7 @@
 
 llvm::DenseMap<ExtensionID, RecoveryStrategy> buildRecoveryStrategies() {
   return {
-      {(ExtensionID)Extension::Brackets, recoverBrackets},
+      {Extension::Brackets, recoverBrackets},
   };
 }
 
Index: clang-tools-extra/pseudo/include/clang-pseudo/grammar/Grammar.h
===================================================================
--- clang-tools-extra/pseudo/include/clang-pseudo/grammar/Grammar.h
+++ clang-tools-extra/pseudo/include/clang-pseudo/grammar/Grammar.h
@@ -162,21 +162,6 @@
   // Terminals have names like "," (kw_comma) or "OPERATOR" (kw_operator).
   llvm::StringRef symbolName(SymbolID) const;
 
-  // Gets the mangled name for a terminal/nonterminal.
-  // Compared to names in the grammar,
-  //   nonterminals `ptr-declartor` becomes `ptr_declarator`;
-  //   terminal `,` becomes `comma`;
-  //   terminal `IDENTIFIER` becomes `identifier`;
-  //   terminal `INT` becomes `int`;
-  // NOTE: for nonterminals, the mangled name is the same as the cxx::Symbol
-  // enum class; for terminals, we deliberately stripped the `kw_` prefix in
-  // favor of the simplicity.
-  std::string mangleSymbol(SymbolID) const;
-  // Gets the mangled name for the rule.
-  // E.g. for the grammar rule `ptr-declarator := ptr-operator ptr-declarator`,
-  // it is `ptr_declarator_0ptr_operator_1ptr_declarator`.
-  std::string mangleRule(RuleID) const;
-
   // Lookup the SymbolID of the nonterminal symbol by Name.
   llvm::Optional<SymbolID> findNonterminal(llvm::StringRef Name) const;
 
Index: clang-tools-extra/pseudo/include/clang-pseudo/cxx/CXX.h
===================================================================
--- clang-tools-extra/pseudo/include/clang-pseudo/cxx/CXX.h
+++ clang-tools-extra/pseudo/include/clang-pseudo/cxx/CXX.h
@@ -29,25 +29,56 @@
 namespace clang {
 namespace pseudo {
 namespace cxx {
-// Symbol represents nonterminal symbols in the C++ grammar.
-// It provides a simple uniform way to access a particular nonterminal.
-enum class Symbol : SymbolID {
+
+// We want enums to be scoped but implicitly convertible to RuleID etc.
+// So create regular (unscoped) enums inside subnamespaces of `detail`.
+// Then add aliases for them outside `detail`.
+namespace detail {
+namespace symbols {
+enum Symbol : SymbolID {
 #define NONTERMINAL(X, Y) X = Y,
 #include "CXXSymbols.inc"
 #undef NONTERMINAL
 };
+} // namespace symbols
 
-enum class Rule : RuleID {
-#define RULE(X, Y) X = Y,
+namespace extensions {
+enum Extension : ExtensionID {
+#define EXTENSION(X, Y) X = Y,
 #include "CXXSymbols.inc"
-#undef RULE
+#undef EXTENSION
 };
+} // namespace extensions
 
-enum class Extension : ExtensionID {
-#define EXTENSION(X, Y) X = Y,
+namespace rules {
+// For each symbol we close the last symbol's enum+namespace and open new ones.
+// We need a dummy namespace+enum so that this works for the first rule.
+namespace dummy {
+enum Rule {
+//clang-format off
+#define NONTERMINAL(NAME, ID) \
+};                            \
+}                             \
+namespace NAME {              \
+enum Rule : RuleID {
+//clang-format on
+#define RULE(LHS, RHS, ID) RHS = ID,
 #include "CXXSymbols.inc"
-#undef EXTENSION
 };
+}
+} // namespace rules
+} // namespace detail
+
+// Symbol represents nonterminal symbols in the C++ grammar.
+// It provides a simple uniform way to access a particular nonterminal.
+using Symbol = detail::symbols::Symbol;
+
+using Extension = detail::extensions::Extension;
+
+namespace rule {
+#define NONTERMINAL(NAME, ID) using NAME = detail::rules::NAME::Rule;
+#include "CXXSymbols.inc"
+} // namespace rule
 
 // Returns the Language for the cxx.bnf grammar.
 const Language &getLanguage();
Index: clang-tools-extra/pseudo/gen/Main.cpp
===================================================================
--- clang-tools-extra/pseudo/gen/Main.cpp
+++ clang-tools-extra/pseudo/gen/Main.cpp
@@ -58,6 +58,50 @@
 }
 } // namespace
 
+namespace clang {
+namespace pseudo {
+namespace {
+
+// Mangles a symbol name into a valid identifier.
+//
+// These follow names in the grammar fairly closely:
+//   nonterminal: `ptr-declartor` becomes `ptr_declarator`;
+//   punctuator: `,` becomes `COMMA`;
+//   keyword: `INT` becomes `INT`;
+//   terminal: `IDENTIFIER` becomes `IDENTIFIER`;
+std::string mangleSymbol(SymbolID SID, const Grammar &G) {
+  static std::string *TokNames = new std::string[]{
+#define TOK(X) llvm::StringRef(#X).upper(),
+#define KEYWORD(Keyword, Condition) llvm::StringRef(#Keyword).upper(),
+#include "clang/Basic/TokenKinds.def"
+      };
+  if (isToken(SID))
+    return TokNames[symbolToToken(SID)];
+  std::string Name = G.symbolName(SID).str();
+  // translation-unit -> translation_unit
+  std::replace(Name.begin(), Name.end(), '-', '_');
+  return Name;
+}
+
+// Mangles the RHS of a rule definition into a valid identifier.
+// 
+// These are unique only for a fixed LHS.
+// e.g. for the grammar rule `ptr-declarator := ptr-operator ptr-declarator`,
+// it is `ptr_operator__ptr_declarator`.
+std::string mangleRule(RuleID RID, const Grammar &G) {
+  const auto &R = G.lookupRule(RID);
+  std::string MangleName = mangleSymbol(R.seq().front(), G);
+  for (SymbolID S : R.seq().drop_front()) {
+    MangleName.append("__");
+    MangleName.append(mangleSymbol(S, G));
+  }
+  return MangleName;
+}
+
+} // namespace
+} // namespace pseudo
+} // namespace clang
+
 int main(int argc, char *argv[]) {
   llvm::cl::ParseCommandLineOptions(argc, argv, "");
 
@@ -81,21 +125,26 @@
   case EmitSymbolList:
     Out.os() << R"cpp(
 #ifndef NONTERMINAL
-#define NONTERMINAL(X, Y)
+#define NONTERMINAL(NAME, ID)
 #endif
 #ifndef RULE
-#define RULE(X, Y)
+#define RULE(LHS, RHS, ID)
 #endif
 #ifndef EXTENSION
-#define EXTENSION(X, Y)
+#define EXTENSION(NAME, ID)
 #endif
 )cpp";
     for (clang::pseudo::SymbolID ID = 0; ID < G.table().Nonterminals.size();
-         ++ID)
-      Out.os() << llvm::formatv("NONTERMINAL({0}, {1})\n", G.mangleSymbol(ID),
-                                ID);
-    for (clang::pseudo::RuleID RID = 0; RID < G.table().Rules.size(); ++RID)
-      Out.os() << llvm::formatv("RULE({0}, {1})\n", G.mangleRule(RID), RID);
+         ++ID) {
+      Out.os() << llvm::formatv("NONTERMINAL({0}, {1})\n",
+                                clang::pseudo::mangleSymbol(ID, G), ID);
+      for (const clang::pseudo::Rule &R : G.rulesFor(ID)) {
+        clang::pseudo::RuleID RID = &R - G.table().Rules.data();
+        Out.os() << llvm::formatv("RULE({0}, {1}, {2})\n",
+                                  clang::pseudo::mangleSymbol(R.Target, G),
+                                  clang::pseudo::mangleRule(RID, G), RID);
+      }
+    }
     for (clang::pseudo::ExtensionID EID = 1 /*skip the sentinel 0 value*/;
          EID < G.table().AttributeValues.size(); ++EID) {
       llvm::StringRef Name = G.table().AttributeValues[EID];
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to