sammccall created this revision.
sammccall added reviewers: hokein, usaxena95.
Herald added a project: All.
sammccall requested review of this revision.
Herald added subscribers: cfe-commits, alextsao1999.
Herald added a project: clang-tools-extra.
- Place rules under rule::lhs::rhs__rhs__rhs
- Change mangling of keywords to ALL_CAPS (needed to turn keywords that appear
alone on RHS into valid identifiers)
- Make enums implicitly convertible to underlying type (though still scoped,
using alias tricks)
In principle this lets us exhaustively write a switch over all rules of a NT:
switch ((rule::declarator)N->rule()) {
case rule::declarator::noptr_declarator:
...
}
In practice we don't do this anywhere yet as we're often switching over multiple
nonterminal kinds at once.
Repository:
rG LLVM Github Monorepo
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/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
@@ -46,11 +46,11 @@
}
std::string Grammar::mangleSymbol(SymbolID SID) const {
- static const char *const TokNames[] = {
+ static std::string *TokNames = new std::string[]{
#define TOK(X) #X,
-#define KEYWORD(X, Y) #X,
+#define KEYWORD(Keyword, Condition) llvm::StringRef(#Keyword).upper(),
#include "clang/Basic/TokenKinds.def"
- nullptr};
+ };
if (clang::pseudo::isToken(SID))
return TokNames[clang::pseudo::symbolToToken(SID)];
std::string Name = symbolName(SID).str();
@@ -61,9 +61,13 @@
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]));
+ std::string MangleName;
+ for (size_t I = 0; I < R.seq().size(); ++I) {
+ MangleName += mangleSymbol(R.seq()[I]);
+ MangleName.append("__");
+ }
+ MangleName.pop_back();
+ MangleName.pop_back();
return MangleName;
}
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,40 +111,39 @@
bool isFunctionDeclarator(const ForestNode *Declarator) {
assert(Declarator->symbol() == (SymbolID)(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;
@@ -172,80 +171,81 @@
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))},
- {(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,
- guardNextTokenNotElse},
- {(RuleID)Rule::selection_statement_0if_1constexpr_2l_paren_3condition_4r_paren_5statement,
- guardNextTokenNotElse},
+ {rule::selection_statement::IF__l_paren__condition__r_paren__statement,
+ guardNextTokenNotElse},
+ {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
@@ -266,7 +266,7 @@
llvm::DenseMap<ExtensionID, RecoveryStrategy> buildRecoveryStrategies() {
return {
- {(ExtensionID)Extension::Brackets, recoverBrackets},
+ {Extension::Brackets, recoverBrackets},
};
}
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,50 @@
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 {
+namespace dummy {
+enum Rule {
+//clang-format off
+#define NONTERMINAL(NAME, ID) };} namespace NAME { enum Rule : RuleID {
+#define RULE(LHS, RHS, ID) RHS = ID,
#include "CXXSymbols.inc"
-#undef EXTENSION
+ //clang-format on
};
+}
+} // 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
@@ -81,21 +81,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)
+ ++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);
+ 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",
+ G.mangleSymbol(R.Target), G.mangleRule(RID),
+ 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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits