start: top_level*

?top_level: fun_decl
          | global_var
          | fun_def
          | struct_def
          | typedef

fun_decl: fun_prot ";"
fun_prot: type symbol "(" [fun_param ("," fun_param)*] ")"
fun_param: type [symbol]

global_var: type symbol sized_array* empty_array? [ "=" literal ] ";"

fun_def: fun_prot body

typedef: "typedef" type IDENTIFIER ";"

body: "{" statement* "}"

statement: if_stat
          | while_stat
          | for_stat
          | do_while_stat
          | "break" ";"        -> break
          | "continue" ";"     -> continue
          | "goto" label ";"   -> goto // yay \o/
          | "return" expression ";"  -> return_stat
          | local_var ";"
          | local_array
          | expression ";"
          | body

if_stat: "if" "(" expression ")" statement ["else" statement]
while_stat: "while" "(" expression ")" statement
for_stat: "for" "(" local_var? ";" expression? ";" iter_expression? ")" statement
do_while_stat: "do" statement "while" "(" expression ")" statement

iter_expression: expression
local_var: type symbol initializer?
local_array: type symbol sized_array* (sized_array | empty_array) initializer? ";"
empty_array: "[" "]"
sized_array: "[" array_size "]"
?initializer: "=" (expression | initializer_list)
initializer_list: "{" [init_list_field ("," init_list_field)* ","? ] "}"
?init_list_field: "." field "=" expression
                | prec14_expr

// precedence from https://en.cppreference.com/w/c/language/operator_precedence

?expression: comma_expr

?comma_expr: prec14_expr
           | comma_expr "," prec14_expr

?prec14_expr: prec13_expr
            | prec2_expr "="  prec14_expr  -> assignment
            | prec2_expr "+="  prec14_expr -> add_ass
            | prec2_expr "-="  prec14_expr
            | prec2_expr "*="  prec14_expr
            | prec2_expr "/="  prec14_expr
            | prec2_expr "%="  prec14_expr
            | prec2_expr "<<=" prec14_expr
            | prec2_expr ">>=" prec14_expr
            | prec2_expr "&="  prec14_expr
            | prec2_expr "^="  prec14_expr
            | prec2_expr "|="  prec14_expr -> or_ass

?prec13_expr: prec12_expr
            | prec12_expr "?" prec13_expr ":" prec13_expr

?prec12_expr: prec11_expr
            | prec12_expr "||" prec11_expr
?prec11_expr: prec10_expr
            | prec11_expr "&&" prec10_expr
?prec10_expr: prec9_expr
            | prec10_expr "|" prec9_expr   -> _or
?prec9_expr: prec8_expr
           | prec9_expr "^" prec8_expr
?prec8_expr: prec7_expr
           | prec8_expr "&" prec7_expr     -> _and  // reserved work in python
?prec7_expr: prec6_expr
           | prec7_expr "==" prec6_expr    -> eq
           | prec7_expr "!=" prec6_expr    -> neq
?prec6_expr: prec5_expr
           | prec6_expr "<" prec5_expr     -> lt
           | prec6_expr "<=" prec5_expr    -> lte
           | prec6_expr ">" prec5_expr     -> gt
           | prec6_expr ">=" prec5_expr    -> gte
?prec5_expr: prec4_expr
           | prec5_expr "<<" prec4_expr    -> shl
           | prec5_expr ">>" prec4_expr    -> shr
?prec4_expr: prec3_expr
           | prec4_expr "+" prec3_expr     -> add
           | prec4_expr "-" prec3_expr     -> sub
?prec3_expr: prec2_expr
           | prec3_expr "*" prec2_expr     -> mul
           | prec3_expr "/" prec2_expr     -> div
           | prec3_expr "%" prec2_expr     -> mod
?prec2_expr: prec1_expr
           | "++" prec2_expr               -> pre_increment
           | "--" prec2_expr               -> pre_decrement
           | "+" prec2_expr
           | "-" prec2_expr
           | "!" prec2_expr                -> bool_not
           | "~" prec2_expr
           | "(" (type | funptr_type) ")" prec2_expr       -> cast
           | "*" prec2_expr                -> dereference
           | "&" prec2_expr                -> address_of
           | "sizeof" prec2_expr           -> sizeof

?prec1_expr: literal
           | identifier
           | "(" expression ")"
           | prec1_expr "++"                -> post_increment
           | prec1_expr "--"                -> post_decrement
           | prec1_expr "(" expression? ")" -> fun_call
           | prec1_expr "[" expression "]"  -> array_item
           | prec1_expr "." field           -> field_access
           | prec1_expr "->" field          -> pointer_access




label: IDENTIFIER
literal: SIGNED_NUMBER | ESCAPED_STRING | HEX_LITTERAL | CHARACTER
field: IDENTIFIER
identifier: IDENTIFIER
?symbol: IDENTIFIER
type: type_qualifier* IDENTIFIER
     | struct_type
     | type "*" -> pointer
?array_size: INT
funptr_type: type "(" "*" ")" "(" [fun_param ("," fun_param)*] ")"

?type_qualifier: "volatile"  -> volatile
               | "const"     -> const
               | "static"    -> static
               | "extern"    -> extern

struct_type: "struct" (IDENTIFIER | IDENTIFIER? struct_body)
struct_def: "struct" IDENTIFIER struct_body ";"
struct_body: "{" struct_field* "}"
struct_field: type IDENTIFIER sized_array* ";"

IDENTIFIER: /[_a-zA-Z]\w*/
COMMENT: /\/\/.*/
HEX_LITTERAL: /0x[a-fA-F0-9]+/
CHARACTER: /'([^']|\\n|\\r|\\0|\\t)'/


%import common.WS
%import common.CNAME
%import common.C_COMMENT
%import common.SIGNED_NUMBER
%import common.INT
%import common.ESCAPED_STRING

%ignore COMMENT
%ignore C_COMMENT
%ignore WS
