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