diff options
| author | Roland Reichwein <mail@reichwein.it> | 2020-02-04 21:21:39 +0100 | 
|---|---|---|
| committer | Roland Reichwein <mail@reichwein.it> | 2020-02-04 21:21:39 +0100 | 
| commit | 7b3c48e4b0fed9369f8d62854eb6e2453888fe75 (patch) | |
| tree | 69c24211c46375fa59288d27e9d94b289eedd5e1 | |
| parent | d99d80e862c2799d0dc9a567b710c7b05d6a47a4 (diff) | |
C++20 grammar
| -rwxr-xr-x | cppbnf.cpp | 1933 | 
1 files changed, 1933 insertions, 0 deletions
| diff --git a/cppbnf.cpp b/cppbnf.cpp new file mode 100755 index 0000000..5266fa0 --- /dev/null +++ b/cppbnf.cpp @@ -0,0 +1,1933 @@ +#include "bnf.h" + +#include <algorithm> +#include <unordered_set> +#include <unordered_map> +#include <utility> + +#include <boost/algorithm/string/predicate.hpp> + +#include <gtest/gtest.h> +#include <gmock/gmock.h> + +using namespace std::string_literals; + +namespace { + + // "..." -> {".", ".", "."} + std::vector<std::string> vectorize(std::string s) { +  std::vector<std::string> result; +  std::for_each(s.begin(), s.end(), [&](const char c) {result.push_back(std::string( 1, c )); }); +  return result; + } + + std::unordered_map<std::string, std::unordered_set<std::string>> reverseBNF(const T_BNF& bnf) + { +  std::unordered_map<std::string, std::unordered_set<std::string>> result; +  for (const auto& [symbol, lists] : bnf) { +   for (const auto& list : lists) { +    for (const auto& i : list) { +     auto it = result.find(i); +     if (it == result.end()) +      result.emplace(i, std::unordered_set<std::string>{symbol}); +     else +      it->second.insert(symbol); +    } +   } +  } + +  return result; + } + + bool isTerminal(const std::string& symbol, const T_BNF& bnf) + { +  return bnf.find(symbol) == bnf.end(); + } + + size_t numberOfStartSymbols(const T_BNF& bnf) + { +  // exactly 1 start symbol +  std::vector<std::string> startSymbols; + +  auto reverse{ reverseBNF(bnf) }; + +  for (const auto& [symbol, lists] : bnf) { +   if (reverse.find(symbol) == reverse.end()) +    startSymbols.push_back(symbol); +  } + +  if (startSymbols.size() > 1) { +   std::cout << "Start symbols:" << std::endl; +   for (const auto& i : startSymbols) +    std::cout << " " << i << std::endl; +  } +  return startSymbols.size(); + } + + bool symbolsValid(const T_BNF& bnf) + { +  for (const auto& [symbol, lists] : bnf) { +   if (boost::contains(symbol, " ")) { +    std::cerr << "Warning: Symbol " << symbol << " contains space." << std::endl; +    return false; +   } + +   for (const auto& list : lists) { +    for (const auto& i : list) { +     if (i.size() == 1 && !isTerminal(i, bnf)) { +      std::cerr << "Warning: Non-Terminal symbol " << i << " in " << symbol << " is too long." << std::endl; +      return false; +     } + +     if (boost::contains(i, " ")) { +      std::cerr << "Warning: Symbol " << i << " in " << symbol << " contains space." << std::endl; +      return false; +     } +    } +   } +  } + +  return true; + } + + // returns 1 if exactly one start symbol and + // all nodes size > 1, except terminal symbols + bool valid(const T_BNF& bnf) { +  return numberOfStartSymbols(bnf) == 1 && symbolsValid(bnf); + } + + bool validLex(const T_BNF& bnf) { +  // all terminal symbols exactly one character + +  for (const auto& [symbol, lists] : bnf) { +   for (const auto& list : lists) { +    for (const auto& i : list) { +     if (i.size() != 1 && isTerminal(i, bnf)) { +      std::cerr << "Warning: Terminal symbol in " << symbol << " is too long: "s << i << std::endl; +      return false; +     } +    } +   } +  } + +  return true; + } + + const std::string optionalMarker{"OPTIONAL:"}; + + std::string optional(const std::string& s) + { +  return optionalMarker + s; + } + + std::vector<std::string> all_except(const std::vector<std::string>& blacklist) + { +  std::vector<std::string> result; + +  for (char c = 0x20; c <= 0x7e; c++) { +   std::string s{1, c}; +   if (std::find(blacklist.begin(), blacklist.end(), s) == blacklist.end()) +    result.push_back(s); +  } + +  return result; + } + + bool containsOptional(const std::vector<std::string>& list) + { +  return std::any_of(list.begin(), list.end(), [](const std::string& s) {return boost::starts_with(s, optionalMarker); }); + } + + std::vector<std::vector<std::string>> resolveOptional(const std::vector<std::string>& list) + { +  std::vector<std::vector<std::string>> result{1, list}; + +  while (std::find_if(result[0].begin(), result[0].end(), [](const std::string& s) {return boost::starts_with(s, optionalMarker); }) != result[0].end()) +  { +   size_t size = result.size(); + +   // remove from all entries (all have same OPTIONAL property) the OPTIONAL and append a version without this entry +   for (size_t i = 0; i < size; i++) { +    std::vector<std::string> newList = result[i]; + +    size_t index = std::find_if(result[i].begin(), result[i].end(), [](const std::string& s) {return boost::starts_with(s, optionalMarker); }) - result[i].begin(); +    auto& oldString = result[i][index]; +    oldString = oldString.substr(optionalMarker.size()); // Remove OPTIONAL marker inside old list + +    newList.erase(newList.begin() + index); // Add removed version of list +    result.push_back(newList); +   } +  } +   +  return result; + } + + void resolveOptional(std::vector<std::vector<std::string>>& lists) + { +  for (int i = 0; i < lists.size(); i++) { +   if (containsOptional(lists[i])) { +    auto insertList = resolveOptional(lists[i]); +    // replace element i with new list +    lists.erase(lists.begin() + i); +    lists.insert(lists.begin() + i, insertList.begin(), insertList.end()); +   } +  } + } + + T_BNF& normalizeBNF(T_BNF& bnf) + { +  // resolve OPTIONAL symbols +  for (auto& [symbol, lists] : bnf) { +   resolveOptional(lists); +  } + +  return bnf; + } + + T_BNF& normalizeLexBNF(T_BNF& bnf) + { +  normalizeBNF(bnf); + +  // vectorize terminal symbols +  for (auto& [symbol, lists] : bnf) { +   for (auto& list : lists) { +    for (int i = 0; i < list.size(); i++) { +     if (list[i].size() > 1 && isTerminal(list[i], bnf)) { +      auto newList = vectorize(list[i]); +      list.erase(list.begin() + i); +      list.insert(list.begin() + i, newList.begin(), newList.end()); +     } +    } +   } +  } + +  return bnf; + } + +} // namespace + +T_BNF GetCppBNFLex() +{ + T_BNF bnf{ +  // [gram.lex] + +  {"hex-quad", {{"hexadecimal-digit", "hexadecimal-digit", "hexadecimal-digit", "hexadecimal-digit"}}}, + +  {"universal-character-name", { +   {"\\", "u", "hex-quad"}, +   {"\\", "U", "hex-quad", "hex-quad"} +  }}, + +  {"preprocessing-token", { +   {"header-name"}, +   {"import-keyword"}, +   {"identifier"}, +   {"pp-number"}, +   {"character-literal"}, +   {"user-defined-character-literal"}, +   {"string-literal"}, +   {"user-defined-string-literal"}, +   {"preprocessing-op-or-punc"}, +   // + other non-whitespace: TODO +  }}, + +  {"token", { // lex -> gram +   {"identifier"}, +   {"keyword"}, +   {"literal"}, +   {"OPERATOR"}, // conflict with keyword "operator" +   {"punctuator"}, +  }}, + +  {"header-name", { +   {"<", "h-char-sequence", ">"}, +   {"\"", "q-char-sequence", "\""}, +  }}, + +  {"h-char-sequence", {{"h-char"}, {"h-char-sequence", "h-char"}}}, +  {"h-char", {all_except({"\n", ">"})}}, +  {"q-char-sequence", {{"q-char"}, {"q-char-sequence", "q-char"}}}, +  {"q-char", {all_except({"\n", "\""})}}, + +  {"pp-number", { +   {"digit"}, +   {".", "digit"}, +   {"pp-number", "digit"}, +   {"pp-number", "identifier-nondigit"}, +   {"pp-number", "'", "digit"}, +   {"pp-number", "'", "nondigit"}, +   {"pp-number", "e", "sign"}, +   {"pp-number", "E", "sign"}, +   {"pp-number", "p", "sign"}, +   {"pp-number", "P", "sign"}, +   {"pp-number", "."}, +  }}, + +  {"identifier", { +   {"identifier-nondigit"}, +   {"identifier", "identifier-nondigit"}, +   {"identifier", "digit"}, +  }}, + +  {"identifier-nondigit", { +   {"nondigit"}, +   {"universal-character-name"}, +  }}, + +  {"nondigit", { +   {"a"}, {"b"}, {"c"}, {"d"}, {"e"}, {"f"}, {"g"}, {"h"}, {"i"}, {"j"}, {"k"}, {"l"}, {"m"}, +   {"n"}, {"o"}, {"p"}, {"q"}, {"r"}, {"s"}, {"t"}, {"u"}, {"v"}, {"w"}, {"x"}, {"y"}, {"z"}, +   {"A"}, {"B"}, {"C"}, {"D"}, {"E"}, {"F"}, {"G"}, {"H"}, {"I"}, {"J"}, {"K"}, {"L"}, {"M"}, +   {"N"}, {"O"}, {"P"}, {"Q"}, {"R"}, {"S"}, {"T"}, {"U"}, {"V"}, {"W"}, {"X"}, {"Y"}, {"Z"}, {"_"} +  }}, + +  {"digit", {{"0"},{"1"},{"2"},{"3"},{"4"},{"5"},{"6"},{"7"},{"8"},{"9"}}}, + +  {"preprocessing-op-or-punc", { +   {"{"}, {"}"}, {"["}, {"]"}, {"#"}, {"#", "#"}, {"("}, {")"}, +   {"<:"}, {":>"}, {"<%"}, {"%>"}, {"%:"}, {"%:%:"}, {";"}, {":"}, {"..."}, +   {"new"}, {"delete"}, {"?"}, {"::"}, {"."}, {".*"}, {"->"}, {"->*"}, {"~"}, +   {"!"}, {"+"}, {"-"}, {"*"}, {"/"}, {"%"}, {"^"}, {"&"}, {"|"}, +   {"="}, {"+="}, {"-="}, {"*="}, {"/="}, {"%="}, {"^="}, {"&="}, {"|="}, +   {"=="}, {"!="}, {"<"}, {">"}, {"<="}, {">="}, {"<=>"}, {"&&"}, {"||"}, +   {"<<"}, {">>"}, {"<<="}, {">>="}, {"++"}, {"--"}, {","}, +   {"and"}, {"or"}, {"xor"}, {"not"}, {"bitand"}, {"bitor"}, {"compl"}, +   {"and_eq"}, {"or_eq"}, {"xor_eq"}, {"not_eq"} +  }}, + +  {"literal", { +   {"integer-literal"}, +   {"character-literal"}, +   {"floating-point-literal"}, +   {"string-literal"}, +   {"boolean-literal"}, +   {"pointer-literal"}, +   {"user-defined-literal"}, +  }}, + +  {"integer-literal", { +   {"binary-literal", optional("integer-suffix")}, +   {"octal-literal", optional("integer-suffix")}, +   {"decimal-literal", optional("integer-suffix")}, +   {"hexadecimal-literal", optional("integer-suffix")}, +  }}, + +  { "binary-literal", { +   {"0b", "binary-digit"}, +   {"0B", "binary-digit"}, +   {"binary-literal", optional("'"), "binary-digit"}, +  }}, + +  { "octal-literal", { +   {"0"}, +   {"octal-literal", optional("'"), "octal-digit"} +  } }, + +  { "decimal-literal", { +   {"nonzero-digit"}, +   {"decimal-literal", optional("'"), "digit"}, +  } }, + +  { "hexadecimal-literal", { +   {"hexadecimal-prefix", "hexadecimal-digit-sequence"}, +  } }, + +  { "binary-digit", {{"0"}, {"1"}} }, + +  { "octal-digit", {{"0"},{"1"},{"2"},{"3"},{"4"},{"5"},{"6"},{"7"}} }, + +  { "nonzero-digit", {{"1"},{"2"},{"3"},{"4"},{"5"},{"6"},{"7"},{"8"},{"9"}} }, + +  { "hexadecimal-prefix", {{"0x"}, {"0X"}} }, + +  { "hexadecimal-digit-sequence", { +   {"hexadecimal-digit"}, +   {"hexadecimal-digit-sequence", optional("'"), "dexadecimal-digit"}, +  } }, + +  { "hexadecimal-digit", { +   {"0"},{"1"},{"2"},{"3"},{"4"},{"5"},{"6"},{"7"},{"8"},{"9"}, +   {"a"},{"b"},{"c"},{"d"},{"e"},{"f"}, +   {"A"},{"B"},{"C"},{"D"},{"E"},{"F"} +  } }, + +  { "integer-suffix", { +   {"unsigned-suffix", optional("long-suffix")}, +   {"unsigned-suffix", optional("long-long-suffix")}, +   {"long-suffix", optional("unsigned-suffix")}, +   {"long-long-suffix", optional("unsigned-suffix")}, +  } }, + +  { "unsigned-suffix", {{"u"}, {"U"}} }, + +  { "long-suffix", {{"l"}, {"L"}} }, + +  { "long-long-suffix", {{"ll"}, {"LL"}} }, + +  { "character-literal", {{optional("encoding-prefix"), "'", "c-char-sequence", "'"}} }, + +  { "encoding-prefix", {{"u8"}, {"u"}, {"U"}, {"L"}} }, + +  { "c-char-sequence", { +   {"c-char"}, +   {"c-char-sequence", "c-char"}, +  } }, + +  { "c-char", { +   all_except({"'", "\\", "\n"}), +   {"escape-sequence"}, +   {"universal-character-name"}, +  } }, + +  { "escape-sequence", { +   {"simple-escape-sequence"}, +   {"octal-escape-sequence"}, +   {"hexadecimal-escape-sequence"}, +  } }, + +  { "simple-escape-sequence", {{"\\'"},{"\\\""},{"\\?"},{"\\\\"},{"\\a"},{"\\b"},{"\\f"},{"\\n"},{"\\r"},{"\\t"},{"\\v"},} }, + +  { "octal-escape-sequence", { +   {"\\", "octal-digit"}, +   {"\\", "octal-digit", "octal-digit"}, +   {"\\", "octal-digit", "octal-digit", "octal-digit"}, +  } }, + +  { "hexadecimal-escape-sequence", { +   {"\\x", "hexadecimal-digit"}, +   {"hexadecimal-escape-sequence", "hexadecimal-digit"} +  } }, + +  { "floating-point-literal", { +   {"decimal-floating-point-literal"}, +   {"hexadecimal-floating-point-literal"} +  } }, + +  { "decimal-floating-point-literal", { +   {"fractional-constant", optional("exponent-part"), optional("floating-point-suffix")}, +   {"digit-sequence", "exponent-part", optional("floating-point-suffix")}, +  } }, + +  { "hexadecimal-floating-point-literal", { +   {"hexadecimal-prefix", "hexadecimal-fractional-constant", "binary-exponent-part", optional("floating-point-suffix")}, +   {"hexadecimal-prefix", "hexadecimal-digit-sequence", "binary-exponent-part", optional("floating-point-suffix")}, +  } }, + +  { "fractional-constant", { +   {optional("digit-sequence"), ".", "digit-sequence"}, +   {"digit-sequence", "."}, +  } }, + +  { "hexadecimal-fractional-constant", { +   {optional("hexadecimal-digit-sequence"),".","hexadecimal-digit-sequence"}, +   {"hexadecimal-digit-sequence", "."}, +  } }, + +  { "exponent-part", { +   {"e", optional("sign"), "digit-sequence"}, +   {"E", optional("sign"), "digit-sequence"} +  } }, + +  { "binary-exponent-part", { +   {"p", optional("sign"), "digit-sequence"}, +   {"P", optional("sign"), "digit-sequence"} +  } }, + +  { "sign", {{"+"}, {"-"}} }, + +  { "digit-sequence", { +   {"digit"}, +   {"digit-sequence", optional("'"), "digit"}, +  } }, + +  { "floating-point-suffix", {{"f"},{"l"},{"F"},{"L"}} }, + +  { "string-literal", { +   {optional("encoding-prefix"), "\"" , optional("s-char-sequence"), "\"" }, +   {optional("encoding-prefix"), "R", "raw-string"}, +  } }, + +  { "s-char-sequence", { +   {"s-char"}, +   {"s-char-sequence", "s-char"} +  } }, + +  { "s-char", { +   all_except({"\"", "\\", "\n"}), +   {"escape-sequence"}, +   {"universal-character-name"}, +  } }, + +  { "raw-string", { +   {"\"", optional("d-char-sequence"), "(", optional("r-char-sequence"), ")", optional("d-char-sequence"), "\"" }, +  } }, + +  { "r-char-sequence", { +   {"r-char"}, +   {"r-char-sequence", "r-char"} +  } }, + +  { "r-char", { +   all_except({")"}), // TODO: actually: non-match from "raw-string" above: ")", optional("d-char-sequence"), "\"" +  } }, + +  { "d-char-sequence", { +   {"d-char"}, +   {"d-char-sequence", "d-char"} +  } }, + +  { "d-char", { +   all_except({" ", "(", ")", "\\", "\t", "\v", "\f", "\n"}), +  } }, + +  { "boolean-literal", {{"true"}, {"false"}} }, + +  { "pointer-literal", {{"nullptr"}} }, + +  { "user-defined-literal", { +   {"user-defined-integer-literal"}, +   {"user-defined-floating-point-literal"}, +   {"user-defined-string-literal"}, +   {"user-defined-character-literal"}, +  } }, + +  { "user-defined-integer-literal", { +   {"decimal-literal", "ud-suffix"}, +   {"octal-literal", "ud-suffix"}, +   {"hexadecimal-literal", "ud-suffix"}, +   {"binary-literal", "ud-suffix"}, +  } }, + +  { "user-defined-floating-point-literal", { +   {"fractional-constant", optional("exponent-part"), "ud-suffix"}, +   {"digit-sequence", "exponent-part", "ud-suffix"}, +   {"hexadecimal-prefix", "hexadecimal-fractional-constant", "binary-exponent-part", "ud-suffix"}, +   {"hexadecimal-prefix", "hexadecimal-digit-sequence", "binary-exponent-part", "ud-suffix"}, +  } }, + +  { "user-defined-string-literal", { +   {"string-literal", "ud-suffix"}, +  } }, + +  { "user-defined-character-literal", { +   {"character-literal", "ud-suffix"}, +  } }, + +  { "ud-suffix", {{"identifier"}} }, + + }; + + return normalizeLexBNF(bnf); +} + +T_BNF GetCppBNFGram() +{ + T_BNF bnf{ +  // [gram.key] + +  {"typedef-name", {{"identifier"}, {"simple-template-id"}}}, +  {"namespace-name", {{"identifier"}, {"namespace-alias"}}}, +  {"namespace-alias", {{"identifier"}}}, +  {"class-name", {{"identifier"}, {"simple-template-id"}}}, +  {"enum-name", {{"identifier"}}}, +  {"template-name", {{"identifier"}}}, + +  // [gram.basic] + +  {"translation-unit", { +   {optional("top-level-declaration-seq")}, +   {optional("global-module-fragment"), "module-declaration", optional("top-level-declaration-seq"), optional("private-module-fragment")}, +  }}, +  +  {"top-level-declaration-seq", { +   {"top-level-declaration"}, +   {"top-level-declaration-seq", "top-level-declaration"}, +  }}, +  +  {"top-level-declaration", { +   {"module-import-declaration"}, +   {"declaration"}, +  }}, +  +  // [gram.expr] +  +  {"primary-expression", { +   {"literal"}, +   {"this"}, +   {"(", "expression", ")"}, +   {"id-expression"}, +   {"lambda-expression"}, +   {"fold-expression"}, +   {"requires-expression"}, +  }}, +  +  {"id-expression", { +   {"unqualified-id"}, +   {"qualified-id"}, +  }}, +  +  {"unqualified-id", { +   {"identifier"}, +   {"operator-function-id"}, +   {"conversion-function-id"}, +   {"literal-operator-id"}, +   {"~", "type-specified"}, +   {"~", "decltype-specifier"}, +   {"template-id"}, +  }}, +  +  {"qualified-id", {{"nested-name-specifier", optional("template"), "unqualified-id"}}}, +  +  {"nested-name-specifier", { +   {"::"}, +   {"type-name", "::"}, +   {"namespace-name", "::"}, +   {"decltype-specifier", "::"}, +   {"nested-name-specifier", "identifier", "::"}, +   {"nested-name-specifier", optional("template"), "simple-template-id", "::"}, +  }}, +  +  {"lambda-expression", { +   {"lambda-introducer", optional("lambda-declarator"), "compound-statement"}, +   {"lambda-introducer", "<", "template-parameter-list", ">", optional("requires-clause"), optional("lambda-declarator"), "compound-statement"}, +  }}, +  +  {"lambda-introducer", {{"[", optional("lambda-capture"), "]"}}}, +  +  {"lambda-capture", { +   {"capture-default"}, +   {"capture-list"}, +   {"capture-default", ",", "capture-list"}, +  }}, +  +  {"capture-default", {{"&"}, {"="}}}, +  +  {"capture-list", { +   {"capture"}, +   {"capture-list", ",", "capture"} +  }}, +  +  {"capture", { +   {"simple-capture", optional("...")}, +   {optional("..."), "init-capture"}, +  }}, +  +  {"simple-capture", { +   {"identifier"}, +   {"&", "identifier"}, +   {"this"}, +   {"*", "this"}, +  }}, +  +  {"init-capture", { +   {"identifier", "initializer"}, +   {"&", "identifier", "initializer"}, +  }}, +  +  {"fold-expression", { +   {"(", "cast-expression", "fold-operator", ")"}, +   {"(", "...", "fold-operator", "cast-expression", ")"}, +   {"(", "cast-expression", "fold-operator", "...", "fold-operator", "cast-expression", ")"}, +  }}, +  +  {"fold-operator", { +   {"+"}, {"-"}, {"*"}, {"/"}, {"%"}, {"^"}, {"&"}, {"|"}, {"<<"}, {">>"}, +   {"+="}, {"-="}, {"*="}, {"/="}, {"%="}, {"^="}, {"&="}, {"|="}, {"<<="}, {">>="}, +   {"=="}, {"!="}, {"<"}, {">"}, {"<="}, {">="}, {"&&"}, {"||"}, {","}, {".*"}, {"->*"}, +  }}, +  +  {"requires-expression", { +   {"requires", optional("requirement-parameter-list"), "requirement-body"} +  }}, +  +  {"requirement-parameter-list", { +   {"(", optional("parameter-declaration-clause"), ")"} +  }}, +  +  {"requirement-body", { +   {"{", "requirement-seq", "}",} +  }}, +  +  { "requirement-seq", { +   {"requirement"}, +   {"requirement-seq", "requirement"}, +  }}, +  +  { "requirement", { +   {"simple-requirement"}, +   {"type-requirement"}, +   {"compound-requirement"}, +   {"nested-requirement"}, +  } }, +  +  { "simple-requirement", {{"expression", ";"}} }, +  +  { "type-requirement", {{"typename", optional("nested-name-specifier"), "type-name", ";"}} }, +  +  { "compound-requirement", {{"{", "expression", "}", optional("noexcept"), optional("return-type-requirement"), ";"}} }, +  +  { "return-type-requirement", {{"->", "type-constraint"}} }, +  +  { "nested-requirement", {{"requires", "constraint-expression", ";"}} }, +  +  { "postfix-expression", { +   {"primary-expression"}, +   {"postfix-expression", "[", "expr-or-braced-init-list", "]"}, +   {"postfix-expression", "(", optional("expression-list"), ")"}, +   {"simple-type-specifier", "(", optional("expression-list"), ")"}, +   {"typename-specifier", "(", optional("expression-list"), ")"}, +   {"simple-type-specifier", "braced-init-list"}, +   {"typename-specifier", "braced-init-list"}, +   {"postfix-expression", ".", optional("template"), "id-expression"}, +   {"postfix-expression", "->", optional("template"), "id-expression"}, +   {"postfix-expression", "++"}, +   {"postfix-expression", "--"}, +   {"dynamic_cast", "<", "type-id", ">", "(", "expression", ")"}, +   {"static-cast", "<", "type-id", ">", "(", "expression", ")"}, +   {"reinterpret-cast", "<", "type-id", ">", "(", "expression", ")"}, +   {"const_cast", "<", "type-id", ">", "(", "expression", ")"}, +   {"typeid", "(", "expression", ")"}, +   {"typeid", "(", "type-id", ")"}, +  } }, +  +  { "expression-list", {{"initializer-list"}} }, +  +  { "unary-expression", { +   {"postfix-expression"}, +   {"unary-operator", "cast-expression"}, +   {"++", "cast-expression"}, +   {"--", "cast-expression"}, +   {"await-expression"}, +   {"sizeof", "unary-expression"}, +   {"sizeof", "(", "type-id", ")"}, +   {"sizeof", "...", "(", "identifier", ")"}, +   {"alignof", "(", "type-id", ")"}, +   {"noexcept-expression"}, +   {"new-expression"}, +   {"delete-expression"}, +  } }, +  +  { "unary-operator", {{"*"}, {"&"}, {"+"}, {"-"}, {"!"}, {"~"} } }, +  +  { "await-expression", {{"co_await", "cast-expression"}} }, +  +  { "noexcept-expression", {{"noexcept", "(", "expression", ")"}} }, +  +  { "new-expression", { +   {optional("::"), "new", optional("new-placement"), "new-type-id", optional("new-initializer")}, +   {optional("::"), "new", optional("new-placement"), "(", "type-id", ")", optional("new-initializer")}, +  } }, +  +  { "new-placement", {{"(", "expression-list", ")"}} }, +  +  { "new-type-id", {{"type-specifier-seq", optional("new-declarator")}} }, +  +  { "new-declarator", { +   {"ptr-operator", optional("new-declarator")}, +   {"noptr-new-declarator"}, +  } }, +  +  { "noptr-new-declarator", { +   {"[", optional("expression"), "]", optional("attribute-specifier-seq")}, +   {"noptr-new-declarator", "[", "constant-expression", "]" , optional("attribute-specifier-seq")}, +  } }, +  +  { "new-initializer", { +   {"(", optional("expression-list"), ")"}, +   {"braced-init-list"}, +  } }, +  +  { "delete-expression", { +   {optional("::"), "delete", "cast-expression"}, +   {optional("::"), "delete", "[", "]", "cast-expression"}, +  } }, +  +  { "cast-expression", { +   {"unary-expression"}, +   {"(", "type-id", ")", "cast-expression"}, +  } }, +  +  { "pm-expression", { +   {"cast-expression"}, +   {"pm-expression", ".*", "cast-expression"}, +   {"pm-expression", "->*", "cast-expression"}, +  } }, +  +  { "multiplicative-expression", { +   {"pm-expression"}, +   {"multiplicative-expression", "*", "pm-expression"}, +   {"multiplicative-expression", "/", "pm-expression"}, +   {"multiplicative-expression", "%", "pm-expression"}, +  } }, +  +  { "additive-expression", { +   {"multiplicative-expression"}, +   {"additive-expression", "+", "multiplicative-expression"}, +   {"additive-expression", "-", "multiplicative-expression"}, +  } }, +  +  { "shift-expression", { +   {"additive-expression"}, +   {"shift-expression", "<<", "additive-expression"}, +   {"shift-expression", ">>", "additive-expression"}, +  } }, +  +  { "compare-expression", { +   {"shift-expression"}, +   {"compare-expression", "<=>", "shift-expression"} +  } }, +  +  { "relational-expression", { +   {"compare-expression"}, +   {"relational-expression", "<",  "compare-expression"}, +   {"relational-expression", ">",  "compare-expression"}, +   {"relational-expression", "<=", "compare-expression"}, +   {"relational-expression", ">=", "compare-expression"}, +  } }, +  +  { "equality-expression", { +   {"relational-expression"}, +   {"equality-expression", "==", "relational-expression"}, +   {"equality-expression", "!=", "relational-expression"}, +  } }, +  +  { "and-expression", { +   {"equality-expression"}, +   {"and-expression", "&", "equality-expression"}, +  } }, +  +  { "exclusive-or-expression", { +   {"and-expression"}, +   {"exclusive-or-expression", "^", "and-expression"}, +  } }, +  +  { "inclusive-or-expression", { +   {"exclusive-or-expression"}, +   {"inclusive-or-expression", "|", "exclusive-or-expression"}, +  } }, +  +  { "logical-and-expression", { +   {"inclusive-or-expression"}, +   {"logical-and-expression", "&&", "inclusive-or-expression"} +  } }, +  +  { "logical-or-expression", { +   {"logical-and-expression"}, +   {"logical-or-expression", "||", "logical-and-expression"}, +  } }, +  +  { "conditional-expression", { +   {"logical-or-expression"}, +   {"logical-or-expression", "?", "expression", ":", "assignment-expression"}, +  } }, +  +  { "yield-expression", { +   {"co_yield", "assignment-expression"}, +   {"co_yield", "braced-init-list"} +  } }, +  +  { "throw-expression", {{"throw", optional("assignment-expression")}} }, +  +  { "assignment-expression", { +   {"conditional-expression"}, +   {"yield-expression"}, +   {"throw-expression"}, +   {"logical-or-expression", "assignment-operator", "initializer-clause"}, +  } }, +  +  { "assignment-operator", {{"="}, {"*="}, {"/="}, {"%="}, {"+="}, {"-="}, {">>="}, {"<<="}, {"&="}, {"^="}, {"|="}} }, +  +  { "expression", { +   {"assignment-expression"}, +   {"expression", ",", "assignment-expression"}, +  } }, +  +  { "constant-expression", {{"conditional-expression"}} }, +  +  // [gram.stmt] +  +  { "statement", { +   {"labeled-statement"}, +   {optional("attribute-specifier-seq"), "expression-statement"}, +   {optional("attribute-specifier-seq"), "compound-statement"}, +   {optional("attribute-specifier-seq"), "selection-statement"}, +   {optional("attribute-specifier-seq"), "iteration-statement"}, +   {optional("attribute-specifier-seq"), "jump-statement"}, +   {"declaration-statement"}, +   {optional("attribute-specifier-seq"), "try-block"}, +  } }, +  +  { "init-statement", { +   {"expression-statement"}, +   {"simple-declaration"}, +  } }, +  +  { "condition", { +   {"expression"}, +   {optional("attribute-specifier-seq"), "decl-specifier-seq", "declarator", "brace-or-equal-initializer"}, +  } }, +  +  { "labeled-statement", { +   {optional("attribute-specifier-seq"), "identifier", ":", "statement"}, +   {optional("attribute-specifier-seq"), "case", "constant-expression", ":", "statement"}, +   {optional("attribute-specifier-seq"), "default", ":", "statement"}, +  } }, +  +  { "expression-statement", { +   {optional("expression"), ";"} +  } }, +  +  { "compound-statement", { +   {"{", optional("statement-seq"), "}"} +  } }, +  +  { "statement-seq", { +   {"statement"}, +   {"statement-seq statement"}, +  } }, +  +  { "selection-statement", { +   {"if", optional("constexpr"), "(", optional("init-statement"), "condition", ")", "statement"}, +   {"if", optional("constexpr"), "(", optional("init-statement"), "condition", ")", "statement", "else", "statement"}, +   {"switch", "(", optional("init-statement"), "condition", ")", "statement"}, +  } }, +  +  { "iteration-statement", { +   {"while", "(", "condition", ")", "statement"}, +   {"do", "statement", "while", "(", "expression", ")", ";"}, +   {"for", "(", "init-statement", optional("condition"), ";", optional("expression"), ")", "statement"}, +   {"for", "(", optional("init-statement"), "for-range-declaration", ":", "for-range-initializer", ")", "statement"}, +  } }, + +  { "for-range-declaration", { +   {optional("attribute-specifier-seq"), "decl-specifier-seq", "declarator"}, +   {optional("attribute-specifier-seq"), "decl-specifier-seq", optional("ref-qualifier"), "[", "identifier-list", "]"}, +  } }, + +  { "for-range-initializer", { +   {"expr-or-braced-init-list"}, +  } }, + +  { "jump-statement", { +   {"break", ";"}, +   {"continue", ";"}, +   {"return", optional("expr-or-braced-init-list"), ";"}, +   {"coroutine-return-statement"}, +   {"goto", "identifier", ";"}, +  } }, + +  { "coroutine-return-statement", { +   {"co_return", optional("expr-or-braced-init-list"), ";"}, +  } }, + +  { "declaration-statement", { {"block-declaration"} } }, + +  // [gram.dcl] + +  { "declaration-seq", { +   {"declaration"}, +   {"declaration-seq declaration"}, +  } }, + +  {"declaration", { +   {"block-declaration"}, +   {"nodeclspec-function-declaration"}, +   {"function-definition"}, +   {"template-declaration"}, +   {"deduction-guide"}, +   {"explicit-instantiation"}, +   {"explicit-specialization"}, +   {"export-declaration"}, +   {"linkage-specification"}, +   {"namespace-definition"}, +   {"empty-declaration"}, +   {"attribute-declaration"}, +  }}, + +  { "block-declaration", { +   {"simple-declaration"}, +   {"asm-declaration"}, +   {"namespace-alias-definition"}, +   {"using-declaration"}, +   {"using-enum-declaration"}, +   {"using-directive"}, +   {"static_assert-declaration"}, +   {"alias-declaration"}, +   {"opaque-enum-declaration"}, +  } }, + +  { "nodeclspec-function-declaration", { +   {optional("attribute-specifier-seq"), "declarator", ";"}, +  } }, + +  { "alias-declaration", { +   {"using", "identifier", optional("attribute-specifier-seq"), "=", "defining-type-id", ";"}, +  } }, + +  { "simple-declaration", { +   {"decl-specifier-seq", optional("init-declarator-list"), ";"}, +   {"attribute-specifier-seq", "decl-specifier-seq", "init-declarator-list", ";"}, +   {optional("attribute-specifier-seq"), "decl-specifier-seq", optional("ref-qualifier"), "[", "identifier-list", "]", "initializer", ";"}, +  } }, + +  { "static_assert-declaration", { +   {"static_assert", "(", "constant-expression", ")", ";"}, +   {"static_assert", "(", "constant-expression", ",", "string-literal", ")", ";"}, +  } }, + +  { "empty-declaration", { +   {";"}, +  } }, + +  { "attribute-declaration", { +   {"attribute-specifier-seq", ";"}, +  } }, + +  { "decl-specifier", { +   {"storage-class-specifier"}, +   {"defining-type-specifier"}, +   {"function-specifier"}, +   {"friend"}, +   {"typedef"}, +   {"constexpr"}, +   {"consteval"}, +   {"constinit"}, +   {"inline"}, +  } }, + +  { "decl-specifier-seq", { +   {"decl-specifier", optional("attribute-specifier-seq")}, +   {"decl-specifier", "decl-specifier-seq"}, +  } }, + +  { "storage-class-specifier", { +   {"static"}, +   {"thread_local"}, +   {"extern"}, +   {"mutable"}, +  } }, + +  { "function-specifier", { +   {"virtual"}, +   {"explicit-specifier"}, +  } }, + +  { "explicit-specifier", { +   {"explicit", "(", "constant-expression", ")"}, +   {"explicit"}, +  } }, + +  { "typedef-name", { +   {"identifier"}, +   {"simple-template-id"}, +  } }, + +  { "type-specifier", { +   {"simple-type-specifier"}, +   {"elaborated-type-specifier"}, +   {"typename-specifier"}, +   {"cv-qualifier"}, +  } }, + +  { "type-specifier-seq", { +   {"type-specifier", optional("attribute-specifier-seq")}, +   {"type-specifier", "type-specifier-seq"}, +  } }, + +  { "defining-type-specifier", { +   {"type-specifier"}, +   {"class-specifier"}, +   {"enum-specifier"}, +  } }, + +  { "defining-type-specifier-seq", { +   {"defining-type-specifier", optional("attribute-specifier-seq")}, +   {"defining-type-specifier", "defining-type-specifier-seq"}, +  } }, + +  { "simple-type-specifier", { +   {optional("nested-name-specifier"), "type-name"}, +   {"nested-name-specifier", "template", "simple-template-id"}, +   {"decltype-specifier"}, +   {"placeholder-type-specifier"}, +   {optional("nested-name-specifier"), "template-name"}, +   {"char"}, +   {"char8_t"}, +   {"char16_t"}, +   {"char32_t"}, +   {"wchar_t"}, +   {"bool"}, +   {"short"}, +   {"int"}, +   {"long"}, +   {"signed"}, +   {"unsigned"}, +   {"float"}, +   {"double"}, +   {"void"}, +  } }, + +  { "type-name", { +   {"class-name"}, +   {"enum-name"}, +   {"typedef-name"}, +  } }, + +  { "elaborated-type-specifier", { +   {"class-key", optional("attribute-specifier-seq"), optional("nested-name-specifier"), "identifier"}, +   {"class-key", "simple-template-id"}, +   {"class-key", "nested-name-specifier", optional("template"), "simple-template-id"}, +   {"elaborated-enum-specifier"}, +  } }, + +  { "elaborated-enum-specifier", { +   {"enum", optional("nested-name-specifier"), "identifier"}, +  } }, + +  { "decltype-specifier", { +   {"decltype", "(", "expression", ")"}, +  } }, + +  { "placeholder-type-specifier", { +   {optional("type-constraint"), "auto"}, +   {optional("type-constraint"), "decltype", "(", "auto", ")"}, +  } }, + +  { "init-declarator-list", { +   {"init-declarator"}, +   {"init-declarator-list", ",", "init-declarator"}, +  } }, + +  { "init-declarator", { +   {"declarator", optional("initializer")}, +   {"declarator", "requires-clause"}, +  } }, + +  { "declarator", { +   {"ptr-declarator"}, +   {"noptr-declarator", "parameters-and-qualifiers", "trailing-return-type"}, +  } }, + +  { "ptr-declarator", { +   {"noptr-declarator"}, +   {"ptr-operator", "ptr-declarator"}, +  } }, + +  { "noptr-declarator", { +   {"declarator-id", optional("attribute-specifier-seq")}, +   {"noptr-declarator", "parameters-and-qualifiers"}, +   {"noptr-declarator", "[", optional("constant-expression"), "]", optional("attribute-specifier-seq")}, +   {"(", "ptr-declarator", ")"}, +  } }, + +  { "parameters-and-qualifiers", { +   {"(", "parameter-declaration-clause", ")", optional("cv-qualifier-seq"), +    optional("ref-qualifier"), optional("noexcept-specifier"), optional("attribute-specifier-seq")}, +  } }, + +  { "trailing-return-type", { +   {"->", "type-id"}, +  } }, + +  { "ptr-operator", { +   {"*", optional("attribute-specifier-seq"), optional("cv-qualifier-seq")}, +   {"&", optional("attribute-specifier-seq")}, +   {"&&", optional("attribute-specifier-seq")}, +   {"nested-name-specifier", "*", optional("attribute-specifier-seq"), optional("cv-qualifier-seq")}, +  } }, + +  { "cv-qualifier-seq", { +   {"cv-qualifier", optional("cv-qualifier-seq")}, +  } }, + +  { "cv-qualifier", { +   {"const"}, +   {"volatile"}, +  } }, + +  { "ref-qualifier", { +   {"&"}, {"&&"}, +  } }, + +  { "declarator-id", { +   {optional("..."), "id-expression"}, +  } }, + +  { "type-id", { +   {"type-specifier-seq", optional("abstract-declarator")}, +  } }, + +  { "defining-type-id", { +   {"defining-type-specifier-seq", optional("abstract-declarator")}, +  } }, + +  { "abstract-declarator", { +   {"ptr-abstract-declarator"}, +   {optional("noptr-abstract-declarator"), "parameters-and-qualifiers", "trailing-return-type"}, +   {"abstract-pack-declarator"}, +  } }, + +  { "ptr-abstract-declarator", { +   {"noptr-abstract-declarator"}, +   {"ptr-operator", optional("ptr-abstract-declarator")}, +  } }, + +  { "noptr-abstract-declarator", { +   {optional("noptr-abstract-declarator"), "parameters-and-qualifiers"}, +   {optional("noptr-abstract-declarator"), "[", optional("constant-expression"), "]", optional("attribute-specifier-seq")}, +   {"(", "ptr-abstract-declarator", ")"}, +  } }, + +  { "abstract-pack-declarator", { +   {"noptr-abstract-pack-declarator"}, +   {"ptr-operator", "abstract-pack-declarator"}, +  } }, + +  { "noptr-abstract-pack-declarator", { +   {"noptr-abstract-pack-declarator", "parameters-and-qualifiers"}, +   {"noptr-abstract-pack-declarator", "[", optional("constant-expression"), "]", optional("attribute-specifier-seq")}, +   {"..."}, +  } }, + +  { "parameter-declaration-clause", { +   {optional("parameter-declaration-list"), optional("...")}, +   {"parameter-declaration-list", ",", "..."}, +  } }, + +  { "parameter-declaration-list", { +   {"parameter-declaration"}, +   {"parameter-declaration-list", ",", "parameter-declaration"}, +  } }, + +  { "parameter-declaration", { +   {optional("attribute-specifier-seq"), "decl-specifier-seq", "declarator"}, +   {optional("attribute-specifier-seq"), "decl-specifier-seq", "declarator", "initializer-clause"}, +   {optional("attribute-specifier-seq"), "decl-specifier-seq", optional("abstract-declarator")}, +   {optional("attribute-specifier-seq"), "decl-specifier-seq", optional("abstract-declarator"), "=", "initializer-clause"}, +  } }, + +  { "initializer", { +   {"brace-or-equal-initializer"}, +   {"(", "expression-list", ")"}, +  } }, + +  { "brace-or-equal-initializer", { +   {"=", "initializer-clause"}, +   {"braced-init-list"}, +  } }, + +  { "initializer-clause", { +   {"assignment-expression"}, +   {"braced-init-list"}, +  } }, + +  { "braced-init-list", { +   {"{", "initializer-list", optional(","), "}"}, +   {"{", "designated-initializer-list", optional(","), "}"}, +   {"{", "}"}, +  } }, + +  { "initializer-list", { +   {"initializer-clause", optional("...")}, +   {"initializer-list", ",", "initializer-clause", optional("...")}, +  } }, + +  { "designated-initializer-list", { +   {"designated-initializer-clause"}, +   {"designated-initializer-list", ",", "designated-initializer-clause"}, +  } }, + +  { "designated-initializer-clause", { +   {"designator", "brace-or-equal-initializer"}, +  } }, + +  { "designator", { +   {".", "identifier"}, +  } }, + +  { "expr-or-braced-init-list", { +   {"expression"}, +   {"braced-init-list"}, +  } }, + +  { "function-definition", { +   {optional("attribute-specifier-seq"), optional("decl-specifier-seq"), "declarator", optional("virt-specifier-seq"), "function-body"}, +   {optional("attribute-specifier-seq"), optional("decl-specifier-seq"), "declarator", "requires-clause", "function-body"}, +  } }, + +  { "function-body", { +   {optional("ctor-initializer"), "compound-statement"}, +   {"function-try-block"}, +   {"=", "default", ";"}, +   {"=", "delete", ";"}, +  } }, + +  { "enum-name", { +   {"identifier"}, +  } }, + +  { "enum-specifier", { +   {"enum-head", "{", optional("enumerator-list"), "}"}, +   {"enum-head", "{", "enumerator-list", ",", "}"}, +  } }, + +  { "enum-head", { +   {"enum-key", optional("attribute-specifier-seq"), optional("enum-head-name"), optional("enum-base")}, +  } }, + +  { "enum-head-name", { +   {optional("nested-name-specifier"), "identifier"}, +  } }, + +  { "opaque-enum-declaration", { +   {"enum-key", optional("attribute-specifier-seq"), "enum-head-name", optional("enum-base"), ";"}, +  } }, + +  { "enum-key", { +   {"enum"}, +   {"enum", "class"}, +   {"enum", "struct"}, +  } }, +   +  { "enum-base", { +   {":", "type-specifier-seq"}, +  } }, + +  { "enumerator-list", { +   {"enumerator-definition"}, +   {"enumerator-list", ",", "enumerator-definition"}, +  }}, + +  { "enumerator-definition", { +   {"enumerator"}, +   {"enumerator", "=", "constant-expression"}, +  } }, + +  { "enumerator", { +   {"identifier", optional("attribute-specifier-seq")}, +  } }, + +  { "using-enum-declaration", { +   {"using", "elaborated-enum-specifier", ";"}, +  } }, + +  { "namespace-name", { +   {"identifier"}, +   {"namespace-alias"}, +  } }, + +  { "namespace-definition", { +   {"named-namespace-definition"}, +   {"unnamed-namespace-definition"}, +   {"nested-namespace-definition"}, +  }}, + +  { "named-namespace-definition", { +   {optional("inline"), "namespace", optional("attribute-specifier-seq"), "identifier", "{", "namespace-body", "}"}, +  } }, + +  { "unnamed-namespace-definition", { +   {optional("inline"), "namespace", optional("attribute-specifier-seq"), "{", "namespace-body", "}"}, +  } }, + +  { "nested-namespace-definition", { +   {"namespace", "enclosing-namespace-specifier", "::", optional("inline"), "identifier", "{", "namespace-body", "}"}, +  } }, + +  { "enclosing-namespace-specifier", { +   {"identifier"}, +   {"enclosing-namespace-specifier", "::", optional("inline"), "identifier"}, +  } }, + +  { "namespace-body", { +   {optional("declaration-seq")}, +  } }, + +  { "namespace-alias", { +   {"identifier"}, +  } }, + +  { "namespace-alias-definition", { +   {"namespace", "identifier", "=", "qualified-namespace-specifier", ";"}, +  } }, + +  { "qualified-namespace-specifier", { +   {optional("nested-name-specifier"), "namespace-name"}, +  } }, + +  { "using-directive", { +   {optional("attribute-specifier-seq"), "using", "namespace", optional("nested-name-specifier"), "namespace-name", ";"}, +  } }, + +  { "using-declaration", { +   {"using", "using-declarator-list", ";"}, +  } }, + +  { "using-declarator-list", { +   {"using-declarator", optional("...")}, +   {"using-declarator-list", ",", "using-declarator", optional("...")}, +  } }, + +  { "using-declarator", { +   {optional("typename"), "nested-name-specifier", "unqualified-id"}, +  } }, + +  { "asm-declaration", { +   {optional("attribute-specifier-seq"), "asm", "(", "string-literal", ")", ";"}, +  } }, + +  { "linkage-specification", { +   {"extern", "string-literal", "{", optional("declaration-seq"), "}"}, +   {"extern", "string-literal", "declaration"}, +  } }, + +  { "attribute-specifier-seq", { +   {optional("attribute-specifier-seq"), "attribute-specifier"}, +  } }, + +  { "attribute-specifier", { +   {"[", "[", optional("attribute-using-prefix"), "attribute-list", "]", "]"}, +   {"alignment-specifier"}, +  } }, + +  { "alignment-specifier", { +   {"alignas", "(", "type-id", optional("..."), ")"}, +   {"alignas", "(", "constant-expression", optional("..."), ")"}, +  } }, + +  { "attribute-using-prefix", { +   {"using", "attribute-namespace", ":"}, +  } }, + +  { "attribute-list", { +   {optional("attribute")}, +   {"attribute-list", ",", optional("attribute")}, +   {"attribute", "..."}, +   {"attribute-list", ",", "attribute", "..."}, +  } }, + +  { "attribute", { +   {"attribute-token", optional("attribute-argument-clause")}, +  } }, + +  { "attribute-token", { +   {"identifier"}, +   {"attribute-scoped-token"}, +  } }, + +  { "attribute-scoped-token", { +   {"attribute-namespace", "::", "identifier"}, +  } }, + +  { "attribute-namespace", { +   {"identifier"}, +  } }, + +  { "attribute-argument-clause", { +   {"(", optional("balanced-token-seq"), ")"}, +  } }, + +  { "balanced-token-seq", { +   {"balanced-token"}, +   {"balanced-token-seq", "balanced-token"}, +  } }, + +  { "balanced-token", { +   {"(", optional("balanced-token-seq"), ")"}, +   {"[", optional("balanced-token-seq"), "]"}, +   {"{", optional("balanced-token-seq"), "}"}, +   all_except({"(", ")", "[", "]", "{", "}",}), +  }}, + +  // [gram.module] + +  { "module-declaration", { +   {optional("export"), "module", "module-name", optional("module-partition"), optional("attribute-specifier-seq"), ";"}, +  } }, + +  { "module-name", { +   {optional("module-name-qualifier"), "identifier"}, +  } }, + +  { "module-partition", { +   {":", optional("module-name-qualifier"), "identifier"}, +  } }, + +  { "module-name-qualifier", { +   {"identifier", "."}, +   {"module-name-qualifier", "identifier", "."}, +  } }, + +  { "export-declaration", { +   {"export", "declaration"}, +   {"export", "{", optional("declaration-seq"), "}"}, +  } }, + +  { "module-import-declaration", { +   {optional("export"), "import-keyword", "module-name",      optional("attribute-specifier-seq"), ";"}, +   {optional("export"), "import-keyword", "module-partition", optional("attribute-specifier-seq"), ";"}, +   {optional("export"), "import-keyword", "header-name",      optional("attribute-specifier-seq"), ";"}, +  } }, + +  { "global-module-fragment", { +   {"module", ";", optional("top-level-declaration-seq")}, +  } }, + +  { "private-module-fragment", { +   {"module", ":", "private", ";", optional("top-level-declaration-seq")}, +  } }, + +  // [gram.class] + +  { "class-name", { +   {"identifier"}, +   {"simple-template-id"}, +  } }, + +  { "class-specifier", { +   {"class-head", "{", optional("member-specification"), "}"}, +  } }, + +  { "class-head", { +   {"class-key", optional("attribute-specifier-seq"), "class-head-name", optional("class-virt-specifier"), optional("base-clause")}, +   {"class-key", optional("attribute-specifier-seq"), optional("base-clause")}, +  } }, + +  { "class-head-name", { +   {optional("nested-name-specifier"), "class-name"}, +  } }, + +  { "class-virt-specifier", { +   {"final"}, +  } }, + +  { "class-key", { +   {"class"}, +   {"struct"}, +   {"union"}, +  } }, + + +  { "member-specification", { +   {"member-declaration", optional("member-specification")}, +   {"access-specifier", ":", optional("member-specification")}, +  } }, + +  { "member-declaration", { +   {optional("attribute-specifier-seq"), optional("decl-specifier-seq"), optional("member-declarator-list"), ";"}, +   {"function-definition"}, +   {"using-declaration"}, +   {"using-enum-declaration"}, +   {"static_assert-declaration"}, +   {"template-declaration"}, +   {"deduction-guide"}, +   {"alias-declaration"}, +   {"opaque-enum-declaration"}, +   {"empty-declaration"}, +  } }, + +  { "member-declarator-list", { +   {"member-declarator"}, +   {"member-declarator-list", ",", "member-declarator"}, +  } }, + +  { "member-declarator", { +   {"declarator", optional("virt-specifier-seq"), optional("pure-specifier")}, +   {"declarator", "requires-clause"}, +   {"declarator", optional("brace-or-equal-initializer")}, +   {optional("identifier"), optional("attribute-specifier-seq"), ":", "constant-expression", optional("brace-or-equal-initializer")}, +  } }, + +  { "virt-specifier-seq", { +   {"virt-specifier"}, +   {"virt-specifier-seq", "virt-specifier"}, +  } }, + +  { "virt-specifier", { +   {"override"}, +   {"final"}, +  } }, + +  { "pure-specifier", { +   {"=", "0"}, +  } }, + +  { "conversion-function-id", { +   {"operator", "conversion-type-id"}, +  } }, + +  { "conversion-type-id", { +   {"type-specifier-seq", optional("conversion-declarator")}, +  } }, + +  { "conversion-declarator", { +   {"ptr-operator", optional("conversion-declarator")}, +  } }, + +  { "base-clause", { +   {":", "base-specfier-list"}, +  } }, + +  { "base-specfier-list", { +   {"base-specifier", optional("...")}, +   {"base-specifier-list", ",", "base-specifier", optional("...")}, +  } }, + +  { "base-specifier", { +   {optional("attribute-specifier-seq"), "class-or-decltype"}, +   {optional("attribute-specifier-seq"), "virtual", optional("access-specifier"), "class-or-decltype"}, +   {optional("attribute-specifier-seq"), "access-specifier", optional("virtual"), "class-or-decltype"}, +  } }, + +  { "class-or-decltype", { +   {optional("nested-name-specifier"), "type-name"}, +   {"nested-name-specifier", "template", "simple-template-id"}, +   {"decltype-specifier"}, +  } }, + +  { "access-specifier", { +   {"private"}, +   {"protected"}, +   {"public"}, +  } }, + +  { "ctor-initializer", { +   {":", "mem-initializer-list"}, +  } }, + +  { "mem-initializer-list", { +   {"mem-initializer", optional("...")}, +   {"mem-initializer-list", ",", "mem-initializer", optional("...")}, +  } }, + +  { "mem-initializer", { +   {"mem-initializer-id", "(", optional("expression-list"), ")"}, +   {"mem-initializer-id", "braced-init-list"}, +  } }, + +  { "mem-initializer-id", { +   {"class-or-decltype"}, +   {"identifier"}, +  } }, + +  // [gram.over] + +  { "operator-function-id", { +   {"operator", "OPERATOR"}, +  } }, + +  { "OPERATOR", { +   {"new"}, {"delete"}, {"new[]"}, {"delete[]"}, {"co_await()[]"}, {"->"}, {"->*"}, +   {"~"}, {"!"}, {"+"}, {"-"}, {"*"}, {"/"}, {"%"}, {"^"}, {"&"}, +   {"|"}, {"="}, {"+="}, {"-="}, {"*="}, {"/="}, {"%="}, {"^="}, {"&="}, +   {"|="}, {"=="}, {"!="}, {"<"}, {">"}, {"<="}, {">="}, {"<=>"}, {"&&"}, +   {"||"}, {"<<"}, {">>"}, {"<<="}, {">>="}, {"++"}, {"--"}, {","}, +  } }, + +  { "literal-operator-id", { +   {"operator", "string-literal", "identifier"}, +   {"operator", "user-defined-string-literal"}, +  } }, + +  // [gram.temp] + +  { "template-declaration", { +   {"template-head", "declaration"}, +   {"template-head", "concept-definition"}, +  } }, + +  { "template-head", { +   {"template", "<", "template-parameter-list", ">", optional("requires-clause")}, +  } }, + +  { "template-parameter-list", { +   {"template-parameter"}, +   {"template-parameter-list", ",", "template-parameter"}, +  } }, + +  { "requires-clause", { +   {"requires", "constraint-logical-or-expression"}, +  } }, + +  { "constraint-logical-or-expression", { +   {"constraint-logical-and-expression"}, +   {"constraint-logical-or-expression", "||", "constraint-logical-and-expression"}, +  } }, + +  { "constraint-logical-and-expression", { +   {"primary-expression"}, +   {"constraint-logical-and-expression", "&&", "primary-expression"}, +  } }, + +  { "template-parameter", { +   {"type-parameter"}, +   {"parameter-declaration"}, +  } }, + +  { "type-parameter", { +   {"type-parameter-key", optional("..."), optional("identifier")}, +   {"type-parameter-key", optional("identifier"), "=", "type-id"}, +   {"type-constraint", optional("...") ,optional("identifier")}, +   {"type-constraint", optional("identifier"), "=", "type-id"}, +   {"template-head type-parameter-key", optional("..."), optional("identifier")}, +   {"template-head type-parameter-key", optional("identifier"), "=", "id-expression"}, +  } }, + +  { "type-parameter-key", { +   {"class"}, +   {"typename"}, +  } }, + +  { "type-constraint", { +   {optional("nested-name-specifier"), "concept-name"}, +   {optional("nested-name-specifier"), "concept-name", "<", optional("template-argument-list"), ">"}, +  } }, + +  { "simple-template-id", { +   {"template-name", "<", optional("template-argument-list"), ">"}, +  } }, + +  { "template-id", { +   {"simple-template-id"}, +   {"operator-function-id", "<", optional("template-argument-list"), ">"}, +   {"literal-operator-id" , "<", optional("template-argument-list"), ">"}, +  } }, + +  { "template-name", { +   {"identifier"}, +  } }, + +  { "template-argument-list", { +   {"template-argument", optional("...")}, +   {"template-argument-list", ",", "template-argument", optional("...")}, +  } }, + +  { "template-argument", { +   {"constant-expression"}, +   {"type-id"}, +   {"id-expression"}, +  } }, + +  { "constraint-expression", { +   {"logical-or-expression"}, +  } }, + +  { "deduction-guide", { +   {optional("explicit-specifier"), "template-name", "(", "parameter-declaration-clause", ")", "->", "simple-template-id", ";"}, +  } }, + +  { "concept-definition", { +   {"concept", "concept-name", "=", "constraint-expression", ";"}, +  } }, + +  { "concept-name", { +   {"identifier"}, +  } }, + +  { "typename-specifier", { +   {"typename", "nested-name-specifier", "identifier"}, +   {"typename", "nested-name-specifier", optional("template"), "simple-template-id"}, +  } }, + +  { "explicit-instantiation", { +   {optional("extern"), "template", "declaration"}, +  } }, + +  { "explicit-specialization", { +   {"template", "<", ">", "declaration"}, +  } }, + +  // [gram.except] + +  { "try-block", { +   {"try", "compound-statement", "handler-seq"}, +  } }, + +  { "function-try-block", { +   {"try", optional("ctor-initializer"), "compound-statement", "handler-seq"}, +  } }, + +  { "handler-seq", { +   {"handler", optional("handler-seq")}, +  } }, + +  { "handler", { +   {"catch", "(", "exception-declaration", ")", "compound-statement"}, +  } }, + +  { "exception-declaration", { +   {optional("attribute-specifier-seq"), "type-specifier-seq", "declarator"}, +   {optional("attribute-specifier-seq"), "type-specifier-seq", optional("abstract-declarator")}, +   {"..."}, +  } }, + +  { "noexcept-specifier", { +   {"noexcept", "(", "constant-expression", ")"}, +   {"noexcept"}, +  } }, + +  // [gram.cpp] + +  { "preprocessing-file", { +   {optional("group")}, +  } }, + +  { "group", { +   {"group-part"}, +   {"group", "group-part"}, +  } }, + +  { "group-part", { +   {"control-line"}, +   {"if-section"}, +   {"text-line"}, +   {"#", "conditionally-supported-directive"}, +  } }, + +  { "control-line", { +   {"#", "include", "pp-tokens", "new-line"}, +   {optional("export"), "import", "pp-tokens", "new-line"}, +   {"#", "define", "identifier", "replacement-list", "new-line"}, +   {"#", "define", "identifier", "lparen", optional("identifier-list"), ")", "replacement-list", "new-line"}, +   {"#", "define", "identifier", "lparen", "...", ")", "replacement-list", "new-line"}, +   {"#", "define", "identifier", "lparen", "identifier-list", ",", "...", ")", "replacement-list", "new-line"}, +   {"#", "undef",  "identifier", "new-line"}, +   {"#", "line", "pp-tokens", "new-line"}, +   {"#", "error",  optional("pp-tokens"), "new-line"}, +   {"#", "pragma", optional("pp-tokens"), "new-line"}, +   {"#", "new-line"}, +  } }, + +  { "if-section", { +   {"if-group", optional("elif-groups"), optional("else-group"), "endif-line"}, +  } }, + +  { "if-group", { +   {"#", "if",     "constant-expression", "new-line", optional("group")}, +   {"#", "ifdef",  "identifier", "new-line", optional("group")}, +   {"#", "ifndef", "identifier", "new-line", optional("group")}, +  } }, + +  { "elif-groups", { +   {"elif-group"}, +   {"elif-groups", "elif-group"}, +  } }, + +  { "elif-group", { +   {"#", "elif", "constant-expression", "new-line", optional("group")}, +  } }, + +  { "else-group", { +   {"#", "else", "new-line", optional("group")}, +  } }, + +  { "endif-line", { +   {"#", "endif", "new-line"}, +  } }, + +  { "text-line", { +   {optional("pp-tokens"), "new-line"}, +  } }, + +  { "conditionally-supported-directive", { +   {"pp-tokens", "new-line"}, +  } }, + +  { "lparen", { +   {"("}, // TODO: NOT immediately preceded by white-space! +  } }, + +  { "identifier-list", { +   {"identifier"}, +   {"identifier-list", "identifier"}, +  } }, + +  { "replacement-list", { +   {optional("pp-tokens")}, +  } }, + +  { "pp-tokens", { +   {"preprocessing-token"}, +   {"pp-tokens", "preprocessing-token"}, +  } }, + +  { "new-line", { +   {"\n"}, +  } }, + +  { "defined-macro-expression", { +   {"defined", "identifier"}, +   {"defined", "(", "identifier", ")"}, +  } }, + +  { "h-preprocessing-token", { +   {"preprocessing-token"}, // TODO: except ">" +  } }, + +  { "h-pp-tokens", { +   {"h-preprocessing-token"}, +   {"h-pp-tokens", "h-preprocessing-token"}, +  } }, + +  { "header-name-tokens", { +   {"string-literal"}, +   {"<", "h-pp-tokens", ">"}, +  } }, + +  { "has-include-expression", { +   {"__has_include", "(", "header-name", ")"}, +   {"__has_include", "(", "header-name-tokens", ")"}, +  } }, + +  { "has-attribute-expression", { +   {"__has_cpp_attribute", "(", "pp-tokens", ")"}, +  } }, + +  { "pp-import", { +   {optional("export"), "import", "header-name",        optional("pp-tokens"), ";", "new-line"}, +   {optional("export"), "import", "header-name-tokens", optional("pp-tokens"), ";", "new-line"}, +   {optional("export"), "import",                                "pp-tokens",  ";", "new-line"}, +  } }, + +  { "pp-global-module-fragment", { +   {"module", ";", "pp-balanced-token-seq", "module"}, +  } }, + +  { "pp-balanced-token-seq", { +   {"pp-balanced-token"}, +   {"pp-balanced-token-seq", "pp-balanced-token"}, +  } }, + +  { "pp-balanced-token", { +   {"pp-ldelim", optional("pp-balanced-token-seq"), "pp-rdelim"}, +   // TODO: + any preprocessing-token except pp-ldelim and pp-rdelim +  } }, + +  { "pp-ldelim", { +   {"(", "[", "{", "<:", "<%"}, +  } }, + +  { "pp-rdelim", { +   {")", "]", "}", ":>", "%>"}, +  } }, + +  { "va-opt-replacement", { +   {"__VA_OPT__", "(", optional("pp-tokens"), ")"}, +  } }, + }; + + return normalizeBNF(bnf); +} + +TEST(Lex, Test2) { + auto bnf = GetCppBNFLex(); + + EXPECT_TRUE(valid(bnf)); + EXPECT_TRUE(validLex(bnf)); +} + +TEST(Gram, Test3) { + auto bnf = GetCppBNFGram(); + + EXPECT_TRUE(valid(bnf)); +} | 
