1264790Sbapt/*
2264790Sbapt * demonstrate enhancements derived from btyacc:
3264790Sbapt * backtracking to resolve conflicts
4264790Sbapt * semantic disambiguation via []-actions invoking YYVALID & YYERROR
5264790Sbapt * %locations
6264790Sbapt * @$ & @N to refer to lhs & rhs symbol location
7264790Sbapt * %destructor
8264790Sbapt * syntactic suger for inherited attributes
9264790Sbapt * extension to %type to define inherited attribute type
10264790Sbapt */
11264790Sbapt
12264790Sbapt%LOCATIONS
13264790Sbapt
14264790Sbapt%{
15264790Sbapt/* dummy types just for compile check */
16264790Sbapttypedef int Code;
17264790Sbapttypedef int Decl_List;
18264790Sbapttypedef int Expr;
19264790Sbapttypedef int Expr_List;
20264790Sbapttypedef int Scope;
21264790Sbapttypedef int Type;
22264790Sbaptenum Operator { ADD, SUB, MUL, MOD, DIV, DEREF };
23264790Sbapt
24264790Sbapttypedef unsigned char bool;
25264790Sbapttypedef struct Decl {
26264790Sbapt    Scope *scope;
27264790Sbapt    Type  *type;
28264790Sbapt    bool (*istype)(void);
29264790Sbapt} Decl;
30264790Sbapt
31264790Sbapt#include "btyacc_demo.tab.h"
32264790Sbapt#include <stdlib.h>
33264790Sbapt#include <stdio.h>
34264790Sbapt%}
35264790Sbapt
36264790Sbapt%union {
37264790Sbapt    Scope	*scope;
38264790Sbapt    Expr	*expr;
39264790Sbapt    Expr_List	*elist;
40264790Sbapt    Type	*type;
41264790Sbapt    Decl	*decl;
42264790Sbapt    Decl_List	*dlist;
43264790Sbapt    Code	*code;
44264790Sbapt    char	*id;
45264790Sbapt    };
46264790Sbapt
47264790Sbapt%left '+' '-'
48264790Sbapt%left '*' '/' '%'
49264790Sbapt%nonassoc PREFIX
50264790Sbapt%nonassoc POSTFIX '(' '[' '.'
51264790Sbapt
52264790Sbapt%token <id>	ID
53264790Sbapt%token <expr>	CONSTANT
54264790Sbapt%token		EXTERN REGISTER STATIC CONST VOLATILE IF THEN ELSE CLCL
55264790Sbapt
56264790Sbapt%type <expr>	expr(<scope>)
57264790Sbapt%type		decl(<scope>) declarator_list(<scope>, <type>)
58264790Sbapt		decl_list(<scope>)
59264790Sbapt%type <code>	statement(<scope>) statement_list(<scope>)
60264790Sbapt		block_statement(<scope>)
61264790Sbapt%type <decl>	declarator(<scope>, <type>) formal_arg(<scope>)
62264790Sbapt%type <type>	decl_specs(<scope>) decl_spec(<scope>) typename(<scope>)
63264790Sbapt		cv_quals cv_qual
64264790Sbapt%type <scope>	opt_scope(<scope>)
65264790Sbapt%type <dlist>	formal_arg_list(<scope>) nonempty_formal_arg_list(<scope>)
66264790Sbapt
67264790Sbapt%destructor	{ // 'msg' is a 'char *' indicating the context of destructor invocation
68264790Sbapt		  printf("%s accessed by symbol \"decl\" (case s.b. 273) @ position[%d,%d..%d,%d]\n",
69264790Sbapt			 msg,
70264790Sbapt			 @$.first_line, @$.first_column,
71264790Sbapt			 @$.last_line, @$.last_column);
72264790Sbapt		  free($<decl>$->scope); free($<decl>$->type); } decl
73264790Sbapt%destructor	{ printf("%s accessed by symbol with type <decl> (case s.b. 279 & 280) @ position[%d,%d..%d,%d]\n",
74264790Sbapt			 msg,
75264790Sbapt			 @$.first_line, @$.first_column,
76264790Sbapt			 @$.last_line, @$.last_column);
77264790Sbapt		  free($$); } <decl>
78264790Sbapt%destructor	{ printf("%s accessed by symbol of any type other than <decl>  @ position[%d,%d..%d,%d]\n",
79264790Sbapt			 msg,
80264790Sbapt			 @$.first_line, @$.first_column,
81264790Sbapt			 @$.last_line, @$.last_column);
82264790Sbapt		  free($$); } <*>
83264790Sbapt%destructor	{ printf("%s accessed by symbol with no type @ position[%d,%d..%d,%d]\n",
84264790Sbapt			 msg,
85264790Sbapt			 @$.first_line, @$.first_column,
86264790Sbapt			 @$.last_line, @$.last_column);
87264790Sbapt		  /* in this example, we don't know what to do here */ } <>
88264790Sbapt
89264790Sbapt%start input
90264790Sbapt
91264790Sbapt%%
92264790Sbapt
93264790Sbaptopt_scope($e):		[ $$ = $e; ]
94264790Sbapt  | CLCL		[ $$ = global_scope; ]
95264790Sbapt  | opt_scope ID CLCL	[ Decl *d = lookup($1, $2);
96264790Sbapt			  if (!d || !d->scope) YYERROR;
97264790Sbapt			  $$ = d->scope; ]
98264790Sbapt  ;
99264790Sbapt
100264790Sbapttypename($e): opt_scope ID
101264790Sbapt      [ Decl *d = lookup($1, $2);
102264790Sbapt	if (d == NULL || d->istype() == 0) YYERROR;
103264790Sbapt	$$ = d->type; ]
104264790Sbapt  ;
105264790Sbapt
106264790Sbaptinput: decl_list(global_scope = new_scope(0)) ;
107264790Sbaptdecl_list($e): | decl_list decl($e) ;
108264790Sbaptdecl($e):
109264790Sbapt    decl_specs declarator_list($e,$1) ';' [YYVALID;]
110264790Sbapt  | decl_specs declarator($e,$1) block_statement(start_fn_def($e, $2))
111264790Sbapt      { /* demonstrate use of @$ & @N, although this is just the
112264790Sbapt	   default computation and so is not necessary */
113264790Sbapt	@$.first_line   = @1.first_line;
114264790Sbapt	@$.first_column = @1.first_column;
115264790Sbapt	@$.last_line    = @3.last_line;
116264790Sbapt	@$.last_column  = @3.last_column;
117264790Sbapt	finish_fn_def($2, $3); }
118264790Sbapt  ;
119264790Sbapt
120264790Sbaptdecl_specs($e):
121264790Sbapt    decl_spec			[ $$ = $1; ]
122264790Sbapt  | decl_specs decl_spec($e)	[ $$ = type_combine($1, $2); ]
123264790Sbapt  ;
124264790Sbapt
125264790Sbaptcv_quals:			[ $$ = 0; ]
126264790Sbapt  | cv_quals cv_qual		[ $$ = type_combine($1, $2); ]
127264790Sbapt  ;
128264790Sbapt
129264790Sbaptdecl_spec($e):
130264790Sbapt    cv_qual		[ $$ = $1; ]
131264790Sbapt  | typename		[ $$ = $1; ]
132264790Sbapt  | EXTERN		[ $$ = bare_extern(); ]
133264790Sbapt  | REGISTER		[ $$ = bare_register(); ]
134264790Sbapt  | STATIC		[ $$ = bare_static(); ]
135264790Sbapt  ;
136264790Sbapt
137264790Sbaptcv_qual:
138264790Sbapt    CONST		[ $$ = bare_const(); ]
139264790Sbapt  | VOLATILE		[ $$ = bare_volatile(); ]
140264790Sbapt  ;
141264790Sbapt
142264790Sbaptdeclarator_list($e, $t):
143264790Sbapt    declarator_list ',' declarator($e, $t)
144264790Sbapt  | declarator
145264790Sbapt  ;
146264790Sbapt
147264790Sbaptdeclarator($e, $t):
148264790Sbapt    /* empty */			[ if (!$t) YYERROR; ]
149264790Sbapt				{ $$ = declare($e, 0, $t); }
150264790Sbapt  | ID				{ $$ = declare($e, $1, $t); }
151264790Sbapt  | '(' declarator($e, $t) ')'	{ $$ = $2; }
152264790Sbapt  | '*' cv_quals declarator($e, $t) %prec PREFIX
153264790Sbapt	  { $$ = make_pointer($3, $2); }
154264790Sbapt  | declarator '[' expr($e) ']'
155264790Sbapt	  { $$ = make_array($1->type, $3); }
156264790Sbapt  | declarator '(' formal_arg_list($e) ')' cv_quals
157264790Sbapt	  { $$ = build_function($1, $3, $5); }
158264790Sbapt  ;
159264790Sbapt
160264790Sbaptformal_arg_list($e):		{ $$ = 0; }
161264790Sbapt  | nonempty_formal_arg_list	{ $$ = $1; }
162264790Sbapt  ;
163264790Sbaptnonempty_formal_arg_list($e):
164264790Sbapt    nonempty_formal_arg_list ',' formal_arg($e)	{ $$ = append_dlist($1, $3); }
165264790Sbapt  | formal_arg					{ $$ = build_dlist($1); }
166264790Sbapt  ;
167264790Sbaptformal_arg($e):
168264790Sbapt    decl_specs declarator($e,$1)	{ $$ = $2; }
169264790Sbapt  ;
170264790Sbapt
171264790Sbaptexpr($e):
172264790Sbapt    expr '+' expr($e)		{ $$ = build_expr($1, ADD, $3); }
173264790Sbapt  | expr '-' expr($e)		{ $$ = build_expr($1, SUB, $3); }
174264790Sbapt  | expr '*' expr($e)		{ $$ = build_expr($1, MUL, $3); }
175264790Sbapt  | expr '%' expr($e)		{ $$ = build_expr($1, MOD, $3); }
176264790Sbapt  | expr '/' expr($e)		{ $$ = build_expr($1, DIV, $3); }
177264790Sbapt  | '*' expr($e) %prec PREFIX	{ $$ = build_expr(0, DEREF, $2); }
178264790Sbapt  | ID				{ $$ = var_expr($e, $1); }
179264790Sbapt  | CONSTANT			{ $$ = $1; }
180264790Sbapt  ;
181264790Sbapt
182264790Sbaptstatement($e):
183264790Sbapt    decl			{ $$ = 0; }
184264790Sbapt  | expr($e) ';' [YYVALID;]	{ $$ = build_expr_code($1); }
185264790Sbapt  | IF '(' expr($e) ')' THEN statement($e) ELSE statement($e) [YYVALID;]
186264790Sbapt    { $$ = build_if($3, $6, $8); }
187264790Sbapt  | IF '(' expr($e) ')' THEN statement($e) [YYVALID;]
188264790Sbapt    { $$ = build_if($3, $6, 0); }
189264790Sbapt  | block_statement(new_scope($e)) [YYVALID;]{ $$ = $1; }
190264790Sbapt  ;
191264790Sbapt
192264790Sbaptstatement_list($e):			{ $$ = 0; }
193264790Sbapt  | statement_list statement($e)	{ $$ = code_append($1, $2); }
194264790Sbapt  ;
195264790Sbapt
196264790Sbaptblock_statement($e):
197264790Sbapt    '{' statement_list($e) '}' { $$ = $2; }
198264790Sbapt  ;
199264790Sbapt%%
200264790Sbapt
201264790Sbaptextern int YYLEX_DECL();
202264790Sbaptextern void YYERROR_DECL();
203264790Sbapt
204264790Sbaptextern Scope *global_scope;
205264790Sbapt
206264790Sbaptextern Decl * lookup(Scope *scope, char *id);
207264790Sbaptextern Scope * new_scope(Scope *outer_scope);
208264790Sbaptextern Scope * start_fn_def(Scope *scope, Decl *fn_decl);
209264790Sbaptextern void finish_fn_def(Decl *fn_decl, Code *block);
210264790Sbaptextern Type * type_combine(Type *specs, Type *spec);
211264790Sbaptextern Type * bare_extern(void);
212264790Sbaptextern Type * bare_register(void);
213264790Sbaptextern Type * bare_static(void);
214264790Sbaptextern Type * bare_const(void);
215264790Sbaptextern Type * bare_volatile(void);
216264790Sbaptextern Decl * declare(Scope *scope, char *id, Type *type);
217264790Sbaptextern Decl * make_pointer(Decl *decl, Type *type);
218264790Sbaptextern Decl * make_array(Type *type, Expr *expr);
219264790Sbaptextern Decl * build_function(Decl *decl, Decl_List *dlist, Type *type);
220264790Sbaptextern Decl_List * append_dlist(Decl_List *dlist, Decl *decl);
221264790Sbaptextern Decl_List * build_dlist(Decl *decl);
222264790Sbaptextern Expr * build_expr(Expr *left, enum Operator op, Expr *right);
223264790Sbaptextern Expr * var_expr(Scope *scope, char *id);
224264790Sbaptextern Code * build_expr_code(Expr *expr);
225264790Sbaptextern Code * build_if(Expr *cond_expr, Code *then_stmt, Code *else_stmt);
226264790Sbaptextern Code * code_append(Code *stmt_list, Code *stmt);
227