2 # Copyright (C) 2008, The Perl Foundation.
6 This is the grammar for C99 written as a sequence of Perl 6 rules.
14 grammar C99::Grammar is PCT::Grammar;
16 ## A.2.4 External definitions
21 <external_declaration>+
22 [ $ || <.panic: Syntax error> ]
26 rule external_declaration {
27 | <declaration> {*} #= declaration
28 | <function_definition> {*} #= function_definition
31 rule function_definition {
32 <declaration_specifiers>
44 <declaration_specifiers>
45 [ <init_declarator> [',' <init_declarator>]* ]?
50 rule declaration_specifiers {
52 | <storage_class_specifier>
54 | <function_specifier>
58 rule function_specifier {
62 rule init_declarator {
63 <declarator> ['=' <initializer>]?
67 rule storage_class_specifier {
77 | <struct_or_union_specifier>
97 rule struct_or_union_specifier {
98 $<type>=['struct'|'union']
100 | <struct_or_union_definition>
105 rule struct_or_union_definition {
106 <identifier>? '{' <struct_declaration>+ '}'
109 rule pre_declaration {
113 rule struct_declaration {
114 <specifier_qualifier_list> <struct_declarator_list>* ';'
117 rule specifier_qualifier_list {
124 rule struct_declarator_list {
125 <struct_declarator> [',' <struct_declarator>]*
128 rule struct_declarator {
129 | <declarator>? ':' <constant_expression>
133 rule enum_specifier {
134 | 'enum' <identifier>? '{' <enumerator_list> [',']? '}'
135 | 'enum' <identifier>
138 rule enumerator_list {
139 <enumerator> [',' <enumerator>]*
143 <enumeration_constant> ['=' <constant_expression>]?
146 rule type_qualifier {
147 $<qualifier>=['const'|'restrict'|'volatile']
156 rule direct_declarator {
162 rule declarator_prefix {
163 | '(' <declarator> ')' {*} #= declarator
164 | <identifier> {*} #= identifier
167 rule declarator_suffix {
168 | '(' <parameter_type_list> ')' {*} #= parameter_type_list
169 | '(' <identifier_list>? ')' {*} #= identifier_list ## old-style C parameter declarations
170 | '[' <assignment_expression>? ']'
175 '*' <type_qualifier>* ['*']?
178 rule parameter_type_list {
179 <parameter_list> [$<vararg>=[',' '...']]?
183 rule parameter_list {
184 <parameter_declaration> [',' <parameter_declaration>]*
188 rule parameter_declaration {
189 <declaration_specifiers>
191 | <declarator> {*} #= declarator
192 | <abstract_declarator>? {*} #= abstract_declarator
196 rule identifier_list {
197 <identifier> [',' <identifier>]*
201 <specifier_qualifier_list> <abstract_declarator>?
204 rule abstract_declarator {
206 | ['*']? <direct_abstract_declarator>
209 rule direct_abstract_declarator {
211 | '(' <abstract_declatator> ')'
212 | '[' <assignment_expression>? ']'
213 | '(' <parameter_type_list> ')'
215 <direct_abstract_declarator_1>*
218 rule direct_abstract_declarator_1 {
219 | '[' <assignment_expression>? ']'
221 | '(' <parameter_type_list> ')'
226 ## a typedef name can be a return type specifier. This is ambiguous, because
227 ## the parser doesn't know if it's a return type thingie or the name of the
228 ## function. Therefore, typedef'd names must be stored in a %hash, so that
229 ## this rule is not calling <identifier>, but inspecting the registered
230 ## typedef'd names. For now, specify 'SOME_TYPEDEF_NAME' as the only typedef'd name.
237 | <assignment_expression>
238 | '{' <initializer_list> [',']? '}'
241 rule initializer_list {
242 <initializer_item> [',' <initializer_item>]*
245 rule initializer_item {
246 <designation>? <initializer>
254 | '[' <constant_expression> ']'
263 | <labeled_statement>
264 | <compound_statement> {*} #= compound_statement
265 | <expression_statement> {*} #= expression_statement
266 | <if_statement> {*} #= if_statement
268 | <while_statement> {*} #= while_statement
269 | <do_while_statement> {*} #= do_while_statement
270 | <for1_statement> {*} #= for1_statement
271 | <for2_statement> {*} #= for2_statement
272 | <jump_statement> {*} #= jump_statement
275 rule labeled_statement {
276 | <identifier> ':' <statement>
277 | 'case' <constant_expression> ':' <statement>
278 | 'default' ':' <statement>
281 rule compound_statement {
282 '{' <block_item>* '}'
287 | <declaration> {*} #= declaration
288 | <statement> {*} #= statement
291 rule expression_statement {
297 'if' '(' <expression> ')' <statement> ['else' $<else>=<statement>]?
301 rule switch_statement {
302 'switch' '(' <expression> ')' <statement>
305 rule while_statement {
306 'while' '(' <expression> ')' <statement>
310 rule do_while_statement {
311 'do' <statement> 'while' '(' <expression> ')' ';'
315 rule for1_statement {
316 'for' '(' [$<init>=<expression>]? ';' [$<cond>=<expression>]? ';' [$<step>=<expression>]? ')'
321 rule for2_statement {
322 'for' '(' <declaration> [$<cond>=<expression>]? ';' [$<step>=<expression>]? ')' <statement>
326 rule jump_statement {
327 | 'goto' <identifier> ';' {*} #= goto
328 | 'continue' ';' {*} #= continue
329 | 'break' ';' {*} #= break
330 | 'return' <expression>? ';' {*} #= return
334 ## A.1.1 Lexical elements
340 ## | <c_string_literal>
344 regex preprocessing_token {
348 | <character_constant>
350 | <!pound> <punctuator>
351 | <universal_character_name>
352 | <-[# \r\n\t]>\S* ## <-[#]-\S>\S* ##non-whitespace
358 [ auto | enum | restrict | unsigned
359 | break | extern | return | void
360 | case | float | short | volatile
361 | char | for | signed | while
362 | const | goto | sizeof | _Bool
363 | continue | if | static | _Complex
364 | default | inline | struct | _Imaginary
366 | double | long | typedef
367 | else | register | union ]>>
371 token reserved_word {
378 <identifier_nondigit> [ <identifier_nondigit> | <digit> ]*
382 token identifier_nondigit {
383 <alpha> | <[_]> | <universal_character_name>
386 ## A.1.4 Universal character names
388 token universal_character_name {
397 | <floating_constant> {*} #= floating_constant
398 | <integer_constant> {*} #= integer_constant
399 | <enumeration_constant> {*} #= enumeration_constant
400 | <character_constant> {*} #= character_constant
403 token integer_constant {
406 | <hexadecimal_constant>
412 token decimal_constant {
416 token octal_constant {
420 token hexadecimal_constant {
424 token integer_suffix {
429 token floating_constant {
431 | <decimal_floating_constant>
432 | <hexadecimal_floating_constant>
437 token decimal_floating_constant {
439 | <fractional_constant> <exponent_part>?
440 | <digit_sequence> <exponent_part>
445 token hexadecimal_prefix {
449 token hexadecimal_floating_constant {
452 | <hexadecimal_fractional_constant>
453 | <hexadecimal_digit_constant>
455 <binary_exponent_part> <floating_suffix>?
458 token fractional_constant {
459 | <digit_sequence>? \. <digit_sequence>
460 | <digit_sequence> \.
463 token exponent_part {
464 <[eE]> ['+'|'-']? <digit_sequence>
467 token digit_sequence { <digit>+ }
469 token hexadecimal_fractional_constant {
470 | <hexadecimal_digit_sequence>? \. <hexadecimal_digit_sequence>
471 | <hexadecimal_digit_sequence> \.
474 token binary_exponent_part {
475 <[pP]> ['+'|'-']? <digit_sequence>
478 token hexadecimal_digit_sequence { <xdigit>+ }
480 token floating_suffix { <[fFlL]> }
482 token enumeration_constant { <identifier> }
484 token character_constant { [L]? \' <c_char>+ \' }
486 token <c_char> { <-['\\\n]> | <escape_sequence> }
488 token escape_sequence {
491 | <octal_digit>**{1..3}
493 | <universal_character_name>
497 ## A.1.6 String literals
498 token c_string_literal {
499 [L]? <string_literal: '"'>
505 token s_char { <-["\\\n]> | <escape_sequence> }
508 ## A.2 Phrase structure grammar
514 rule constant_expression {
515 <conditional_expression>
520 <assignment_expression> [',' <assignment_expression>]*
524 rule assignment_expression {
525 [<unary_expression> <assign_op>]* <conditional_expression>
529 rule assign_op { '='|'*='|'/='|'%='|'+='|'-='|'<<='|'>>='|'&='|'^='|'|=' }
531 rule conditional_expression {
532 <logical_expression> ['?' <expression> ':' <conditional_expression>]?
536 rule logical_expression is optable { ... }
538 proto 'infix:||' is precedence('1') { ... }
540 proto 'infix:&&' is tighter('infix:||') { ... }
542 proto 'infix:|' is tighter('infix:&&') { ... }
544 proto 'infix:^' is tighter('infix:|') { ... }
546 proto 'infix:&' is tighter('infix:^') { ... }
548 proto 'infix:==' is tighter('infix:&') { ... }
549 proto 'infix:!=' is equal('infix:==') { ... }
551 proto 'infix:<' is tighter('infix:==') { ... }
552 proto 'infix:>' is equal('infix:<') { ... }
553 proto 'infix:>=' is equal('infix:<') { ... }
554 proto 'infix:<=' is equal('infix:<') { ... }
556 proto 'infix:<<' is tighter('infix:==') { ... }
557 proto 'infix:>>' is equal('infix:<<') { ... }
559 proto 'infix:+' is tighter('infix:<<') is pirop('n_add') { ... }
560 proto 'infix:-' is equal('infix:+') is pirop('n_sub') { ... }
562 proto 'infix:*' is tighter('infix:+') is pirop('n_mul') { ... }
563 proto 'infix:/' is equal('infix:*') is pirop('n_div') { ... }
564 proto 'infix:%' is equal('infix:*') is pirop('n_mod') { ... }
566 proto 'term:' is tighter('infix:*')
567 is parsed(&cast_expression) { ... }
570 rule postfix_expression_prefix {
571 | <primary_expression> {*} #= primary_expression
572 | '(' <type_name> ')' '{' <initializer_list> [',']? '}' {*} #= type_name
575 rule postfix_expression {
576 <postfix_expression_prefix>
577 <postfix_expression_suffix>*
581 rule postfix_expression_suffix {
582 | <index> {*} #= index
583 | <arguments> {*} #= arguments
584 | <direct_field> {*} #= direct_field
585 | <indirect_field> {*} #= indirect_field
586 | <inc_or_dec> {*} #= inc_or_dec
604 rule indirect_field {
610 '(' <argument_expression_list>? ')'
614 rule argument_expression_list {
615 <assignment_expression> [',' <assignment_expression>]*
619 rule unary_expression {
620 | <postfix_expression> {*} #= postfix_expression
621 | <prefix_expression> {*} #= prefix_expression
622 | <unary_operator> <cast_expression>
623 | 'sizeof' <unary_expression>
624 | 'sizeof' '(' <type_name> ')'
627 rule prefix_expression {
628 $<op>=['++'|'--'] <unary_expression>
632 rule unary_operator {
633 '&' | '*' | '+' | '-' | '~' | '!'
636 rule cast_expression {
637 ['(' <type_name> ')']* <unary_expression>
641 rule primary_expression {
642 | <identifier> {*} #= identifier
643 | <constant> {*} #= constant
644 | <c_string_literal> {*} #= c_string_literal
645 | '(' <expression> ')' {*} #= expression
661 | \[ | \] | <[(){}.]> | '->'
662 | '++' | '--' | <[&*+\-~!/%]>
663 | '<<' | '>>' | '<' | '>'
664 | '<=' | '>=' | '==' | '!='
665 | <[^|]> | '&&' | '||'
667 | <[*/%+\-&^|]> | '<<' | '>>' | '='
669 | '<:' | ':>' | '<%' | '%>' | '%:' | '%:%:'
673 ## A.3 Preprocessing directives
676 rule pre_processing_file {
685 | <pp_tokens>? <newline>
691 <if_group> <elif_group>* <else_group>? <endif_line>
695 | '#' 'if' <constant_expression> <newline> <group>?
696 | '#' 'ifdef' <identifier> <newline> <group>?
697 | '#' 'ifndef' <identifier> <newline> <group>?
701 '#' 'elif' <constant_expression> <newline> <group>?
705 '#' 'else' <newline> <group>?
709 '#' 'endif' <newline>
713 | '#' 'include' <pp_tokens> <newline>
714 | '#' 'define' <identifier> <replacement_list> <newline>
715 | '#' 'define' <identifier> <lparen> <identifier_list>? ')' <replacement_list> <newline>
716 | '#' 'define' <identifier> <lparen> '...' ')' <replacement_list> <newline>
717 | '#' 'define' <identifier> <lparen> <identifier_list> ',' '...' ')' <replacement_list> <newline>
718 | '#' 'undef' <identifier> <newline>
719 | '#' 'line' <pp_tokens> <newline>
720 | '#' 'error' <pp_tokens>? <newline>
721 | '#' 'pragma' <pp_tokens>? <newline>
726 <preprocessing_token>+
729 rule preprocessing_token {
733 | <character_constant>
739 ['.']? <digit> <pp_number_suffix>*
742 rule pp_number_suffix {
744 | <identifier_nondigit>
749 rule replacement_list {
761 ## A.1.8 Header names
767 token h_char { <-[\n>]> }
768 token q_char { <-[\n"]> }