# $Id: /mirror/trunk/languages/c99/src/cpp/src/parser/grammar.pg 27596 2008-05-17T16:09:58.605412Z tewk  $
# Copyright (C) 2008, The Perl Foundation.

=begin overview

This is the grammar for C99 written as a sequence of Perl 6 rules.


taken from n869.pdf
google for n869.pdf

=end overview

grammar C99::CPP::Grammar is PCT::Grammar;

token ws { 
    | \h* 
    | <multilinecomment>
}

token TOP {
    ^
    <pre_processing_file>
    [ $ || <.panic: Syntax error> ]
    {*}
}

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

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

token decimal_constant {
    <[1..9]> <digit>*
}

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 { <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 c_string_literal {
    [L]? <string_literal: '"'>
    {*}
}

##\" <s_char>* \"

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


## A.2 Phrase structure grammar
##

## A.2.1 Expressions
##

rule expression {
    <constant_expression>
    {*}
}

rule constant_expression {
    <conditional_expression>
    {*}
}

rule assign_op { '='|'*='|'/='|'%='|'+='|'-='|'<<='|'>>='|'&='|'^='|'|=' }

rule conditional_expression {
    <logical_expression> ['?' <conditional_expression> ':' <conditional_expression>]?
    {*}
}

rule logical_expression is optable { ... }

proto 'infix:||' is precedence('1') { ... }

proto 'infix:&&' is tighter('infix:||') { ... }

proto 'infix:|' is tighter('infix:&&') { ... }

proto 'infix:^' is tighter('infix:|') { ... }

proto 'infix:&' is tighter('infix:^') { ... }

proto 'infix:==' is tighter('infix:&') { ... }
proto 'infix:!=' is equal('infix:==') { ... }

proto 'infix:<' is tighter('infix:==') { ... }
proto 'infix:>' is equal('infix:<') { ... }
proto 'infix:>=' is equal('infix:<') { ... }
proto 'infix:<=' is equal('infix:<') { ... }

proto 'infix:<<' is tighter('infix:==') { ... }
proto 'infix:>>' is equal('infix:<<') { ... }

proto 'infix:+' is tighter('infix:<<') is pirop('n_add') { ... }
proto 'infix:-' is equal('infix:+') is pirop('n_sub') { ... }

proto 'infix:*' is tighter('infix:+') is pirop('n_mul') { ... }
proto 'infix:/' is equal('infix:*') is pirop('n_div') { ... }
proto 'infix:%' is equal('infix:*') is pirop('n_mod') { ... }

proto 'term:' is tighter('infix:*')
              is parsed(&cast_expression) { ... }


rule postfix_expression_prefix {
    | <primary_expression> {*}                                  #= primary_expression
    | '(' <type_name> ')' '{' <initializer_list> [',']? '}' {*} #= type_name
}

rule postfix_expression {
    <postfix_expression_prefix>
    <postfix_expression_suffix>*
    {*}
}

rule postfix_expression_suffix {
    | <index> {*}                           #= index
    | <arguments>  {*}                      #= arguments
    | <direct_field> {*}                    #= direct_field
    | <indirect_field> {*}                  #= indirect_field
    | <inc_or_dec> {*}                      #= inc_or_dec
}

rule inc_or_dec {
    $<op>=['++'|'--']
    {*}
}

rule index {
    '[' <expression> ']'
    {*}
}

rule direct_field {
    '.' <identifier>
    {*}
}

rule indirect_field {
    '->' <identifier>
    {*}
}

rule arguments {
    '(' <argument_expression_list>? ')'
    {*}
}

rule argument_expression_list {
    <assignment_expression> [',' <assignment_expression>]*
    {*}
}

rule unary_expression {
    | <postfix_expression> {*}              #= postfix_expression
    | <prefix_expression> {*}               #= prefix_expression
    | <unary_operator> <cast_expression>
    | 'sizeof' <unary_expression>
    | 'sizeof' '(' <type_name> ')'
}

rule prefix_expression {
    $<op>=['++'|'--'] <unary_expression>
    {*}
}

rule unary_operator {
    '&' | '*' | '+' | '-' | '~' | '!'
}

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

rule primary_expression {
    | <identifier> {*}             #= identifier
    | <constant> {*}               #= constant
    | <c_string_literal> {*}       #= c_string_literal
    | '(' <expression> ')' {*}     #= expression
}

token pound { '#' }
token begincomment { '/*' }

token multilinecomment { '/*' .*? '*/' }


regex preprocessing_token {
#  | <multilinecomment>
  | <header_name>
  | <identifier>
  | <pp_number>
  | <character_constant>
  | '"' <string_literal: '"'> '"'
  | <!pound> <!begincomment> <punctuator>
  | <universal_character_name>
  | <!begincomment><-[# \t\r\n]>\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     ]>>
}

token reserved_word {
    <keyword>
}

token identifier {
    <!reserved_word>
    <identifier_nondigit> [ <identifier_nondigit> | <digit> ]*
    {*}
}

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

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

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

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


## A.1.7 Punctuators
##

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

## A.3 Preprocessing directives
##

rule pre_processing_file {
    <group>?
}

rule group {
    <group_part>+
}

rule group_part {
    | <pp_tokens>? <newline>
    | <if_section>
    | <control_line>
}

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

rule if_group {
    | '#' 'if' <constant_expression> <newline> <group>?
    | '#' 'ifdef' <identifier> <newline> <group>?
    | '#' 'ifndef' <identifier> <newline> <group>?
}

rule elif_group {
    '#' 'elif' <constant_expression> <newline> <group>?
}

rule else_group {
    '#' 'else' <newline> <group>?
}

rule endif_line {
    '#' 'endif' <newline>
}

rule control_line {
    | '#' 'include' <pp_tokens> <newline>
    | '#' 'define' <identifier> <replacement_list> <newline>
    | '#' 'define' <identifier> <lparen> <identifier_list>? ')' <replacement_list> <newline>
    | '#' 'define' <identifier> <lparen> '...' ')' <replacement_list> <newline>
    | '#' 'define' <identifier> <lparen> <identifier_list> ',' '...' ')' <replacement_list> <newline>
    | '#' 'undef' <identifier> <newline>
    | '#' 'line' <pp_tokens> <newline>
    | '#' 'error' <pp_tokens>? <newline>
    | '#' 'pragma' <pp_tokens>? <newline>
    | '#' <newline>
}

rule pp_tokens { [ <preprocessing_token> ]+ }

token pp_number {
    ['.']? <digit> <pp_number_suffix>*
}

token pp_number_suffix {
    | '.'
    | <identifier_nondigit>
    | <digit>
    | <[eEpP]> ['+'|'-']
}

rule replacement_list {
  <pp_tokens>?
}

token lparen { '(' }

token newline { \n }

## A.1.8 Header names
token header_name {
  | \< <h_char>+ \>
  | \" <q_char>+ \"
}

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