1{
2#include <stdio.h>
3#include <string.h>
4
5char *reserved_words[] = { "auto", "break", "case", "char", "const",
6  "continue", "default", "do", "double", "else", "enum", "extern", "float",
7  "for", "goto", "if", "int", "long", "register", "return", "short", "signed",
8  "sizeof", "static", "struct", "typedef", "union", "unsigned", "void",
9  "volatile", "while", NULL};
10
11static int is_one_of(char *s, char *e, char **list) {
12  while (*list) {
13    if (strlen(*list) == e-s && !strncmp(s, *list, e-s)) return 1;
14    list++;
15  }
16  return 0;
17}
18}
19
20program: statements ;
21
22statements: statement*;
23statements_expr: statements expression?;
24statement: function_definition
25	   | declaration ';'
26	   | expression ';'
27	   | '{' statements_expr '}';
28
29function_definition
30  : declaration_specifiers declarator '{' statements_expr '}' ;
31
32declaration : declaration_specifiers init_declarator_list? ;
33
34init_declarator_list :	init_declarator (',' init_declarator)* ;
35init_declarator : declarator ('=' initializer)? ;
36
37declaration_specifiers
38  : (storage_class_specifier | type_specifier | type_qualifier)+ ;
39
40storage_class_specifier: 'auto' | 'register' | 'static' | 'extern' | 'typedef';
41
42type_specifier: 'void' | 'char' | 'short' | 'int' | 'long' | 'float'
43  | 'double' | 'signed' | 'unsigned' | struct_or_union_specifier
44  | enum_specifier | typeID;
45
46type_qualifier: 'const' | 'volatile';
47
48typeID: identifier [
49/*
50  D_Sym *s = find_sym(${scope}, $n0.start, $n0.end);
51  if (!s) ${reject};
52  if (!s->user.is_typename) ${reject};
53*/
54];
55
56struct_or_union_specifier: ('struct' | 'union')
57  ( identifier | identifier? '{' struct_declaration+ '}') ;
58
59struct_declaration : specifier_qualifier_list struct_declarator_list ';' ;
60
61specifier_qualifier_list : (type_specifier | type_qualifier)+ ;
62
63struct_declarator_list : struct_declarator (',' struct_declarator)* ;
64
65struct_declarator : declarator | declarator? ':' constant;
66
67enum_specifier : 'enum'
68  ( identifier ('{' enumerator_list '}')?
69  | '{' enumerator_list '}') ;
70enumerator_list : enumerator (',' enumerator)* ;
71enumerator : identifier ('=' expression)?;
72
73declarator : '*' type_qualifier* declarator | direct_declarator ;
74
75direct_declarator : identifier declarator_suffix*
76                  | '(' declarator ')' declarator_suffix* ;
77
78declarator_suffix : '[' expression? ']' | '(' parameter_list? ')';
79
80parameter_list : parameter_declaration_list ( "," "..." )? ;
81
82parameter_declaration
83  : declaration_specifiers (declarator? | abstract_declarator) ;
84
85initializer : expr | '{' initializer (',' initializer)* '}' ;
86
87type_name : specifier_qualifier_list abstract_declarator ;
88
89abstract_declarator
90  : '*' type_qualifier* abstract_declarator
91  | '(' abstract_declarator ')' abstract_declarator_suffix+
92  | ('[' expression? ']')+
93  | ;
94
95abstract_declarator_suffix
96  : '[' expression? ']'
97  | '('  parameter_declaration_list? ')' ;
98
99parameter_declaration_list
100  : parameter_declaration ( ',' parameter_declaration )* ;
101
102expression
103  : expr
104  | expr ',' expr $left 6700
105  /* labels */
106  | identifier ':' expression $right 6600
107  | 'case' expression ':' expression $right 6500
108  | 'default' ':' expression $right 6500
109  /* conditionals */
110  | 'if' '(' statements_expr ')' expression $right 6000
111  | 'if' '(' statements_expr ')' statement 'else' expression $right 6100
112  | 'switch' '(' statements_expr ')' expression $right 6200
113  /* loops */
114  | 'while' '(' statements_expr ')' expression $right 6300
115  | 'do' statement 'while' expression $right 6400
116  | 'for' '(' expression (';' expression (';' expression)?)? ')'
117          expression $right 6500
118  /* jump */
119  | 'goto' expression?
120  | 'continue' expression?
121  | 'break' expression?
122  | 'return' expression?
123  | expression juxiposition expression
124  ;
125
126juxiposition: $binary_op_left 5000;
127
128expr
129  : identifier
130  | constant
131  | strings
132  | '(' statements_expr')'
133  | '[' statements_expr ']'
134  | '{' statements_expr '}'
135  | expr '?' expression ':' expr $right 8600
136  /* post operators */
137  | expr '--' $left 9900
138  | expr '++' $left 9900
139  | expr '(' statements_expr ')' $left 9900
140  | expr '[' statements_expr ']' $left 9900
141  | expr '{' statements_expr '}' $left 9900
142  /* pre operators */
143  | 'sizeof' expression $right 9900
144  | '-' expr $right 9800
145  | '+' expr $right 9800
146  | '~' expr $right 9800
147  | '!' expr $right 9800
148  | '*' expr $right 9800
149  | '&' expr $right 9800
150  | '--' expr $right 9800
151  | '++' expr $right 9800
152  | '(' type_name ')' expr $right 9800
153  /* binary operators */
154  | expr '->' expr $left 9900
155  | expr '.' expr $left 9900
156  | expr '*' expr $left 9600
157  | expr '/' expr $left 9600
158  | expr '%' expr $left 9600
159  | expr '+' expr $left 9500
160  | expr '-' expr $left 9500
161  | expr '<<' expr $left 9400
162  | expr '>>' expr $left 9400
163  | expr '<' expr $left 9300
164  | expr '<=' expr $left 9300
165  | expr '>' expr $left 9300
166  | expr '>=' expr $left 9300
167  | expr '==' expr $left 9200
168  | expr '!=' expr $left 9200
169  | expr '&' expr $left 9100
170  | expr '^' expr $left 9000
171  | expr '|' expr $left 8900
172  | expr '&&' expr $left 8800
173  | expr '||' expr $left 8700
174  | expr '=' expr $left 8500
175  | expr '*=' expr $left 8500
176  | expr '/=' expr $left 8500
177  | expr '%=' expr $left 8500
178  | expr '+=' expr $left 8500
179  | expr '-=' expr $left 8500
180  | expr '<<=' expr $left 8500
181  | expr '>>=' expr $left 8500
182  | expr '&=' expr $left 8500
183  | expr '|=' expr $left 8500
184  | expr '^=' expr $left 8500
185  | expr application expr
186  ;
187
188application: $binary_op_left 7000;
189
190strings: string | strings string $left 10000;
191constant : decimalint | hexint | octalint | character | float1 | float2;
192character: "'[^']*'";
193string: "\"[^\"]*\"";
194decimalint: "[1-9][0-9]*[uUlL]?" $term -1;
195hexint: "(0x|0X)[0-9a-fA-F]+[uUlL]?" $term -2;
196octalint: "0[0-7]*[uUlL]?" $term -3;
197float1: "([0-9]+.[0-9]*|[0-9]*.[0-9]+)([eE][\-\+]?[0-9]+)?[fFlL]?" $term -4;
198float2: "[0-9]+[eE][\-\+]?[0-9]+[fFlL]?" $term -5;
199identifier: "[a-zA-Z_][a-zA-Z0-9_]*" $term -6 [
200  if (is_one_of($n0.start, $n0.end, reserved_words))
201    ${reject};
202];
203