1 /*
2 * demonstrate enhancements derived from btyacc:
3 * backtracking to resolve conflicts
4 * semantic disambiguation via []-actions invoking YYVALID & YYERROR
5 * %locations
6 * @$ & @N to refer to lhs & rhs symbol location
7 * %destructor
8 * syntactic suger for inherited attributes
9 * extension to %type to define inherited attribute type
10 */
11
12 %LOCATIONS
13
14 %{
15 /* dummy types just for compile check */
16 typedef int Code;
17 typedef int Decl_List;
18 typedef int Expr;
19 typedef int Expr_List;
20 typedef int Scope;
21 typedef int Type;
22 enum Operator { ADD, SUB, MUL, MOD, DIV, DEREF };
23
24 typedef unsigned char bool;
25 typedef struct Decl {
26 Scope *scope;
27 Type *type;
28 bool (*istype)(void);
29 } Decl;
30
31 #include "btyacc_demo.tab.h"
32 #include <stdlib.h>
33 #include <stdio.h>
34 %}
35
36 %union {
37 Scope *scope;
38 Expr *expr;
39 Expr_List *elist;
40 Type *type;
41 Decl *decl;
42 Decl_List *dlist;
43 Code *code;
44 char *id;
45 };
46
47 %left '+' '-'
48 %left '*' '/' '%'
49 %nonassoc PREFIX
50 %nonassoc POSTFIX '(' '[' '.'
51
52 %token <id> ID
53 %token <expr> CONSTANT
54 %token EXTERN REGISTER STATIC CONST VOLATILE IF THEN ELSE CLCL
55
56 %type <expr> expr(<scope>)
57 %type decl(<scope>) declarator_list(<scope>, <type>)
58 decl_list(<scope>)
59 %type <code> statement(<scope>) statement_list(<scope>)
60 block_statement(<scope>)
61 %type <decl> declarator(<scope>, <type>) formal_arg(<scope>)
62 %type <type> decl_specs(<scope>) decl_spec(<scope>) typename(<scope>)
63 cv_quals cv_qual
64 %type <scope> opt_scope(<scope>)
65 %type <dlist> formal_arg_list(<scope>) nonempty_formal_arg_list(<scope>)
66
67 %destructor { // 'msg' is a 'char *' indicating the context of destructor invocation
68 printf("%s accessed by symbol \"decl\" (case s.b. 273) @ position[%d,%d..%d,%d]\n",
69 msg,
70 @$.first_line, @$.first_column,
71 @$.last_line, @$.last_column);
72 free($<decl>$->scope); free($<decl>$->type); } decl
73 %destructor { printf("%s accessed by symbol with type <decl> (case s.b. 279 & 280) @ position[%d,%d..%d,%d]\n",
74 msg,
75 @$.first_line, @$.first_column,
76 @$.last_line, @$.last_column);
77 free($$); } <decl>
78 %destructor { printf("%s accessed by symbol of any type other than <decl> @ position[%d,%d..%d,%d]\n",
79 msg,
80 @$.first_line, @$.first_column,
81 @$.last_line, @$.last_column);
82 free($$); } <*>
83 %destructor { printf("%s accessed by symbol with no type @ position[%d,%d..%d,%d]\n",
84 msg,
85 @$.first_line, @$.first_column,
86 @$.last_line, @$.last_column);
87 /* in this example, we don't know what to do here */ } <>
88
89 %start input
90
91 %%
92
93 opt_scope($e): [ $$ = $e; ]
94 | CLCL [ $$ = global_scope; ]
95 | opt_scope ID CLCL [ Decl *d = lookup($1, $2);
96 if (!d || !d->scope) YYERROR;
97 $$ = d->scope; ]
98 ;
99
100 typename($e): opt_scope ID
101 [ Decl *d = lookup($1, $2);
102 if (d == NULL || d->istype() == 0) YYERROR;
103 $$ = d->type; ]
104 ;
105
106 input: decl_list(global_scope = new_scope(0)) ;
107 decl_list($e): | decl_list decl($e) ;
108 decl($e):
109 decl_specs declarator_list($e,$1) ';' [YYVALID;]
110 | decl_specs declarator($e,$1) block_statement(start_fn_def($e, $2))
111 { /* demonstrate use of @$ & @N, although this is just the
112 default computation and so is not necessary */
113 @$.first_line = @1.first_line;
114 @$.first_column = @1.first_column;
115 @$.last_line = @3.last_line;
116 @$.last_column = @3.last_column;
117 finish_fn_def($2, $3); }
118 ;
119
120 decl_specs($e):
121 decl_spec [ $$ = $1; ]
122 | decl_specs decl_spec($e) [ $$ = type_combine($1, $2); ]
123 ;
124
125 cv_quals: [ $$ = 0; ]
126 | cv_quals cv_qual [ $$ = type_combine($1, $2); ]
127 ;
128
129 decl_spec($e):
130 cv_qual [ $$ = $1; ]
131 | typename [ $$ = $1; ]
132 | EXTERN [ $$ = bare_extern(); ]
133 | REGISTER [ $$ = bare_register(); ]
134 | STATIC [ $$ = bare_static(); ]
135 ;
136
137 cv_qual:
138 CONST [ $$ = bare_const(); ]
139 | VOLATILE [ $$ = bare_volatile(); ]
140 ;
141
142 declarator_list($e, $t):
143 declarator_list ',' declarator($e, $t)
144 | declarator
145 ;
146
declarator($e,$t)147 declarator($e, $t):
148 /* empty */ [ if (!$t) YYERROR; ]
149 { $$ = declare($e, 0, $t); }
150 | ID { $$ = declare($e, $1, $t); }
151 | '(' declarator($e, $t) ')' { $$ = $2; }
152 | '*' cv_quals declarator($e, $t) %prec PREFIX
153 { $$ = make_pointer($3, $2); }
154 | declarator '[' expr($e) ']'
155 { $$ = make_array($1->type, $3); }
156 | declarator '(' formal_arg_list($e) ')' cv_quals
157 { $$ = build_function($1, $3, $5); }
158 ;
159
formal_arg_list($e)160 formal_arg_list($e): { $$ = 0; }
161 | nonempty_formal_arg_list { $$ = $1; }
162 ;
163 nonempty_formal_arg_list($e):
164 nonempty_formal_arg_list ',' formal_arg($e) { $$ = append_dlist($1, $3); }
165 | formal_arg { $$ = build_dlist($1); }
166 ;
formal_arg($e)167 formal_arg($e):
168 decl_specs declarator($e,$1) { $$ = $2; }
169 ;
170
171 expr($e):
172 expr '+' expr($e) { $$ = build_expr($1, ADD, $3); }
173 | expr '-' expr($e) { $$ = build_expr($1, SUB, $3); }
174 | expr '*' expr($e) { $$ = build_expr($1, MUL, $3); }
175 | expr '%' expr($e) { $$ = build_expr($1, MOD, $3); }
176 | expr '/' expr($e) { $$ = build_expr($1, DIV, $3); }
177 | '*' expr($e) %prec PREFIX { $$ = build_expr(0, DEREF, $2); }
178 | ID { $$ = var_expr($e, $1); }
179 | CONSTANT { $$ = $1; }
180 ;
181
statement($e)182 statement($e):
183 decl { $$ = 0; }
184 | expr($e) ';' [YYVALID;] { $$ = build_expr_code($1); }
185 | IF '(' expr($e) ')' THEN statement($e) ELSE statement($e) [YYVALID;]
186 { $$ = build_if($3, $6, $8); }
187 | IF '(' expr($e) ')' THEN statement($e) [YYVALID;]
188 { $$ = build_if($3, $6, 0); }
189 | block_statement(new_scope($e)) [YYVALID;]{ $$ = $1; }
190 ;
191
statement_list($e)192 statement_list($e): { $$ = 0; }
193 | statement_list statement($e) { $$ = code_append($1, $2); }
194 ;
195
196 block_statement($e):
197 '{' statement_list($e) '}' { $$ = $2; }
198 ;
199 %%
200
201 extern int YYLEX_DECL();
202 extern void YYERROR_DECL();
203
204 extern Scope *global_scope;
205
206 extern Decl * lookup(Scope *scope, char *id);
207 extern Scope * new_scope(Scope *outer_scope);
208 extern Scope * start_fn_def(Scope *scope, Decl *fn_decl);
209 extern void finish_fn_def(Decl *fn_decl, Code *block);
210 extern Type * type_combine(Type *specs, Type *spec);
211 extern Type * bare_extern(void);
212 extern Type * bare_register(void);
213 extern Type * bare_static(void);
214 extern Type * bare_const(void);
215 extern Type * bare_volatile(void);
216 extern Decl * declare(Scope *scope, char *id, Type *type);
217 extern Decl * make_pointer(Decl *decl, Type *type);
218 extern Decl * make_array(Type *type, Expr *expr);
219 extern Decl * build_function(Decl *decl, Decl_List *dlist, Type *type);
220 extern Decl_List * append_dlist(Decl_List *dlist, Decl *decl);
221 extern Decl_List * build_dlist(Decl *decl);
222 extern Expr * build_expr(Expr *left, enum Operator op, Expr *right);
223 extern Expr * var_expr(Scope *scope, char *id);
224 extern Code * build_expr_code(Expr *expr);
225 extern Code * build_if(Expr *cond_expr, Code *then_stmt, Code *else_stmt);
226 extern Code * code_append(Code *stmt_list, Code *stmt);
227