#taken from n869.pdf
#google for n869.pdf

## A.1 Lexical grammar
grammar C99::Grammar;

## A.1.1 Lexical elements
token ws {
  [
  | <'//'> \N* \n
  | <'/*'> .*? <'*/'>
  | \s+
  ]*
}

rule c99_token {
  | <keyword>
  | <identifier>
  | <constant>
  | <string_literal>
  | <punctuator>
}

token pound { <'\#'> }

regex preprocessing_token {
  | <header_name>
  | <identifier>
  | <pp_number>
  | <character_constant>
  | <string_literal>
  | <!pound> <punctuator>
  | <universal_character_name>
  | <-[# \r\n\t]>\S* ## <-[#]-\S>\S* ##non-whitespace
}

## A.1.2 Keywords
token keyword {
  | auto      | enum      | restrict  | unsigned
  | break     | extern    | return    | void
  | case      | float     | short     | volatile
  | char      | for       | signed    | while
  | const     | goto      | sizeof    | _Bool
  | continue  | if        | static    | _Complex
  | default   | inline    | struct    | _Imaginary
  | do        | int       | switch
  | double    | long      | typedef
  | else      | register  | union

}

## A.1.3 Identifiers
#token identifier { <identifier_nondigit> [ <identifier_nondigit> | \d ]* }
token identifier { <?identifier_nondigit> [ <?identifier_nondigit> | <?digit> ]* }

token identifier_nondigit { <alpha> | <[_]> | <universal_character_name> }

## A.1.4 Universal character names
token universal_character_name {
  | <'\u'> <xdigit>**{4}
  | <'\U'> <xdigit>**{8}
}

## A.1.5 Constants
token constant {
  | <integer_constant>
  | <floating_constant>
  | <enumeration_constant>
  | <character_constant>
}

token integer_constant {
  [ <decimal_constant>
  | <octal_constant>
  | <hexadecimal_constant>
  ] <integer_sufffix>?
}

token decimal_constant     { <[1..9]> <digit>   }
#token decimal_constant     { <[1..9]> \d*       }
token octal_constant       { 0 <[0..7]>+        }
token hexadecimal_constant { 0 <[xX]> <xdigit>+ }

token integer_suffix {
  | <[uU]> [ll?|LL?]?
  | [ll?|LL?] <[uU]>?
}

token floating_constant {
  | <decimal_floating_constant>
  | <hexadecimal_floating_constant>
}

token decimal_floating_constant {
  [ <fractional_constant> <exponent_part>?
  | <digit_sequence> <exponent_part> 
  ] <floating_suffix>?
}

token hexadecimal_prefix
{
  0 <[xX]>
}

token hexadecimal_floating_constant {
  <hexadecimal_prefix> 
  [ <hexadecimal_fractional_constant>
  | <hexadecimal_digit_constant>
  ] <binary_exponent_part> <floating_suffix>?
}

token fractional_constant {
  | <digit_sequence>? \. <digit_sequence>
  | <digit_sequence> \.
}

token exponent_part {
  <[eE]> <[\+\-]>? <digit_sequence>
}

#token digit_sequence { \d+ }
token digit_sequence { <digit>+ }

token hexadecimal_fractional_constant {
  | <hexadecimal_digit_sequence>? \. <hexadecimal_digit_sequence>
  | <hexadecimal_digit_sequence> \.
}

token binary_exponent_part {
  <[pP]> <[\+\-]>? <digit_sequence>
}

token hexadecimal_digit_sequence { <xdigit>+ }

token floating_suffix { <[fFlL]> }

token enumeration_constant { <identifier> }

token character_constant { <[L]>? \' <c_char>+ \' }

token <c_char> { <-['\\\n]> | <escape_sequence> }

token escape_sequence {
  \\
  [ <['"?\\abfnrtv]>
  | <octal_digit>**{1..3}
  | x <xdigit>+
  | <universal_character_name>
  ]
}

## A.1.6 String literals
token string_literal { <[L]>? " <s_char>* " }

token s_char { <-["\\\n]> | <escape_sequence> }

## A.1.7 Punctuators
token punctuator {
  | \[        | \]        | <[(){}.]>   | <'->'>
  | <'++'>    | <'--'>    | <[&*+\-~!/%]>
  | <'<<'>    | <'>>'>    | <[<>]>
  | <'<='>    | <'>='>    | <'=='>   | <'!='>
  | <[^|]>    | <'&&'>    | <'||'>
  | <[?:;]>   | <'...'>
  | [ <[*/%+\-&^|]> | <'<<'> | <'>>'> ] <'='>
  | <[,#]>    | <'##'>
  | <'<:'>    | <':>'>    | <'<%'>   | <'%>'>   | <'%:'>   | <'%:%:'>
}

## A.1.8 Header names
token header_name {
  | \< $<name:>=<?h_char>+ \>
  | " $<name>:=<?q_char>+ "
}

token h_char { <-[\n>]> }
token q_char { <-[\n"]> }

## A.1.9 Preprocessing numbers
token pp_number { \.? \d [ \d | <identifier_nondigit> | <[eEpP]> <[\+\-]> | \. ]* }

## A.2 Phrase structure grammar
## XXX: see below

## A.2.2 Declarations
rule declaration { <declaration_specifier>+ <init_declarator_list>? ; }

rule declaration_specifier {
  | <storage_class_specifier>
  | <type_specifier>
  | <type_qualifier>
  | <function_specifier>
}

rule init_declarator_list { init_declarator [ , <init_declarator> ]* }

rule init_declarator { <declarator> [ = <initializer> ]? }

token storage_class_specifier { typedef | extern | static | auto | register }

rule type_specifier {
  | void      | char    | short     | int
  | long      | float   | double    | signed
  | unsigned  | _Bool   | _Complex  | _Imaginary
  | <struct_or_union_specifier>
  | <enum_specifier>
  | <typedef_name>
}

rule struct_or_union_specifier {
  [ $<struct>:=<'struct'> | $<union>:=<'union'> ] [ <identifier> | <identifier>? \{ <struct_declaration>+ \} ]
}

rule struct_declaration { [<type_specifier>|<type_qualifier>]+ <struct_declarator>+ ; }

rule struct_declarator { <declarator> | <declarator>? : <constant_expression> }

rule enum_specifier { enum [ <identifier>? \{ <enumerator> [ , <enumerator> ]+ [,]? \}| <identifier> ] }

rule enumerator { <enumeration_constant> [ = <constant_expression> ]? }

token type_qualifier { const | restrict  | volatile }

token function_specifier { inline }

rule declarator { <pointer>? <direct_declarator> }

rule direct_declarator {
  [ <identifier> | \( <declarator> \) ]
  [
    | \[ <assignment_expression>? \]
    | \[ \* \]
    | \( <parameter_type_list> \)
    | \( <identifier_list>? \)
  ]*
}

rule pointer { [\* <type_qualifier>* ]+ }

rule parameter_type_list { <parameter_declaration> [ , <parameter_declaration> ]* [ , <'...'>]? }

rule parameter_declaration { <declaration_specifier>+ [ <declarator> | <abstract_declatator> ]? }

rule identifier_list { <identifier> [ , <identifier> ]* }

rule type_name { <specifier_qualifier_list> <abstract_declatator>? }

rule abstract_declatator {
  <pointer>? <direct_abstract_declarator>
  |<pointer>
}

rule direct_abstract_declarator {
  [
    | \( <abstract_declatator> \) 
    | \[ <assignment_expression>? \]
    | \( <parameter_type_list> \) 
  ] 
  <direct_abstract_declarator_1>*
}

rule direct_abstract_declarator_1 {
  | \[ <assignment_expression>? \]
  | \[ * \]
  | \( <parameter_type_list> \)
}

rule typedef_name { <identifier> }

rule initializer { <assignment_expression> | \{ <initializer_list> [,]? \} }

rule initializer_list { <designation>? <initializer> [, <designation>? <initializer> ]* }

rule designation { <designator>+ = }

rule designator { 
  | \[ <constant_expression> \]
  | \. <identifier>
}

## A.2.3 Statements
rule statement {
  | <labeled_statement>
  | <compound_statement>
  | <expression_statement>
  | <selection_statement>
  | <iteration_statement>
  | <jump_statement>
}

rule labeled_statement {
  [ <identifier> \:
  | case <constant_expression> \:
  | default \:
  ] <statement>
}

rule compound_statement { \{ [ <declaration> | <statement> ]* \} }

rule expression_statement { <expression>? ; }

rule selection_statement {
  | if \( <expresssion> \) <statement> [else <statement>]?
  | switch \( <expression> \) <statement>
}

rule iteration_statement {
  | while \( <expression> \) <statement>
  | do <statement> while \( <expression> \) ;
  | for \( [ <expression>? ; <expression>? ; <expression>? | <declaration> <expression>? ; <expression>? ] \) <statement>
}

rule jump_statement {
  | goto <identifier> ;
  | continue ;
  | break ;
  | return <expression>? ;
}


## A.2.4 External definitions
rule translation_unit { [ <function_definition> | <declaration> ]+ }

rule function_definition { <declaration_specifier>+ <declarator> <declaration>* <compound_statement> }


## A.3 preprocessing directives
token wsnws {
  <?ws_minus_n>? \n <?ws>?
}

regex prereprocessing_file { <group> }

regex group { <group_line>+ }

regex group_line {
  | <if_section>
  | <control_line>
  | <source_line>? $<wsnws>:=<?wsnws>
}

regex source_line {
  <?pp_tokens>
}


rule if_section { <if_group> <elif_group>* <else_group>? <endif_line> }

token ws_minus_n
{
  [
  | <'//'> \N* \n
  | <'/*'> .*? <'*/'>
  | \t 
  | <' '>
  ## | <\s-<[\n]>
  ]*
}

regex if_group {
  [ 
  | \# <?ws>? $<ifndef>:=<'ifndef'> <?ws> <identifier>
  | \# <?ws>? $<ifdef>:=<'ifdef'> <?ws> <identifier>
  | \# <?ws>? $<if>:=<'if'> <?ws> <constant_expression>
  ] <?wsnws> <group>?
}

regex elif_group { \# <?ws> $<elif>:=<'elif'> <?ws> <constant_expression> <?wsnws> <group>? }
regex else_group { \# <?ws> $<else>:=<'else'> <?wsnws> <group>? }
regex endif_line { \# <?ws> $<endif>:=<'endif'> <?wsnws> }
regex control_line {
  | \# <?ws>? $<include>:=<'include'> <?ws_minus_n> $<value>:=<pp_tokens> <?wsnws>
  | \# <?ws>? $<define>:=<'define'> <?ws>
    [ 
      | $<define_name>:=<identifier>
      | $<define_function>:=(<identifier_p> [ <identifier_list> [, \.\.\.]? | [ \.\.\.] ]? \)) 
    ] <?ws_minus_n>? $<value>:=<pp_tokens>?
  | \# ?<ws>? $<undefine>:=<'undefine'> <?ws_minus_n> <identifier> <?wsnws>
  | \# ?<ws>? $<line>:=<'line'> <?ws_minus_n> $<value>:=<pp_tokens> <?wsnws>
  | \# ?<ws>? $<error>:=<'error'> <?ws_minus_n> $<value>:=<pp_tokens>? <?wsnws>
  | \# ?<ws>? $<pragma>:=<'pragma'> <?ws_minus_n> $<value>:=<pp_tokens>? <?wsnws>
  | \# <?wsnws>

}

token identifier_p { <identifier> \( }
regex pp_tokens { <preprocessing_token> [<?ws_minus_n> <preprocessing_token>]* }


## A.2.1 Expressions
rule primary_expression {
  | <identifier>
  | <constant>
  | <string_literal>
  | \( <expression> \)
}

rule postfix_expression {
  [ <primary_expression> 
  | \( <type_name> \) \{ <initializer_list> [\,]? \} ]

  [ <'++'>
  | <'--'>
  | \[ <expression> \]
  | \( [ <assignment_expression> [ \, <assignment_expression> ]* ]? \)
  | \. <identifier>
  | <'->'> <identifier>
  | \( <type_name> \) \{ <initializer_list> [\,]? \}
  ]*
}

rule unary_expression {
  [<'++'>|<'--'>|<'sizeof'>]? 

  [ <postfix_expression>
  | $<unary_op>:=<[&*+\-~!]> <cast_expression>
  | <'sizeof'> \( <type_name> \)
  ]
}

rule cast_expression {  [ \( <type_name> \) ]* <unary_expression> }

#proto 'term:' is precedence('22=')
#    is parsed(primary_expression)
#    is pastrule('past_term') { ... }

## postfix expressions
#proto 'postfix:++' is precedence('20=') { ... }
#proto 'postcircumfix:[]' is equiv('postfix:++') { ... }
#rule postfix_expression { <postfix_expression> \[ <expression> \] }
#proto 'postcircumfix:()' is equiv('postfix:++') { ... }
#rule postfix_expression { <postfix_expression> \( [ <assignment_expression> [\, <assignment_expression>]* ]? \) }
#proto 'infix:.' is equiv('postfix:++') { ... }
#rule postfix_expression { <postfix_expression> . <identifier> }
#proto 'infix:->' is equiv('postfix:++') { ... }
#rule postfix_expression { <postfix_expression> \-\> <identifier> }
#proto 'postfix:--' is equiv('postfix:++') { ... }
#rule postfix_expression { \( <type_name> \) \{ <initializer_list> [,]? \} }

## unary-expression
#proto 'prefix:++' is precedenc('18=') { ... }
#proto 'prefix:--' is equiv('prefix:++') { ... }
#proto 'prefix:&' is equiv('prefix:++') { ... }
#proto 'prefix:*' is equiv('prefix:++') { ... }
#proto 'prefix:+' is equiv('prefix:++') { ... }
#proto 'prefix:-' is equiv('prefix:++') { ... }
#proto 'prefix:~' is equiv('prefix:++') { ... }
#proto 'prefix:!' is equiv('prefix:++') { ... }
#proto 'prefix:sizeof' is equiv('prefix:++') { ... }
#proto 'prefix:sizeof' is equiv('prefix:++') { ... }
#rule unary_expression { sizeof  <unary_expression> }
#rule unary_expression { sizeof [\( <type_name> \) ] }

## cast-expression
## XXX: PGE doesn't have a precircumfix:() function (yet?)
#proto 'precircumfix:()' is precedence('17=') {...}
#rule cast_expression { [\( <type_name> \) ]* <unary_expression> }

proto 'term:' is precedence('22=')
    is parsed(cast_expression)
    is pastrule('cast_expression') { ... }

## multiplicative
proto 'infix:*' is precedence('16=')
    is post('mul')
    { ... }

proto 'infix:/' is equiv('infix:*')
    is post('div')
    { ... }

proto 'infix:%' is equiv('infix:*')
    is post('mod')
    { ... }

## additive
proto 'infix:+' is precedence('16=')
    is post('add')
    { ... }

proto 'infix:-' is equiv('infix:+')
    is post('sub')
    { ... }


## shift-expression
proto 'infix:<<' is precedence('15=') { ... }
proto 'infix:>>' is precedence('15=') { ... }


## relational-expression
## chaining binary
proto 'infix:<' is equiv('14=') is assoc('chain')
    is pasttype('chain')
    { ... }

proto 'infix:<=' is equiv('infix:<')
    is pasttype('chain')
    { ... }

proto 'infix:>' is equiv('infix:<')
    is pasttype('chain')
    { ... }

proto 'infix:>=' is equiv('infix:<')
    is pasttype('chain')
    { ... }

# equality-expression
proto 'infix:==' is precedence('13=') is assoc('chain')
    is pasttype('chain')
    { ... }

proto 'infix:!=' is equiv('infix:==')
    is pasttype('chain')
    { ... }


proto 'infix:&' is precedence('12=') { ... }
proto 'infix:^' is precedence('11=') { ... }
proto 'infix:|' is precedence('10=') { ... }

proto 'infix:&&' is precedence('09=')
    is pasttype('cond') 
    { ... }

proto 'infix:||' is precedence('08=')
    is pasttype('cond') 
    { ... }

## ternary
#proto 'ternary:? :' is precedence('07=') is assoc('right')
#    is pasttype('cond') 
#    is parsed('conditional_expression')
#    { ... }

rule operator_precedence_parser { {{ 
  .local pmc optable
  .local pmc match_result
  #optable = get_hll_namespace ['Cardinal'; 'Grammar']
  optable = get_root_global [ 'parrot'; 'C99'], '$optable'
  match_result = optable."parse"(match)
  .return (match_result)
}} }

rule conditional_expression { <operator_precedence_parser> [ \? <expression> : <operator_precedence_parser> ]* }

rule assignment_expression { [ <unary_expression> <assignment_operator> ]* <constant_expression> }

token assignment_operator {
  | <'*='>
  | <'/='>
  | <'%='>
  | <'+='>
  | <'-='>
  | <'<<='>
  | <'>>='>
  | <'&='>
  | <'^='>
  | <'|='>
}

rule expression { <assignment_expression> [, <assignment_expression> ] }
rule constant_expression { <conditional_expression> }

## assignment
#proto 'infix:=' is precedence('06=') is assoc('right')
#    is parsed('assignment_expression')
#    is pasttype('assign') 
#    { ... }

#proto 'infix:*=' is equiv('infix:=') is parsed('assignment_expression') { ... }
#proto 'infix:/=' is equiv('infix:=') is parsed('assignment_expression') { ... }
#proto 'infix:%=' is equiv('infix:=') is parsed('assignment_expression') { ... }
#proto 'infix:+=' is equiv('infix:=') is parsed('assignment_expression') { ... }
#proto 'infix:-=' is equiv('infix:=') is parsed('assignment_expression') { ... }
#proto 'infix:<<=' is equiv('infix:=') is parsed('assignment_expression') { ... }
#proto 'infix:>>=' is equiv('infix:=') is parsed('assignment_expression') { ... }
#proto 'infix:&=' is equiv('infix:=') is parsed('assignment_expression') { ... }
#proto 'infix:^=' is equiv('infix:=') is parsed('assignment_expression') { ... }
#proto 'infix:|=' is equiv('infix:=') is parsed('assignment_expression') { ... }
