# Modified from this ANSI C yacc grammmar file I got from the Internet:
# https://www.lysator.liu.se/c/ANSI-C-grammar-y.html
#
#     In 1985, Jeff Lee published his Yacc grammar (which is accompanied by a
#     matching Lex specification) for the April 30, 1985 draft version of the
#     ANSI C standard.
#     Tom Stockfisch reposted it to net.sources in 1987; that original, as
#     mentioned in the answer to question 17.25 of the comp.lang.c FAQ, can be
#     ftp'ed from ftp.uu.net, file usenet/net.sources/ansi.c.grammar.Z.
#
#     Jutta Degener, 1995
#
# ...thanks, Jutta! :)
# - BAG, 2026

primary_expression
    | ident:    IDENTIFIER
    | literal:  CHAR
    | literal:  STRING
    | literal:  NUMBER
    | '(' expression ')'
    ;

field_name
    | IDENTIFIER
    ;

postfix_operator
    | index: '[' expression ']'
    | call:  '(' ( assignment_expression ( ',' assignment_expression )* )? ')'
    | dot:   '.' field_name
    | arrow: '->' field_name
    ;

postfix_expression
    | primary_expression ( postfix_operator )*
    ;

postfix_increment_expression
    | inc: postfix_expression '++'
    | dec: postfix_expression '--'
    | postfix_expression
    ;

unary_operator
    | [ '&' '*' '+' '-' '~' '!' ]
    ;

unary_expression
    | sizeof_type:  'sizeof' '(' type_name ')'
    | sizeof_expr:  'sizeof' unary_expression
    | inc: '++' unary_expression
    | dec: '--' unary_expression
    | unary_operator cast_expression
    | postfix_increment_expression
    ;

cast_expression
    | cast: '(' type_name ')' cast_expression
    | unary_expression
    ;

multiplicative_operator
    | [ '*' '/' '%' ]
    ;

multiplicative_expression
    | cast_expression ( multiplicative_operator cast_expression )*
    ;

additive_operator
    | [ '+' '-' ]
    ;

additive_expression
    | multiplicative_expression ( additive_operator multiplicative_expression )*
    ;

shift_operator
    | [ '<<' '>>' ]
    ;

shift_expression
    | additive_expression ( shift_operator additive_expression )*
    ;

relational_operator
    | [ '<' '>' '<=' '>=' ]
    ;

relational_expression
    | shift_expression ( relational_operator shift_expression )*
    ;

equality_operator
    | [ '==' '!=' ]
    ;

equality_expression
    | relational_expression ( equality_operator relational_expression )*
    ;

and_expression
    | equality_expression ( '&' equality_expression )*
    ;

exclusive_or_expression
    | and_expression ( '^' and_expression )*
    ;

inclusive_or_expression
    | exclusive_or_expression ( '|' exclusive_or_expression )*
    ;

logical_and_expression
    | inclusive_or_expression ( '&&' inclusive_or_expression )*
    ;

logical_or_expression
    | logical_and_expression ( '||' logical_and_expression )*
    ;

conditional_expression
    | logical_or_expression ( '?' expression ':' conditional_expression )?
    ;

assignment_operator
    | [ '=' '*=' '/=' '%=' '+=' '-=' '<<=' '>>=' '&=' '^=' '|=' ]
    ;

assignment_expression
    | assign: unary_expression assignment_operator assignment_expression
    | conditional_expression
    ;

expression
    | assignment_expression ( ',' assignment_expression )*
    ;

constant_expression
    | conditional_expression
    ;

storage_class_specifier
    | [ 'typedef' 'extern' 'static' 'auto' 'register' ]
    ;

type_specifier
    | [ 'void' 'char' 'short' 'int' 'long' 'float' 'double' 'signed' 'unsigned' '_Bool' ]
    | struct_or_union_specifier
    | enum_specifier
    | TYPE_NAME
    ;

type_qualifier
    | [ 'const' 'volatile' 'restrict' ]
    ;

declaration_specifier
    | storage_class_specifier
    | type_specifier
    | type_qualifier
    ;

declaration_specifiers
    | declspec: declaration_specifier ( declaration_specifier )*
    ;

initializer
    | assignment_expression
    | initializer_list: '{' initializer ( ',' initializer )* ( ',' )? '}'
    ;

init_declarator
    | decl: declarator ( '=' initializer )?
    ;

declaration
    # NOTE: patterns explicitly named so we can track when we exit a
    # declaration during parsing, and make note of any typedefs...
    | decl: declaration_specifiers ';'
    | decl: declaration_specifiers ( init_declarator ( ',' init_declarator )* )? ';'
    ;

struct_or_union_or_enum_tag
    | IDENTIFIER
    ;

struct_or_union_specifier
    | struct_or_union ( struct_or_union_or_enum_tag )? '{' struct_declaration_list '}'
    | struct_or_union struct_or_union_or_enum_tag
    ;

struct_or_union
    | [ 'struct' 'union' ]
    ;

struct_declaration_list
    | struct_declaration ( struct_declaration )*
    ;

struct_declaration
    | specifier_qualifier_list struct_declarator_list ';'
    ;

specifier_qualifier
    | type_specifier
    | type_qualifier
    ;

specifier_qualifier_list
    | specifier_qualifier ( specifier_qualifier )*
    ;

struct_declarator_list
    | struct_declarator ( ',' struct_declarator )*
    ;

struct_declarator
    | declarator ( ':' constant_expression )?
    | ':' constant_expression
    ;

enum_specifier
    | 'enum' struct_or_union_or_enum_tag ( '{' enumerator_list '}' )?
    | 'enum' '{' enumerator_list '}'
    ;

enumerator_list
    | enumerator ( ',' enumerator )*
    ;

enumerator
    | IDENTIFIER ( '=' constant_expression )?
    ;

declarator_identifier
    | declare: IDENTIFIER
    ;

declarator_array_suffix
    | '[' ( constant_expression )? ']'
    ;

declarator_suffix
    | array:   declarator_array_suffix ( declarator_array_suffix )*
    | params:  '(' ( parameter_type_list )? ')'
    # Used in K&R function declarations:
    | params:  '(' declarator_identifier ( ',' declarator_identifier )* ')'
    ;

direct_declarator
    | declare: IDENTIFIER
    | '(' declarator ')'
    ;

pointer
    | pointer: '*' ( type_qualifier )* ( pointer )?
    ;

declarator
    | decl: ( pointer )? direct_declarator ( declarator_suffix )?
    ;

# NOTE: this is its own rule, to make sure it always generates a ParseMatch
ellipsis
    | '...'
    ;

parameter_type_list
    | parameter_list ( ',' ellipsis )?
    ;

parameter_list
    | parameter_declaration ( ',' parameter_declaration )*
    ;

parameter_declaration
    | declaration_specifiers declarator
    | declaration_specifiers abstract_declarator
    | declaration_specifiers
    ;

type_name
    | specifier_qualifier_list ( abstract_declarator )?
    ;

abstract_declarator_suffix
    | array:  '[' ( constant_expression )? ']'
    | params: '(' ( parameter_type_list )? ')'
    ;

abstract_declarator
    | pointer ( abstract_declarator )?
    | abstract_declarator_suffix ( abstract_declarator_suffix )*
    | '(' abstract_declarator ')'
    ;

statement
    | labeled_statement
    | compound_statement
    | selection_statement
    | iteration_statement
    | jump_statement
    | expression_statement
    ;

label_name
    | IDENTIFIER
    ;

labeled_statement
    | label:    label_name ':' statement
    ;

compound_statement
    | block:  '{' ( declaration_list )? ( statement_list )? '}'
    ;

declaration_list
    | declaration ( declaration )*
    ;

statement_list
    | statement ( statement )*
    ;

empty_expression_statement
    | ';'
    ;

expression_statement
    | empty_expression_statement
    | expression ';'
    ;

else_statement
    | else:  'else' statement
    ;

switch_body_statement
    # NOTE: the statement after 'case' is optional, to allow for patterns
    # like this:
    #   case 1:
    #   case 2: expression
    # ...which isn't really correct, but we've tweaked the original ANSI
    # grammar in order for our mini-C's "evaluate the grammar-tree directly"
    # approach to work...
    | case:     'case' constant_expression ':' ( statement )?
    | default:  'default' ':' statement
    | statement
    ;

selection_statement
    | if:      'if' '(' expression ')' statement ( else_statement )?
    # ANSI says: 'switch' '(' expression ')' statement
    # ...but we don't support crazy switch statements...
    | switch:  'switch' '(' expression ')' '{' ( switch_body_statement )* '}'
    ;

iteration_statement
    | while:  'while' '(' expression ')' statement
    | do:     'do' statement 'while' '(' expression ')' ';'
    | for:    'for' '(' expression_statement expression_statement ( expression )? ')' statement
    ;

label
    | IDENTIFIER
    ;

jump_statement
    | goto:      'goto' label ';'
    | continue:  'continue' ';'
    | break:     'break' ';'
    | return:    'return' ( expression )? ';'
    ;

function_definition
    | ( declaration_specifiers )? declarator ( declaration_list )? compound_statement
    ;

external_declaration
    | function_definition
    | declaration
    ;

repl_command
    | function_definition
    | declaration
    | statement
    ;

repl_expression
    | trailing: expression
    ;

repl_commands
    | ( repl_command )* ( repl_expression )?
    ;

translation_unit
    | external_declaration ( external_declaration )*
    ;
