xref: /minix/external/bsd/byacc/dist/test/btyacc_demo.y (revision 0a6a1f1d)
1 /*	$NetBSD: btyacc_demo.y,v 1.1.1.1 2015/01/03 22:58:23 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