xref: /freebsd/contrib/byacc/test/btyacc_demo.y (revision 6cec9cad762b6476313fb1f8e931a1647822db6b)
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