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