btyacc_demo.y revision 268899
1/* 2 * demonstrate enhancements derived from btyacc: 3 * backtracking to resolve conflicts 4 * semantic disambiguation via []-actions invoking YYVALID & YYERROR 5 * %locations 6 * @$ & @N to refer to lhs & rhs symbol location 7 * %destructor 8 * syntactic suger for inherited attributes 9 * extension to %type to define inherited attribute type 10 */ 11 12%LOCATIONS 13 14%{ 15/* dummy types just for compile check */ 16typedef int Code; 17typedef int Decl_List; 18typedef int Expr; 19typedef int Expr_List; 20typedef int Scope; 21typedef int Type; 22enum Operator { ADD, SUB, MUL, MOD, DIV, DEREF }; 23 24typedef unsigned char bool; 25typedef struct Decl { 26 Scope *scope; 27 Type *type; 28 bool (*istype)(void); 29} Decl; 30 31#include "btyacc_demo.tab.h" 32#include <stdlib.h> 33#include <stdio.h> 34%} 35 36%union { 37 Scope *scope; 38 Expr *expr; 39 Expr_List *elist; 40 Type *type; 41 Decl *decl; 42 Decl_List *dlist; 43 Code *code; 44 char *id; 45 }; 46 47%left '+' '-' 48%left '*' '/' '%' 49%nonassoc PREFIX 50%nonassoc POSTFIX '(' '[' '.' 51 52%token <id> ID 53%token <expr> CONSTANT 54%token EXTERN REGISTER STATIC CONST VOLATILE IF THEN ELSE CLCL 55 56%type <expr> expr(<scope>) 57%type decl(<scope>) declarator_list(<scope>, <type>) 58 decl_list(<scope>) 59%type <code> statement(<scope>) statement_list(<scope>) 60 block_statement(<scope>) 61%type <decl> declarator(<scope>, <type>) formal_arg(<scope>) 62%type <type> decl_specs(<scope>) decl_spec(<scope>) typename(<scope>) 63 cv_quals cv_qual 64%type <scope> opt_scope(<scope>) 65%type <dlist> formal_arg_list(<scope>) nonempty_formal_arg_list(<scope>) 66 67%destructor { // 'msg' is a 'char *' indicating the context of destructor invocation 68 printf("%s accessed by symbol \"decl\" (case s.b. 273) @ position[%d,%d..%d,%d]\n", 69 msg, 70 @$.first_line, @$.first_column, 71 @$.last_line, @$.last_column); 72 free($<decl>$->scope); free($<decl>$->type); } decl 73%destructor { printf("%s accessed by symbol with type <decl> (case s.b. 279 & 280) @ position[%d,%d..%d,%d]\n", 74 msg, 75 @$.first_line, @$.first_column, 76 @$.last_line, @$.last_column); 77 free($$); } <decl> 78%destructor { printf("%s accessed by symbol of any type other than <decl> @ position[%d,%d..%d,%d]\n", 79 msg, 80 @$.first_line, @$.first_column, 81 @$.last_line, @$.last_column); 82 free($$); } <*> 83%destructor { printf("%s accessed by symbol with no type @ position[%d,%d..%d,%d]\n", 84 msg, 85 @$.first_line, @$.first_column, 86 @$.last_line, @$.last_column); 87 /* in this example, we don't know what to do here */ } <> 88 89%start input 90 91%% 92 93opt_scope($e): [ $$ = $e; ] 94 | CLCL [ $$ = global_scope; ] 95 | opt_scope ID CLCL [ Decl *d = lookup($1, $2); 96 if (!d || !d->scope) YYERROR; 97 $$ = d->scope; ] 98 ; 99 100typename($e): opt_scope ID 101 [ Decl *d = lookup($1, $2); 102 if (d == NULL || d->istype() == 0) YYERROR; 103 $$ = d->type; ] 104 ; 105 106input: decl_list(global_scope = new_scope(0)) ; 107decl_list($e): | decl_list decl($e) ; 108decl($e): 109 decl_specs declarator_list($e,$1) ';' [YYVALID;] 110 | decl_specs declarator($e,$1) block_statement(start_fn_def($e, $2)) 111 { /* demonstrate use of @$ & @N, although this is just the 112 default computation and so is not necessary */ 113 @$.first_line = @1.first_line; 114 @$.first_column = @1.first_column; 115 @$.last_line = @3.last_line; 116 @$.last_column = @3.last_column; 117 finish_fn_def($2, $3); } 118 ; 119 120decl_specs($e): 121 decl_spec [ $$ = $1; ] 122 | decl_specs decl_spec($e) [ $$ = type_combine($1, $2); ] 123 ; 124 125cv_quals: [ $$ = 0; ] 126 | cv_quals cv_qual [ $$ = type_combine($1, $2); ] 127 ; 128 129decl_spec($e): 130 cv_qual [ $$ = $1; ] 131 | typename [ $$ = $1; ] 132 | EXTERN [ $$ = bare_extern(); ] 133 | REGISTER [ $$ = bare_register(); ] 134 | STATIC [ $$ = bare_static(); ] 135 ; 136 137cv_qual: 138 CONST [ $$ = bare_const(); ] 139 | VOLATILE [ $$ = bare_volatile(); ] 140 ; 141 142declarator_list($e, $t): 143 declarator_list ',' declarator($e, $t) 144 | declarator 145 ; 146 147declarator($e, $t): 148 /* empty */ [ if (!$t) YYERROR; ] 149 { $$ = declare($e, 0, $t); } 150 | ID { $$ = declare($e, $1, $t); } 151 | '(' declarator($e, $t) ')' { $$ = $2; } 152 | '*' cv_quals declarator($e, $t) %prec PREFIX 153 { $$ = make_pointer($3, $2); } 154 | declarator '[' expr($e) ']' 155 { $$ = make_array($1->type, $3); } 156 | declarator '(' formal_arg_list($e) ')' cv_quals 157 { $$ = build_function($1, $3, $5); } 158 ; 159 160formal_arg_list($e): { $$ = 0; } 161 | nonempty_formal_arg_list { $$ = $1; } 162 ; 163nonempty_formal_arg_list($e): 164 nonempty_formal_arg_list ',' formal_arg($e) { $$ = append_dlist($1, $3); } 165 | formal_arg { $$ = build_dlist($1); } 166 ; 167formal_arg($e): 168 decl_specs declarator($e,$1) { $$ = $2; } 169 ; 170 171expr($e): 172 expr '+' expr($e) { $$ = build_expr($1, ADD, $3); } 173 | expr '-' expr($e) { $$ = build_expr($1, SUB, $3); } 174 | expr '*' expr($e) { $$ = build_expr($1, MUL, $3); } 175 | expr '%' expr($e) { $$ = build_expr($1, MOD, $3); } 176 | expr '/' expr($e) { $$ = build_expr($1, DIV, $3); } 177 | '*' expr($e) %prec PREFIX { $$ = build_expr(0, DEREF, $2); } 178 | ID { $$ = var_expr($e, $1); } 179 | CONSTANT { $$ = $1; } 180 ; 181 182statement($e): 183 decl { $$ = 0; } 184 | expr($e) ';' [YYVALID;] { $$ = build_expr_code($1); } 185 | IF '(' expr($e) ')' THEN statement($e) ELSE statement($e) [YYVALID;] 186 { $$ = build_if($3, $6, $8); } 187 | IF '(' expr($e) ')' THEN statement($e) [YYVALID;] 188 { $$ = build_if($3, $6, 0); } 189 | block_statement(new_scope($e)) [YYVALID;]{ $$ = $1; } 190 ; 191 192statement_list($e): { $$ = 0; } 193 | statement_list statement($e) { $$ = code_append($1, $2); } 194 ; 195 196block_statement($e): 197 '{' statement_list($e) '}' { $$ = $2; } 198 ; 199%% 200 201extern int YYLEX_DECL(); 202extern void YYERROR_DECL(); 203 204extern Scope *global_scope; 205 206extern Decl * lookup(Scope *scope, char *id); 207extern Scope * new_scope(Scope *outer_scope); 208extern Scope * start_fn_def(Scope *scope, Decl *fn_decl); 209extern void finish_fn_def(Decl *fn_decl, Code *block); 210extern Type * type_combine(Type *specs, Type *spec); 211extern Type * bare_extern(void); 212extern Type * bare_register(void); 213extern Type * bare_static(void); 214extern Type * bare_const(void); 215extern Type * bare_volatile(void); 216extern Decl * declare(Scope *scope, char *id, Type *type); 217extern Decl * make_pointer(Decl *decl, Type *type); 218extern Decl * make_array(Type *type, Expr *expr); 219extern Decl * build_function(Decl *decl, Decl_List *dlist, Type *type); 220extern Decl_List * append_dlist(Decl_List *dlist, Decl *decl); 221extern Decl_List * build_dlist(Decl *decl); 222extern Expr * build_expr(Expr *left, enum Operator op, Expr *right); 223extern Expr * var_expr(Scope *scope, char *id); 224extern Code * build_expr_code(Expr *expr); 225extern Code * build_if(Expr *cond_expr, Code *then_stmt, Code *else_stmt); 226extern Code * code_append(Code *stmt_list, Code *stmt); 227