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