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