# C99 grammar with a few extensions needed to make more syntax tests designed for gcc/clang extensions work (e.g. they always support some c11/c23-isms because they originated as GNU extensions)
__COMMENTS ::= "//" | "#"
__COMMENT_PAIRS ::= /* */
__BRACKET_PAIRS ::= { } | ( ) | [ ]
# only used by the peekres command (not peekr, not regex terminals)
__RESERVED_WORDS ::=
auto break case char const continue default do double else enum extern float for goto
if inline __inline__ __inline int long
register restrict __cdecl __stdcall __restrict__ return short signed sizeof static struct switch typedef union unsigned void volatile
while _Bool _Complex _Imaginary _Float16 __bf16 __int128
S ::= translation_unit
declaration_specifiers ::=
declaration_specifier $become declaration_specifiers_star
declaration_specifiers_star ::=
@peekr(1, r`[\[\),;:=]`r) #empty
| @peekr(0, r`__attribute__|__attribute`r) declaration_specifiers_star_guarded
| @peekr(1, r`\(`r) $become declaration_specifiers_star_guard2
| $become declaration_specifiers_star_guarded
declaration_specifiers_star_guard2 ::=
@peekr(2, r`\*|__attribute__|__attribute`r) $become declaration_specifiers_star_guarded
| #empty
declaration_specifiers_star_guarded ::=
@guard(is_declaration_indicator) declaration_specifier $become declaration_specifiers_star
| #empty
declaration_specifier ::=
@peekr(0, r`typedef|extern|static|auto|register`r) storage_class_specifier $become attribute_list
| @peekr(0, r`const|restrict|__cdecl|__stdcall|__restrict__|volatile`r) type_qualifier $become attribute_list
| @peekr(0, r`inline|__inline__|__inline`r) function_specifier $become attribute_list
| type_specifier $become attribute_list
# gcc extension
attribute_list ::=
@peekr(0, r`__attribute__|__attribute`r) attribute $become attribute_list
| #empty
storage_class_specifier ::=
@auto R`typedef|extern|static|auto|register`r
type_specifier ::=
@auto R`void|char|short|int|__builtin_va_list|long|float|double|signed|unsigned|_Bool|_Complex|_Imaginary`r
| @peek(0, "enum") enum_specifier
| @peekr(0, r`struct|union`r) struct_or_union_specifier
| @peekr(0, r`typeof|__typeof__`r) typeof_specifier
| typedef_name
type_qualifier ::=
@auto R`const|restrict|__cdecl|__stdcall|__restrict__|volatile`r
typeof_specifier ::=
R`typeof|__typeof__`r "(" many_balanced ")"
struct_or_union_specifier ::=
struct_or_union $become struct_or_union_specifier_next
struct_or_union_specifier_next ::=
@peekr(0, r`__attribute__|__attribute`r) attribute_list $become struct_or_union_specifier_info
| $become struct_or_union_specifier_info
struct_or_union_specifier_info ::=
@auto "{" !hook(scope_push) struct_declaration_list !hook(scope_pop) "}"
| identifier attribute_list $become struct_or_union_specifier_info2
struct_or_union_specifier_info2 ::=
@auto "{" !hook(scope_push) struct_declaration_list !hook(scope_pop) "}" | #empty
struct_or_union ::=
@auto "struct" | "union"
struct_declaration_list ::=
@peek(0, "}") #empty
| struct_declaration $become struct_declaration_star
struct_declaration_star ::=
@peek(0, "}") #empty (FOLLOW set logic)
| struct_declaration $become struct_declaration_star
struct_declaration ::=
specifier_qualifier_list struct_declarator_list ";"
specifier_qualifier_list ::=
specifier_qualifier specifier_qualifier_star
specifier_qualifier ::=
@peekr(0, r`const|restrict|__cdecl|__stdcall|__restrict__|volatile`r) type_qualifier
| type_specifier
specifier_qualifier_star ::=
@peekr(1, r`[\[;:=]`r) #empty
| @peekr(0, r`const|restrict|__cdecl|__stdcall|__restrict__|volatile`r) type_qualifier $become specifier_qualifier_star
| @guard(is_type_specifier_start) type_specifier $become specifier_qualifier_star
| #empty
struct_declarator_list ::=
struct_declarator $become struct_declarator_list_tail
struct_declarator_list_tail ::=
@auto "," struct_declarator $become struct_declarator_list_tail
| #empty
struct_declarator ::=
@peek(0, ";") #empty
| @auto ":" constant_expression
| declarator $become struct_declarator_declarator_tail
struct_declarator_declarator_tail ::=
@auto ":" constant_expression
| #empty
enum_specifier ::=
"enum" attribute_list $become enum_specifier_contents
enum_specifier_contents ::=
@peek(0, "{") $become enum_specifier_info
| identifier $become enum_specifier_info_maybe
enum_specifier_info_maybe ::=
@peek(0, "{") $become enum_specifier_info
| #empty
enum_specifier_info ::=
"{" enumerator_list "}" !hook(enums_log)
enumerator_list ::=
enumerator $become enumerator_list_tail
enumerator_list_tail ::=
@auto "," $become enumerator_list_tail2
| #empty
enumerator_list_tail2 ::=
@peek(0, "}") #empty # FOLLOW set logic
| enumerator $become enumerator_list_tail
enumerator ::=
enumeration_constant attribute_list $become enumerator_value
enumerator_value ::=
@auto "=" constant_expression
| #empty
function_specifier ::=
@auto "inline" | @auto "__inline__" | "__inline"
identifier_list ::=
identifier $become identifier_list_tail
identifier_list_tail ::=
@auto "," identifier $become identifier_list_tail
| #empty
pointer ::=
pointer_info $become pointer_star
pointer_info ::=
"*" type_qualifier_star
pointer_star ::=
@peek(0, "*") pointer_info $become pointer_star
| #empty
type_qualifier_list ::=
type_qualifier type_qualifier_star
type_qualifier_star ::=
@peekr(0, r`const|restrict|__cdecl|__stdcall|__restrict__|volatile`r) type_qualifier $become type_qualifier_star
| #empty
parameter_type_list ::=
parameter_declaration $become parameter_list_tail
parameter_list_tail ::=
@auto "," $become parameter_list_tail2
| @peek(0, ")") #empty # FOLOW set logic
parameter_list_tail2 ::=
@auto "..."
| parameter_declaration $become parameter_list_tail
parameter_declaration ::=
attribute_list declaration_specifiers attribute_list parameter_declarator !hook(typedefs_log)
parameter_declarator ::=
@peek(0, "*") pointer $become parameter_declarator2
| @peekr(0, r`\(|\[`r) NA_direct_abstract_declarator
| @peekr(0, r`[^,)]*`r) declarator
| #empty (no variable name)
parameter_declarator2 ::=
@peekr(0, r`\(|\[`r) NA_direct_abstract_declarator
| @peekr(0, r`[^,)]*`r) direct_declarator attribute_list
| #empty (no variable name)
type_name ::=
specifier_qualifier_list abstract_declarator_maybe
abstract_declarator_maybe ::=
@peekr(0, r`\(|\[|\*`r) abstract_declarator
| #empty
declarator ::=
@peek(0, "*") pointer attribute_list direct_declarator maybe_asm_statement attribute_list
| direct_declarator maybe_asm_statement attribute_list
direct_declarator ::=
@auto "(" attribute_list declarator ")" $become direct_declarator_corelist
| attribute_list identifier direct_declarator_corelist
direct_declarator_core ::=
@auto "[" any_direct_declarator_core_sq
| "(" direct_declarator_core_p
direct_declarator_core_p ::=
@auto ")"
| @auto "..." ")"
| @peekr(0, r`__attribute__|__attribute`r) !hook(scope_push) parameter_type_list !hook(scope_pop) ")"
| @guard(is_declaration_indicator) !hook(scope_push) parameter_type_list !hook(scope_pop) ")"
| !hook(scope_push) identifier_list !hook(scope_pop) ")" # Blame this rule specifically for concrete and abstract declarators not being merged.
direct_declarator_corelist ::=
@peekr(0, r`\[|\(`r) direct_declarator_core $become direct_declarator_corelist
| #empty
direct_abstract_declarator_core ::=
@auto "[" any_direct_declarator_core_sq
| "(" direct_abstract_declarator_core_p
direct_abstract_declarator_core_p ::=
@auto ")"
| @auto "..." ")"
| !hook(scope_push) parameter_type_list !hook(scope_pop) ")"
# Note the lack of identifier_list rule.
direct_abstract_declarator_corelist ::=
@peekr(0, r`\[|\(`r) direct_abstract_declarator_core direct_abstract_declarator_corelist
| #empty
abstract_declarator ::=
@peek(0, "*") pointer $become direct_abstract_declarator_maybe
| direct_abstract_declarator
direct_abstract_declarator_maybe ::=
@peekr(0, r`\(|\[`r) direct_abstract_declarator
| #empty
direct_abstract_declarator ::=
attribute_list abstract_declarator_wrapped_and_maybe direct_abstract_declarator_corelist
abstract_declarator_wrapped_and_maybe ::=
@peek(0, "(") $become abstract_declarator_wrapped_and_maybe2
| #empty
abstract_declarator_wrapped_and_maybe2 ::=
@peekr(1, r`\*|\(|\[|__attribute__|__attribute`r) "(" attribute_list abstract_declarator ")"
| #empty
# "name allowed" variants
NA_abstract_declarator ::=
@peek(0, "*") pointer identifier_maybe NA_direct_abstract_declarator_maybe
| identifier_maybe NA_direct_abstract_declarator
NA_direct_abstract_declarator_maybe ::=
@peekr(0, r`\(|\[`r) NA_direct_abstract_declarator
| #empty
NA_direct_abstract_declarator ::=
attribute_list NA_abstract_declarator_wrapped_and_maybe direct_abstract_declarator_corelist
# non-empty identifier_list terms are forbidden outside of function definitions
# AND: function definitions cannot be abstract
# THEREFORE: it's safe to use direct_abstract_declarator_corelist instead of direct_declarator_corelist
NA_abstract_declarator_wrapped_and_maybe ::=
@peek(0, "(") $become NA_abstract_declarator_wrapped_and_maybe2
| #empty
NA_abstract_declarator_wrapped_and_maybe2 ::=
@peekr(1, r`\*|\(|\[|__attribute__|__attribute`r) "(" attribute_list NA_abstract_declarator ")"
| #empty
# agnostic to what kind of declarator we're in
any_direct_declarator_core_sq ::=
@auto "static" type_qualifier_star assignment_expression "]"
| @peekr(0, r`const|restrict|__cdecl|__stdcall|__restrict__|volatile`r) type_qualifier_list $become any_direct_declarator_chunk_square3
| @auto "]"
| @peek(0, "*") $become any_declarator_chunk_square_ptrpart
| assignment_expression "]"
any_direct_declarator_chunk_square3 ::=
@auto "static" assignment_expression "]"
| @auto "]"
| @peek(0, "*") $become any_declarator_chunk_square_ptrpart
| assignment_expression "]"
any_declarator_chunk_square_ptrpart ::=
@peek(1, "]") "*" "]"
| assignment_expression "]"
typedef_name ::=
identifier
initializer ::=
@auto "{" initializer_list $become initializer_comma_chomp
| assignment_expression
initializer_comma_chomp ::=
@auto "," "}"
| "}"
designated_initializer ::=
@peekr(0, r`[\[.]`r) designation initializer
| initializer
initializer_list ::=
@peek(0, "}") #empty # C23 extension: empty initializer lists
| designated_initializer $become initializer_list_tail
initializer_list_tail ::=
@auto "," $become initializer_list_tail_guarded
| #empty
initializer_list_tail_guarded ::=
@peek(0, "}") #empty
| designated_initializer $become initializer_list_tail
designation ::=
designator_list "="
designator_list ::=
designator $become designator_star
designator_star ::=
@peekr(0, r`[\[.]`r) designator $become designator_star
| #empty
designator ::=
@auto "[" constant_expression "]"
| "." identifier
primary_expression ::=
@peekr(0, r`[L]?\x22.*\x22`r) string_literal
| @auto "_Generic" "(" many_balanced ")"
| @guard(is_ident_not_known_enum) $become_as identifier
| $become constant
postfix_expression_atom ::=
@auto "(" $become postfix_expression_atom_choice
| $become_as primary_expression
postfix_expression_atom_choice ::=
@guard(is_type_specifier_start) $become_as compound_lit_expression
| $become_as primary_expression_2
primary_expression_2 ::= expression ")"
compound_lit_expression ::= type_name ")" "{" initializer_list initializer_comma_chomp
postfix_expression ::=
@peekr(0, r`__builtin_.*`r) $become postfix_expression_builtin_guard
| postfix_expression_atom $become postfix_trailer_star
postfix_expression_builtin_guard ::=
@peek(1, "(") ext_builtin
| postfix_expression_atom $become postfix_trailer_star
ext_builtin ::= # builtins can take non-expressions as arguments. bypass argument parsing.
R`__builtin_[a-zA-Z_0-9]*`r "(" many_balanced ")" $become postfix_trailer_star
postfix_trailer_star ::=
@peekr(0, r`\[|\(|\.|->|\+\+|--`r) postfix_trailer $become postfix_trailer_star
| #empty
postfix_trailer ::=
@auto "[" expression "]"
| @auto "(" $become postfix_trailer_paren
| @auto "." identifier
| @auto "->" identifier
| @auto "++"
| "--"
postfix_trailer_paren ::=
@auto ")"
| $become_as argument_expression_list
argument_expression_list ::=
assignment_expression $become argument_expression_list_tail
argument_expression_list_tail ::=
@auto "," assignment_expression $become argument_expression_list_tail
| ")" #empty
unary_expression ::=
@auto "++" $become unary_expression
| @auto "--" $become unary_expression
| @auto "sizeof" $become sizeof_argument
| @auto "_Alignof" $become sizeof_argument
| @auto R`[&*\+\-~!]`r cast_expression
| $become_as postfix_expression
sizeof_argument ::=
@peek(0, "(") $become sizeof_argument_guarded
| $become_as unary_expression
sizeof_argument_guarded ::=
@guard(is_postfix_not_sizeof_argument) assignment_expression
| "(" $become sizeof_argument_trail
sizeof_argument_trail ::=
@guard(is_type_specifier_start) type_name ")"
| assignment_expression ")"
cast_expression ::=
@guard(is_primitive_cast) "(" type_name ")" $become cast_expression
| $become_as unary_expression
infix_expression ::=
cast_expression $become infix_expression_tail
infix_expression_tail ::=
@auto R`(?x)(?:\
\|\||&&|==|>=|<=|!=|>>|<<|\
\*|\+|\^|\||&|-|/|%|>|<\
)`r cast_expression $become infix_expression_tail
| !hook(fix_infix_precedence) #empty
conditional_expression ::=
infix_expression $become conditional_expression_tail
conditional_expression_tail ::=
@auto "?" expression ":" conditional_expression | #empty
# The C standard tried encoding semantics in syntax.
# It doesn't even work. Examples: ++x = 5; and (x + 3) = 5;
#assignment_expression ::=
# conditional_expression
# unary_expression r`(?:\*|/|%|\+|-|<<|>>|&|\^|\|)?=`r assignment_expression
# Slightly more permissive rule that is less incredibly awful to parse:
assignment_expression ::=
@auto "__extension__" $become assignment_expression
| conditional_expression $become assignment_expression_tail
assignment_expression_tail ::=
@auto R`(?:\*|/|%|\+|-|<<|>>|&|\^|\|)?=`r conditional_expression $become assignment_expression_tail
| #empty
# I suspect this is roughly what real C compilers do and that they enforce the semantics rule afterwards.
# For example in GCC this is a semantics error instead of a syntax error, saying that x+5 isn't a valid lvalue. Clang fails similarly:
# int myfunc() {
# int* x;
# 5+x = 3;
# }
# ... and using x+5 instead of 5+x gives the same error. And using ++0 (yes, really) instead of 5+x gives the same error.
expression ::=
@auto "__extension__" $become expression
| @peekr(1, r`\]`r) primary_expression $become expression_tail
| assignment_expression $become expression_tail
expression_tail ::=
@auto "," assignment_expression $become expression_tail
| #empty
constant_expression ::=
$become conditional_expression
maybe_asm_statement ::=
@peekr(0, r`__asm|__asm__|asm`r) asm_statement
| #empty
statement ::=
@peekr(0, r`__attribute__|__attribute`r) attribute_list $become core_statement
| $become core_statement
core_statement ::=
@peekr(0, r`__asm|__asm__|asm`r) asm_statement ";"
| @guard(is_label) $become_as labeled_statement
| @peekr(0, r`switch|if`r) $become_as selection_statement
| @peekr(0, r`while|do|for`r) $become_as iteration_statement
| @peekr(0, r`goto|continue|break|return`r) $become_as jump_statement
| @peek(0, "{") $become_as scoped_compound_statement
| $become_as expression_statement
# gcc extension
asm_statement ::=
R`__asm|__asm__|asm`r asm_qualifiers "(" asm_body ")"
asm_qualifiers ::=
@auto "volatile" $become asm_qualifiers
| @auto "__volatile__" $become asm_qualifiers
| @auto "inline" $become asm_qualifiers
| @auto "__inline__" $become asm_qualifiers
| @auto "goto" $become asm_qualifiers
| #empty
asm_body ::=
string_literal asm_body_2
asm_body_2 ::=
@auto ":" asm_var_regs asm_body_3
| #empty
asm_body_3 ::=
@auto ":" asm_var_regs asm_body_4
| #empty
asm_body_4 ::=
@auto ":" asm_clobbers asm_body_5
| #empty
asm_body_5 ::=
@auto ":" asm_gotos
| #empty
asm_var_regs ::=
@auto "[" identifier "]" string_literal "(" expression ")" $become asm_var_regs_tail
| @peekr(0, r`[L]?\x22.*\x22`r) string_literal "(" expression ")" $become asm_var_regs_tail
| #empty
asm_var_regs_tail ::=
@auto "," $become asm_var_regs
| #empty
asm_clobbers ::=
@peek(0, "[") "[" identifier "]" string_literal $become asm_var_regs_tail
| @peekr(0, r`[L]?\x22.*\x22`r) string_literal $become asm_var_regs_tail
| #empty
asm_clobbers_tail ::=
@auto "," $become asm_clobbers
| #empty
asm_gotos ::=
@peekr(0, r`[a-zA-Z_].*`r) identifier $become asm_var_regs_tail
| #empty
asm_gotos_tail ::=
@auto "," $become asm_gotos
| #empty
labeled_statement ::=
@auto "case" constant_expression ":" statement
| @auto "default" ":" statement
| identifier ":" statement
scoped_compound_statement ::=
!hook(scope_push) compound_statement !hook(scope_pop)
compound_statement ::=
@peekr(0, r`__attribute__|__attribute`r) attribute_list $become compound_statement
| "{" $become compound_statement_trail
attribute ::=
$pruned r`__attribute__|__attribute`r "(" "(" many_balanced ")" ")"
compound_statement_trail ::=
@auto "}"
| block_item_list "}"
block_item_list ::=
block_item $become block_item_star
block_item_star ::=
@peek(0, "}") #empty # FOLLOW set logic
| block_item $become block_item_star
block_item ::=
attribute_list $become block_item_unguarded
block_item_unguarded ::=
@peek(1, ":") $become_as statement # namelookup-bug-2.c
| @guard(is_declaration_indicator) $become_as declaration
| $become_as statement
expression_statement ::=
@auto ";"
| expression ";"
selection_statement ::=
@auto "switch" $pruned "(" expression ")" statement
| "if" $pruned "(" expression ")" statement $become else_maybe
else_maybe ::=
@auto "else" statement
| #empty
iteration_statement ::=
@auto "while" $pruned "(" expression ")" statement
| @auto "do" $pruned statement "while" "(" expression ")" ";"
| "for" $pruned "(" forloop_head_contents ")" statement
forloop_head_contents ::=
@auto ";" $become forloop_head_contents2
| @guard(is_declaration_indicator) declaration $become forloop_head_contents2
| expression ";" $become forloop_head_contents2
forloop_head_contents2 ::=
@auto ";" $become forloop_head_contents3
| expression ";" $become forloop_head_contents3
forloop_head_contents3 ::=
@peek(0, ")") #empty # FOLLOW set logic
| expression
jump_statement ::=
@auto "goto" identifier $pruned ";"
| @auto "continue" $pruned ";"
| @auto "break" $pruned ";"
| "return" $become return_operand
return_operand ::=
@auto ";"
| expression $pruned ";"
translation_unit ::=
external_declaration $become external_declaration_star
external_declaration_star ::=
@eof #empty
| external_declaration $become external_declaration_star
declaration ::=
declaration_specifiers $become declaration_tail
declaration_tail ::=
@auto ";"
| init_declarator_list ";" !hook(typedefs_log)
#function_definition:
# declaration_specifiers declarator $become function_definition_cont
#external_declaration ::=
# @guard(is_funcdef) function_definition
# | declaration
# UHHHH yeah it looks like this isn't how real C compilers do it and also it's insane.
# The insanity is the arbitrarily long ambiguity until the first declarator stops.
# Let's do something tractible instead.
external_declaration ::=
@auto ";" #stray semicolon
| @peekr(0, r`(?:_S|s)tatic_assert`r) static_assert
| attribute_list $become external_declaration_deattributed
external_declaration_deattributed ::=
@peekr(0, r`__asm|__asm__|asm`r) asm_statement ";"
| declaration_specifiers $become extdec_chooser
extdec_chooser ::=
@peek(0, ";") $become_as empty_declaration
| declarator $become extdec_declarator_choice
empty_declaration ::= ";"
extdec_declarator_choice ::=
@peekr(0, r`=|;|,|asm|__asm|__asm__`r) $become_as extdec_declaration
| $become_as function_definition
extdec_declaration_init ::=
init_declarator $become init_declarator_list_tail
extdec_declaration ::=
@auto "," init_declarator_list ";" !hook(typedefs_log)
| @auto "=" initializer $become extdec_declaration_init_rest
| ";" !hook(typedefs_log)
extdec_declaration_init_rest ::=
@auto "," init_declarator_list ";" !hook(typedefs_log)
| ";" !hook(typedefs_log)
function_definition ::=
attribute_list func_knr_declaration_star $become func_scope
func_scope ::=
@peekr(0, r`__attribute__|__attribute`r) attribute_list $become func_scope
| @peek(0, "{") !hook(scope_push) !hook(entered_function) compound_statement !hook(scope_pop)
func_knr_declaration_star ::=
@peek(0, "{") #empty
| declaration $become func_knr_declaration_star
static_assert ::=
R`(?:_S|s)tatic_assert`r "(" assignment_expression many_balanced ")" ";"
init_declarator_list ::=
init_declarator $become init_declarator_list_tail
init_declarator_list_tail ::=
@auto "," init_declarator $become init_declarator_list_tail
| #empty
init_declarator ::=
declarator $become init_declarator_tail
init_declarator_tail ::=
@auto "=" initializer
| #empty
constant ::=
@auto R`(?x) (?:(?: 0[xX][a-fA-F0-9]+ | [1-9][0-9]* | 0[0-7]* ) (?:[uU](?:ll|LL|l|L)?|(?:ll|LL|l|L)[uU]?)?)`r
| @auto R`(?x) (?:(?: (?: [0-9]*\.[0-9]+ | [0-9]+\. ) (?:[eE](?:-|\+)?[0-9]+)? | [0-9]+[eE](?:-|\+)?[0-9]+ ) (?:f16|F16|f|l|F|L)?)`r
| @auto R`(?x) (?:0[xX] (?: [a-fA-F0-9]*\.[a-fA-F0-9]+ | [a-fA-F0-9]+(?:\.)? ) [pP](?:-|\+)? [0-9]+ (?:f16|F16|f|l|F|L)?)`r
#| @auto R`(?x) [L]? \x27 (?: [^\x27\\\n] | \\[\x27\x22\\abefnrtv?] | \\[0-7]{1,3} | \\x[0-9a-fA-F]+ | (?:\\u[a-fA-F0-9]{1,4}|\\U[a-fA-F0-9]{1,8}) )+ \x27`r
| @auto R`(?x) [L]? \x27 (?: [^\x27\\\n] | \\[^xuU] | \\[0-7]{1,3} | \\x[0-9a-fA-F]+ | (?:\\u[a-fA-F0-9]{1,4}|\\U[a-fA-F0-9]{1,8}) )+ \x27`r
| @guard(is_known_enum) enumeration_constant
enumeration_constant ::=
identifier
string_literal ::=
string_literal_core $become string_literal_star
string_literal_star ::=
#@peekr(0, r`(?x) [L]? \x22 (?:[^\x22\\\n] | \\[\x27\x22\\abefnrtv?] | \\[0-7]{1,3} | \\x[0-9a-fA-F]+ | (?:\\u[a-fA-F0-9]{1,4}|\\U[a-fA-F0-9]{1,8}) )*\x22`r)
@peekr(0, r`(?x) [L]? \x22 (?:[^\x22\\\n] | \\[^xuU] | \\[0-7]{1,3} | \\x[0-9a-fA-F]+ | (?:\\u[a-fA-F0-9]{1,4}|\\U[a-fA-F0-9]{1,8}) )*\x22`r)
string_literal_core $become string_literal_star
| #empty
string_literal_core ::=
#R`(?x) [L]? \x22 (?:[^\x22\\\n] | \\[\x27\x22\\abefnrtv?] | \\[0-7]{1,3} | \\x[0-9a-fA-F]+ | (?:\\u[a-fA-F0-9]{1,4}|\\U[a-fA-F0-9]{1,8}) )*\x22`r
R`(?x) [L]? \x22 (?:[^\x22\\\n] | \\[^xuU] | \\[0-7]{1,3} | \\x[0-9a-fA-F]+ | (?:\\u[a-fA-F0-9]{1,4}|\\U[a-fA-F0-9]{1,8}) )*\x22`r
identifier_maybe ::=
@auto R`(?:[a-zA-Z_]|(?:\\u[a-fA-F0-9]{1,4}|\\U[a-fA-F0-9]{1,8}))(?:[a-zA-Z_]|(?:\\u[a-fA-F0-9]{1,4}|\\U[a-fA-F0-9]{1,8})|[0-9])*`r
| #empty
identifier ::=
R`(?:[a-zA-Z_]|(?:\\u[a-fA-F0-9]{1,4}|\\U[a-fA-F0-9]{1,8}))(?:[a-zA-Z_]|(?:\\u[a-fA-F0-9]{1,4}|\\U[a-fA-F0-9]{1,8})|[0-9])*`r
# Dummy for tokenization
_token_dummy ::=
r`(?x)(?:(?: (?: [0-9]*\.[0-9]+ | [0-9]+\. ) (?:[eE](?:-|\+)?[0-9]+)? | [0-9]+[eE](?:-|\+)?[0-9]+ ) (?:f16|F16|f|l|F|L)?)|\
(?:0[xX] (?: [a-fA-F0-9]*\.[a-fA-F0-9]+ | [a-fA-F0-9]+(?:\.)? ) [pP](?:-|\+)? [0-9]+ (?:f16|F16|f|l|F|L)?)|\
(?:[L]? \x27 (?:[^\x27\\\n] | \\[^xuU] | \\[0-7]{1,3} | \\x[0-9a-fA-F]+ | (?:\\u[a-fA-F0-9]{1,4}|\\U[a-fA-F0-9]{1,8}) )+\x27)|\
(?:[L]? \x22 (?:[^\x22\\\n] | \\[^xuU] | \\[0-7]{1,3} | \\x[0-9a-fA-F]+ | (?:\\u[a-fA-F0-9]{1,4}|\\U[a-fA-F0-9]{1,8}) )*\x22)|\
(?:(?:[a-zA-Z_]|(?:\\u[a-fA-F0-9]{1,4}|\\U[a-fA-F0-9]{1,8}))(?:[a-zA-Z_]|(?:\\u[a-fA-F0-9]{1,4}|\\U[a-fA-F0-9]{1,8})|[0-9])*)|\
(?:(?: 0[xX][a-fA-F0-9]+ | [1-9][0-9]* | 0[0-7]* ) (?:[uU](?:ll|LL|l|L)?|(?:ll|LL|l|L)[uU]?)?)|\
(?:(?:\*|/|%|\+|-|<<|>>|&|\^|\|)=|<<|>>|<=|>=|==|!=|&&|\|\||[&*/\+\-~!%<>=\^\|])`r
many_balanced ::=
@peek(0, ")") #empty
| @peek(0, "]") #empty
| @peek(0, "}") #empty
| @auto "(" many_balanced ")" $become many_balanced
| @auto "[" many_balanced "]" $become many_balanced
| @auto "{" many_balanced "}" $become many_balanced
| $any $become many_balanced