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 */
18typedef int Code;
19typedef int Decl_List;
20typedef int Expr;
21typedef int Expr_List;
22typedef int Scope;
23typedef int Type;
24enum Operator { ADD, SUB, MUL, MOD, DIV, DEREF };
25
26typedef unsigned char bool;
27typedef 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
95opt_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
102typename($e): opt_scope ID
103      [ Decl *d = lookup($1, $2);
104	if (d == NULL || d->istype() == 0) YYERROR;
105	$$ = d->type; ]
106  ;
107
108input: decl_list(global_scope = new_scope(0)) ;
109decl_list($e): | decl_list decl($e) ;
110decl($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
122decl_specs($e):
123    decl_spec			[ $$ = $1; ]
124  | decl_specs decl_spec($e)	[ $$ = type_combine($1, $2); ]
125  ;
126
127cv_quals:			[ $$ = 0; ]
128  | cv_quals cv_qual		[ $$ = type_combine($1, $2); ]
129  ;
130
131decl_spec($e):
132    cv_qual		[ $$ = $1; ]
133  | typename		[ $$ = $1; ]
134  | EXTERN		[ $$ = bare_extern(); ]
135  | REGISTER		[ $$ = bare_register(); ]
136  | STATIC		[ $$ = bare_static(); ]
137  ;
138
139cv_qual:
140    CONST		[ $$ = bare_const(); ]
141  | VOLATILE		[ $$ = bare_volatile(); ]
142  ;
143
144declarator_list($e, $t):
145    declarator_list ',' declarator($e, $t)
146  | declarator
147  ;
148
149declarator($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
162formal_arg_list($e):		{ $$ = 0; }
163  | nonempty_formal_arg_list	{ $$ = $1; }
164  ;
165nonempty_formal_arg_list($e):
166    nonempty_formal_arg_list ',' formal_arg($e)	{ $$ = append_dlist($1, $3); }
167  | formal_arg					{ $$ = build_dlist($1); }
168  ;
169formal_arg($e):
170    decl_specs declarator($e,$1)	{ $$ = $2; }
171  ;
172
173expr($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
184statement($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
194statement_list($e):			{ $$ = 0; }
195  | statement_list statement($e)	{ $$ = code_append($1, $2); }
196  ;
197
198block_statement($e):
199    '{' statement_list($e) '}' { $$ = $2; }
200  ;
201%%
202
203extern int YYLEX_DECL();
204extern void YYERROR_DECL();
205
206extern Scope *global_scope;
207
208extern Decl * lookup(Scope *scope, char *id);
209extern Scope * new_scope(Scope *outer_scope);
210extern Scope * start_fn_def(Scope *scope, Decl *fn_decl);
211extern void finish_fn_def(Decl *fn_decl, Code *block);
212extern Type * type_combine(Type *specs, Type *spec);
213extern Type * bare_extern(void);
214extern Type * bare_register(void);
215extern Type * bare_static(void);
216extern Type * bare_const(void);
217extern Type * bare_volatile(void);
218extern Decl * declare(Scope *scope, char *id, Type *type);
219extern Decl * make_pointer(Decl *decl, Type *type);
220extern Decl * make_array(Type *type, Expr *expr);
221extern Decl * build_function(Decl *decl, Decl_List *dlist, Type *type);
222extern Decl_List * append_dlist(Decl_List *dlist, Decl *decl);
223extern Decl_List * build_dlist(Decl *decl);
224extern Expr * build_expr(Expr *left, enum Operator op, Expr *right);
225extern Expr * var_expr(Scope *scope, char *id);
226extern Code * build_expr_code(Expr *expr);
227extern Code * build_if(Expr *cond_expr, Code *then_stmt, Code *else_stmt);
228extern Code * code_append(Code *stmt_list, Code *stmt);
229