├── AUTHORS.txt ├── Makefile ├── README.md ├── c_parser.l ├── c_parser.y ├── generate_tokens.py ├── input ├── symtable.h ├── tokens └── tokens.h /AUTHORS.txt: -------------------------------------------------------------------------------- 1 | PRATEEK VIJ 2 | SAGAR MANCHANDA 3 | SAURABH BATRA 4 | UPPINDER CHUGH -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | c_parser: lex.yy.c y.tab.c 2 | g++ lex.yy.c y.tab.c -o c_parser -g -w -fpermissive -std=c++11 3 | 4 | lex.yy.c: y.tab.c c_parser.l 5 | lex c_parser.l 6 | 7 | y.tab.c: c_parser.y 8 | yacc -d -v -Wconflicts-sr c_parser.y 9 | 10 | clean: 11 | rm lex.yy.c y.tab.c y.tab.h c_parser 12 | 13 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FrontEnd-C-Compiler 2 | 3 | 4 | The following is an implementation of front-end C compiler using flex and bison. The program takes a C-program as input and perform syntax parsing, semantic analysis and Intermediate Code Generation. The parser is based on LALR grammar. 5 | 6 | If the input C program is valid, program output Symbol table along with intermediate code. 7 | 8 | 9 | To compile the code, run 10 | ```bash 11 | $ make 12 | ``` 13 | To recompile. run 14 | ``` 15 | $ make clean 16 | $ make 17 | ``` 18 | 19 | The program need bison and flex installed. You can install them by 20 | ```bash 21 | $ sudo apt-get install bison 22 | $ sudo apt-get install flex 23 | ``` 24 | 25 | The list of supported tokens is given in file "tokens". If you want to add or remove tokens, make changes in the file "tokens". Then, run 26 | ```bash 27 | $ python generate_tokens.py 28 | ``` 29 | This will generate "tokens.h" which is used by the program. 30 | 31 | To run the code, write the sample code to parse in file "input". Now run the command 32 | ```bash 33 | $ ./c_parser < input 34 | ``` 35 | 36 | ### About the code 37 | 1. **c_parser.y**: Primary file containing the grammer for parsing and semantic analysis. 38 | 2. **c_parser.l**: Contains regex and token_strings for converting strings to tokens. 39 | 3. **symtable.h**: Code for symbol table generation and maintainance. 40 | 4. **tokens.h**: Contains tokens for flex parsing 41 | 42 | ### Examples 43 | 44 | ```c 45 | int max(int a,int b){ 46 | if ( a > b ){ 47 | return a; 48 | } 49 | return b; 50 | } 51 | int main(){ 52 | 53 | int a, b; 54 | a = 2; 55 | b = 5; 56 | int c; 57 | if ( a > b) { 58 | return b; 59 | while( b > 0 ){ 60 | c = c+1; 61 | b = b-1; 62 | } 63 | } 64 | return 0; 65 | } 66 | ``` 67 | 68 | Output 69 | ```bash 70 | Symbol Table 71 | $global 0 72 | >>Name: $global 73 | >>Param count: 0 74 | >>Params : 75 | >>Var : 76 | max int 2 77 | >>Name: max 78 | >>Param count: 2 79 | >>Params : a(int)(1) b(int)(1) 80 | >>Var : 81 | main int 0 82 | >>Name: main 83 | >>Param count: 0 84 | >>Params : 85 | >>Var : a(int)(2) simple b(int)(2) simple c(int)(2) simple 86 | 87 | 0 func begin max 88 | 1 t1 = a > b 89 | 2 if (t1 == 0) goto 4 90 | 3 return a 91 | 4 return b 92 | 5 func end 93 | 6 func begin main 94 | 7 a = 2 95 | 8 b = 5 96 | 9 t2 = a > b 97 | 10 if (t2 == 0) goto 20 98 | 11 return b 99 | 12 t3 = b > 0 100 | 13 if (t3 == 0) goto 20 101 | 14 t4 = a * 3 102 | 15 t5 = c + t4 103 | 16 c = t5 104 | 17 t6 = b - 1 105 | 18 b = t6 106 | 19 goto 12 107 | 20 return 0 108 | 21 func end 109 | 110 | ``` 111 | -------------------------------------------------------------------------------- /c_parser.l: -------------------------------------------------------------------------------- 1 | %{ 2 | 3 | #include "y.tab.h" 4 | 5 | using namespace std; 6 | 7 | #define RET(token_name, token) { yylval.lex_val = strdup(yytext);return token;} 8 | 9 | 10 | %} 11 | 12 | %% 13 | "if" RET("IF", IF) 14 | "else" RET("ELSE", ELSE) 15 | "while" RET("WHILE", WHILE) 16 | "do" RET("DO", DO) 17 | "for" RET("FOR", FOR) 18 | "main" RET("MAIN", MAIN) 19 | "struct" RET("STRUCT", STRUCT) 20 | "return" RET("RETURN", RETURN) 21 | "default" RET("DEFAULT", DEFAULT) 22 | "const" RET("CONST", CONST) 23 | "break" RET("BREAK", BREAK) 24 | "continue" RET("CONTINUE", CONTINUE) 25 | "goto" RET("GOTO", GOTO) 26 | "void" RET("VOID", VOID) 27 | "int" RET("INT", INT) 28 | "float" RET("FLOAT", FLOAT) 29 | "char" RET("CHAR", CHAR) 30 | ";" RET("SEMICOLON", SEMICOLON) 31 | "," RET("COMMA", COMMA) 32 | "[" RET("LEFT_SQ_BRACKET", LEFT_SQ_BRACKET) 33 | "]" RET("RIGHT_SQ_BRACKET", RIGHT_SQ_BRACKET) 34 | "{" RET("LEFT_CURLY_BRACKET", LEFT_CURLY_BRACKET) 35 | "}" RET("RIGHT_CURLY_BRACKET", RIGHT_CURLY_BRACKET) 36 | "(" RET("LP", LP) 37 | ")" RET("RP", RP) 38 | "->" RET("DEREFERENCE", DEREFERENCE) 39 | "+" RET("PLUS", PLUS) 40 | "-" RET("MINUS", MINUS) 41 | "*" RET("ASTERISK", ASTERISK) 42 | "/" RET("DIVIDE", DIVIDE) 43 | "." RET("DOT", DOT) 44 | "&&" RET("AND_EXP", AND_EXP) 45 | "&" RET("AMP", AMP) 46 | "%" RET("MODULO", MODULO) 47 | "=" RET("ASSIGN_OP", ASSIGN_OP) 48 | "||" RET("OR_EXP", OR_EXP) 49 | "!" RET("NOT_EXP", NOT_EXP) 50 | ">>" RET("RIGHT_SHIFT", RIGHT_SHIFT) 51 | "<<" RET("LEFT_SHIFT", LEFT_SHIFT) 52 | "|" RET("OR_BIT", OR_BIT) 53 | "<=" RET("LTE", LTE) 54 | ">=" RET("GTE", GTE) 55 | "<" RET("LT", LT) 56 | ">" RET("GT", GT) 57 | "==" RET("EQ", EQ) 58 | [0-9]+ RET("INTEGER", INTEGER) 59 | \'[a-zA-Z]\' RET("CHARACTER", CHARACTER) 60 | [0-9]+\.?[0-9]* RET("REAL", REAL) 61 | [a-zA-Z_][a-zA-Z0-9_]* RET("ID", ID) 62 | \"(\\.|''|[^'\n])*\" RET("STRING",STRING) 63 | [ \t\n] ; 64 | . {printf("Unexpected token : %s\n", yytext);} 65 | %% 66 | 67 | int yywrap() {return 1;} -------------------------------------------------------------------------------- /c_parser.y: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | 4 | using namespace std; 5 | #include "symtable.h" 6 | 7 | 8 | extern char* yytext; 9 | extern int yyleng; 10 | void yyerror(char*); 11 | int yylex(void); 12 | #define YYDEBUG 1 13 | // #define YYSTYPE container 14 | // extern YYSTYPE yylval; 15 | 16 | int next_quad = 0, temp_num = 0; 17 | vector i_code; 18 | vector tempList(10000); // stores type of each temp variable used for corresponing temp_num 19 | 20 | string newTemp(string); // feed type to this 21 | void genCode(string); 22 | void printThreeAddressCode(); 23 | int increment(string s); 24 | vector *makelist(); 25 | void backpatch(vector *list, int quad); 26 | void substitute(int quad_number, string replacent); 27 | 28 | map sizes; 29 | 30 | %} 31 | 32 | %glr-parser 33 | %define parse.error verbose 34 | 35 | %start Start 36 | %token IF ELSE WHILE DO FOR MAIN STRUCT RETURN DEFAULT CONST BREAK CONTINUE GOTO 37 | %token VOID INT FLOAT CHAR 38 | %token SEMICOLON COMMA LEFT_SQ_BRACKET RIGHT_SQ_BRACKET LEFT_CURLY_BRACKET RIGHT_CURLY_BRACKET LP RP 39 | %token PLUS MINUS ASTERISK DIVIDE DOT DEREFERENCE AMP MODULO ASSIGN_OP AND_EXP OR_EXP NOT_EXP RIGHT_SHIFT LEFT_SHIFT AND_BIT OR_BIT 40 | %token LT GT EQ LTE GTE 41 | %token INTEGER CHARACTER STRING REAL ID 42 | %token _THEN_ _ELSE_ 43 | 44 | %left OR_EXP 45 | %left AND_EXP 46 | %left EQ 47 | %left LT GT LTE GTE 48 | %left PLUS MINUS 49 | %left ASTERISK DIVIDE 50 | 51 | %right ASSIGN_OP 52 | 53 | %nonassoc _THEN_ 54 | %nonassoc ELSE 55 | 56 | %right "declaration" 57 | %right LP 58 | 59 | 60 | %union { 61 | char* lex_val; 62 | struct Node *node; 63 | } 64 | 65 | %type id_array L var_type res_id const expr asg func_call elist explist DIMLIST 66 | %type stmt_list cond_stmt ifexp n m stmt scoped_stmt Decl funccall_stmt 67 | %type while_exp while_stmt array_elem dims lhs 68 | %type INTEGER CHARACTER STRING REAL ID operator comparator 69 | %type VOID INT FLOAT CHAR 70 | %type PLUS MINUS DIVIDE ASTERISK LEFT_SHIFT RIGHT_SHIFT AMP OR_BIT AND_BIT AND_EXP OR_EXP 71 | %type LTE GTE EQ GT LT 72 | 73 | 74 | 75 | 76 | %% 77 | 78 | Start : Decl Start{ } 79 | | function Start{ } 80 | | 81 | ; 82 | 83 | 84 | Decl : var_type L SEMICOLON {} 85 | { 86 | 87 | symtab->patch($1->attr["type"], $2->namelist, current_level ); 88 | } 89 | ; 90 | 91 | 92 | L : id_array 93 | { 94 | $$ = new Node; 95 | $$->namelist = $1->namelist; 96 | // cout << "here2" <namelist = new list; 103 | *($$->namelist) = *($1->namelist); 104 | if (($3->namelist)->size()) 105 | { 106 | int id_array_val = ($3->namelist)->front(); 107 | ($$->namelist)->push_back(id_array_val); 108 | } 109 | 110 | } 111 | ; 112 | 113 | id_array : ID DIMLIST 114 | { 115 | // cout << "here3" <attr["name"] = $1; 118 | string name = $1; 119 | // int a; 120 | bool found; 121 | int var_ptr = symtab->search_var(name, active_func_ptr, current_level, &found); 122 | int var_level = -1; 123 | if (found) 124 | { 125 | var_level = symtab->func_name_table[active_func_ptr].loc_varlist_ptr[var_ptr].level; 126 | // cout << "level: "<namelist = new list; 129 | if (found && var_level == current_level) 130 | { 131 | cout << "Error: Redeclaration of variable within the same scope " << name <search_param(name, &found, active_func_ptr); 136 | if (found) 137 | { 138 | cout << "Error: Variable "<< name << " already declared as a parameter" << endl; 139 | } 140 | else{ 141 | string var_tag = "simple"; 142 | if($2->attr_list["dimlist"]->size()){ 143 | var_tag = "array"; 144 | } 145 | int sym_ptr = symtab->add_var(active_func_ptr,name,"",current_level, var_tag, $2->attr_list["dimlist"]); 146 | ($$->namelist)->push_back(sym_ptr); 147 | } 148 | } 149 | else{ 150 | string var_tag = "simple"; 151 | if($2->attr_list["dimlist"]->size()){ 152 | var_tag = "array"; 153 | } 154 | int sym_ptr = symtab->add_var(active_func_ptr,name,"",current_level, var_tag, $2->attr_list["dimlist"]); 155 | ($$->namelist)->push_back(sym_ptr); 156 | } 157 | 158 | } 159 | ; 160 | 161 | 162 | DIMLIST : DIMLIST LEFT_SQ_BRACKET INTEGER RIGHT_SQ_BRACKET 163 | { 164 | $1->attr_list["dimlist"]->push_back(stoi($3)); 165 | $$->attr_list["dimlist"] = $1->attr_list["dimlist"]; 166 | 167 | } 168 | | 169 | { 170 | $$ = new Node; 171 | $$->attr_list["dimlist"] = makelist(); 172 | } 173 | ; 174 | 175 | 176 | function : func_head LEFT_CURLY_BRACKET body RIGHT_CURLY_BRACKET 177 | { 178 | active_func_ptr = curr_func_stack.top(); // suggest global, gadbad 179 | current_level = 0; 180 | curr_func_stack.pop(); 181 | genCode("func end"); 182 | } 183 | ; 184 | 185 | func_head : res_id LP paramlist RP { current_level = 2;} 186 | ; 187 | 188 | res_id : var_type ID 189 | { 190 | string type = $1->attr["type"]; 191 | string name = $2; 192 | bool found; 193 | int a; 194 | symtab->search_func(name,&found); 195 | if (found) 196 | cout << "Error: Function " << name << " already declared" << endl; 197 | else{ 198 | active_func_ptr = symtab->add_function(name,type); 199 | current_level = 1; 200 | curr_func_stack.push(active_func_ptr); 201 | } 202 | genCode("func begin " + name); 203 | 204 | } 205 | | VOID ID 206 | { 207 | string type = "void"; 208 | string name = $2; 209 | bool found; 210 | symtab->search_func(name,&found); 211 | if (found) 212 | cout << "Error: Function " << name << " already declared" << endl; 213 | else{ 214 | active_func_ptr = symtab->add_function(name,type); 215 | current_level = 1; 216 | curr_func_stack.push(active_func_ptr); 217 | } 218 | genCode("func begin " + name); 219 | } 220 | | var_type MAIN 221 | { 222 | string type = $1->attr["type"]; 223 | string name = "main"; 224 | bool found; 225 | symtab->search_func(name,&found); 226 | if (found) 227 | cout << "Error: Function " << name << " already declared" << endl; 228 | else{ 229 | active_func_ptr = symtab->add_function(name,type); 230 | current_level = 1; 231 | curr_func_stack.push(active_func_ptr); 232 | 233 | } 234 | genCode("func begin " + name); 235 | } 236 | | VOID MAIN 237 | { 238 | string type = "void"; 239 | string name = "main"; 240 | bool found; 241 | symtab->search_func(name,&found); 242 | if (found) 243 | cout << "Error: Function " << name << " already declared" << endl; 244 | else{ 245 | active_func_ptr = symtab->add_function(name,type); 246 | current_level = 1; 247 | curr_func_stack.push(active_func_ptr); 248 | } 249 | genCode("func begin " + name); 250 | } 251 | ; 252 | 253 | paramlist : params {} 254 | | {} 255 | ; 256 | 257 | params : params COMMA param { } 258 | | param {} 259 | ; 260 | 261 | param : var_type ID 262 | { 263 | string type = $1->attr["type"]; 264 | string name = $2; 265 | bool found; 266 | symtab->search_param(name, &found, active_func_ptr); 267 | if (found) 268 | cout << "Error: Param " << name << " already in use" << endl; 269 | else{ 270 | symtab->add_param(active_func_ptr, name,type); 271 | } 272 | } 273 | ; 274 | 275 | 276 | 277 | body : stmt_list 278 | { 279 | current_level ++; 280 | if (!symtab->func_name_table[active_func_ptr].returned && symtab->func_name_table[active_func_ptr].result_type != "void") { 281 | cout << "Error: Function " << symtab->func_name_table[active_func_ptr].name << " does not have a return statement." << endl; 282 | } 283 | } 284 | | 285 | ; 286 | stmt_list : stmt_list stmt 287 | | stmt 288 | { 289 | $$ = new Node; 290 | $$->attr_list["next"] = $1->attr_list["next"]; 291 | } 292 | ; 293 | 294 | stmt : Decl 295 | { 296 | $$ = new Node; 297 | $$->attr_list["next"] = makelist(); 298 | // $$->attr_list["next"] = 299 | } 300 | | funccall_stmt 301 | | asg 302 | { 303 | // changes required here !! 304 | $$ = new Node; 305 | $$->attr_list["next"] = makelist(); 306 | // genCode("Assignment"); 307 | // backpatch($$->attr["next"],next_quad); 308 | 309 | } 310 | 311 | | cond_stmt 312 | { 313 | $$ = new Node; 314 | $$->attr_list["next"] = $1->attr_list["next"]; 315 | backpatch($$->attr_list["next"], next_quad); 316 | } 317 | | while_stmt 318 | { 319 | $$ = new Node; 320 | $$->attr_list["next"] = $1->attr_list["next"]; 321 | backpatch($$->attr_list["next"], next_quad); 322 | 323 | } 324 | | return_stmt 325 | { 326 | $$ = new Node; 327 | $$->attr_list["next"] = makelist(); 328 | } 329 | | scoped_stmt 330 | { 331 | $$ = new Node; 332 | $$->attr_list["next"] = $1->attr_list["next"]; 333 | // backpatch($1->attr_list["next"], next_quad); 334 | } 335 | 336 | ; 337 | 338 | scoped_stmt : nest_begin stmt_list nest_end 339 | { 340 | $$ = new Node; 341 | $$->attr_list["next"] = $2->attr_list["next"]; 342 | } 343 | ; 344 | 345 | nest_begin : LEFT_CURLY_BRACKET 346 | { 347 | current_level++; 348 | } 349 | ; 350 | 351 | nest_end : RIGHT_CURLY_BRACKET 352 | { 353 | current_level--; 354 | } 355 | ; 356 | 357 | asg : lhs ASSIGN_OP expr SEMICOLON 358 | { 359 | string type = $1->attr["type"]; 360 | 361 | if (type != $3->attr["type"]) { 362 | cout << "Error: Type mismatch, type of " << $1 << " does not match type of RHS." << endl; 363 | } else { 364 | genCode($1->attr["tempname"]+" = "+$3->attr["tempname"]); 365 | } 366 | 367 | } 368 | ; 369 | 370 | lhs : ID 371 | { 372 | $$ = new Node; 373 | bool found_var = false, found_param = false; 374 | 375 | int vnptr = symtab->search_var($1, active_func_ptr, current_level, &found_var); 376 | int pnptr = symtab->search_param($1, &found_param, active_func_ptr); 377 | if (!found_var && !found_param) { 378 | cout << "Error: Variable " << $1 << " not declaredd in this scope." << endl; 379 | } else { 380 | string type = ""; 381 | if (vnptr != -1) { 382 | type = symtab->func_name_table[active_func_ptr].loc_varlist_ptr[vnptr].type; 383 | } else { 384 | type = symtab->func_name_table[active_func_ptr].paramlist_ptr[pnptr].type; 385 | } 386 | 387 | $$->attr["type"] = type; 388 | $$->attr["tempname"] = $1; 389 | } 390 | } 391 | | array_elem {$$ = $1;} 392 | ; 393 | 394 | funccall_stmt : func_call SEMICOLON 395 | { 396 | // active_func_ptr = curr_func_stack.top(); 397 | curr_func_stack.pop(); 398 | call_name_ptr = curr_func_stack.top(); 399 | } 400 | ; 401 | 402 | func_call : ID LP explist RP 403 | { 404 | $$ = new Node; 405 | $$->attr["type"] = "ERROR"; 406 | string name = $1; 407 | bool found = false; 408 | int fnptr = symtab->search_func(name, &found); 409 | 410 | 411 | if(!found) { 412 | cout << "Function " << name << " not declared." << endl; 413 | call_name_ptr = 0; 414 | } else { 415 | string type = symtab->func_name_table[fnptr].result_type; 416 | $$->attr["type"] = type; 417 | int num_params = symtab->func_name_table[fnptr].num_params; 418 | if (num_params != stoi($3->attr["pno"])) 419 | { 420 | cout << "Mismatch in number of parameters of function "<attr["tempname"] = result_var; 429 | 430 | genCode("refparam " + result_var); 431 | genCode("call " + name + ", " + to_string(num_params + 1)); 432 | curr_func_stack.push(active_func_ptr); 433 | } 434 | active_func_ptr = fnptr; 435 | } 436 | } 437 | ; 438 | 439 | explist : elist 440 | { 441 | $$ = new Node; 442 | $$->attr["pno"] = $1->attr["pno"]; 443 | } 444 | | { 445 | $$ = new Node; 446 | $$->attr["pno"] = "0"; 447 | } 448 | ; 449 | 450 | elist : elist COMMA expr 451 | { 452 | int newVal = increment($1->attr["pno"]); 453 | $$ = new Node; 454 | $$->attr["pno"] = to_string(newVal); 455 | bool ok; 456 | symtab->check_param_type(curr_func_stack.top(), newVal, $3->attr["type"], ok); 457 | if(!ok) 458 | cout << "Parameter type mismatch in declaration and call."; 459 | else 460 | genCode("param expr.result"); 461 | } 462 | 463 | | expr 464 | { 465 | $$ = new Node; 466 | $$->attr["pno"] = "1"; 467 | bool ok; 468 | symtab->check_param_type(curr_func_stack.top(), 1, $1->attr["type"], ok); 469 | if(!ok) 470 | cout << "Parameter type mismatch in declaration and call."; 471 | else 472 | genCode("param expr.result"); 473 | } 474 | 475 | 476 | 477 | expr : const {$$ = $1;} 478 | | array_elem {$$ = $1;} 479 | | ID 480 | { 481 | $$ = new Node; 482 | $$->attr["type"] = "ERROR"; 483 | bool found_var = false, found_param = false; 484 | int vnptr = symtab->search_var($1, active_func_ptr, current_level, &found_var); 485 | int pnptr = symtab->search_param($1, &found_param, active_func_ptr); 486 | if (!found_var && !found_param) { 487 | cout << "Error: Variable " << $1 << " not declared in this scope." << endl; 488 | } else { 489 | if (vnptr != -1) { 490 | $$->attr["type"] = symtab->func_name_table[active_func_ptr].loc_varlist_ptr[vnptr].type; 491 | $$->attr["name"] = symtab->func_name_table[active_func_ptr].loc_varlist_ptr[vnptr].name; 492 | $$->attr["tempname"] = $$->attr["name"]; 493 | } else { 494 | $$->attr["type"] = symtab->func_name_table[active_func_ptr].paramlist_ptr[pnptr].type; 495 | $$->attr["name"] = symtab->func_name_table[active_func_ptr].paramlist_ptr[pnptr].name; 496 | $$->attr["tempname"] = $$->attr["name"]; 497 | } 498 | } 499 | } 500 | | LP expr RP {$$ = $2;} 501 | | func_call 502 | { 503 | $$ = $1; 504 | } 505 | | const operator expr 506 | { 507 | $$ = new Node; 508 | $$->attr["type"] = "ERROR"; 509 | if ($1->attr["type"] != $3->attr["type"]) { 510 | cout << "Error: Type mismatch for operator " << $1 << endl; 511 | } 512 | else{ 513 | $$->attr["type"] = $1->attr["type"]; 514 | $$->attr["tempname"] = newTemp($1->attr["type"]); 515 | genCode($$->attr["tempname"] + " = " + $1->attr["tempname"] + " " + $2 + " " + $3->attr["tempname"]); 516 | } 517 | } 518 | | ID operator expr 519 | { 520 | $$ = new Node; 521 | $$->attr["type"] = "ERROR"; 522 | 523 | bool found_var = false, found_param = false; 524 | int vnptr = symtab->search_var($1, active_func_ptr, current_level, &found_var); 525 | int pnptr = symtab->search_param($1, &found_param, active_func_ptr); 526 | if (!found_var && !found_param) { 527 | cout << "Error: Variable " << $1 << " not declared in this scope." << endl; 528 | } else { 529 | if (vnptr != -1 && symtab->func_name_table[active_func_ptr].loc_varlist_ptr[vnptr].type != $3->attr["type"]) { 530 | cout << "Error: Type mismatch for operator " << $1 << endl; 531 | } else if (pnptr != -1 && symtab->func_name_table[active_func_ptr].paramlist_ptr[pnptr].type != $3->attr["type"] ) { 532 | cout << "Error: Type mismatch for operator " << $1 << endl; 533 | } 534 | else{ 535 | $$->attr["type"] = $3->attr["type"]; 536 | $$->attr["tempname"] = newTemp($3->attr["type"]); 537 | genCode($$->attr["tempname"] + " = " + $1 + " " + $2 + " " + $3->attr["tempname"]); 538 | } 539 | } 540 | } 541 | | func_call operator expr 542 | { 543 | $$ = new Node; 544 | $$->attr["type"] = "ERROR"; 545 | if ($1->attr["type"] != $3->attr["type"]) { 546 | cout << "Error: Type mismatch for operator " << $1 << endl; 547 | } 548 | else{ 549 | $$->attr["type"] = $1->attr["type"]; 550 | $$->attr["tempname"] = newTemp($1->attr["type"]); 551 | genCode($$->attr["tempname"] + " = " + $1->attr["tempname"] + " " + $2 + " " + $3->attr["tempname"]); 552 | } 553 | } 554 | | expr comparator expr 555 | { 556 | $$ = new Node; 557 | $$->attr["type"] = "ERROR"; 558 | if ($1->attr["type"] != $3->attr["type"]) { 559 | cout << "Error: Type mismatch for comparator " << $1 << endl; 560 | } 561 | else{ 562 | $$->attr["type"] = "int"; 563 | $$->attr["tempname"] = newTemp($$->attr["type"]); 564 | genCode($$->attr["tempname"] + " = " + $1->attr["tempname"] + " " + $2 + " " + $3->attr["tempname"]); 565 | } 566 | } 567 | ; 568 | 569 | 570 | const : INTEGER {$$ = new Node; $$->attr["type"] = "int"; $$->attr["value"] = $1; $$->attr["tempname"] = $1;} 571 | | REAL {$$ = new Node; $$->attr["type"] = "float"; $$->attr["value"] = $1; $$->attr["tempname"] = $1;} 572 | | CHARACTER {$$ = new Node; $$->attr["type"] = "char"; $$->attr["value"] = $1; $$->attr["tempname"] = $1;} 573 | ; 574 | 575 | 576 | comparator : LTE {$$ =$1;} 577 | | GTE {$$ =$1;} 578 | | EQ {$$ =$1;} 579 | | GT {$$ =$1;} 580 | | LT {$$ =$1;} 581 | ; 582 | 583 | operator : ASTERISK {$$ = $1;} 584 | | PLUS {$$ = $1;} 585 | | MINUS {$$ = $1;} 586 | | DIVIDE {$$ = $1;} 587 | | LEFT_SHIFT {$$ = $1;} 588 | | RIGHT_SHIFT {$$ = $1;} 589 | | AMP {$$ = $1;} 590 | | OR_BIT {$$ = $1;} 591 | | AND_BIT {$$ = $1;} 592 | | AND_EXP {$$ = $1;} 593 | | OR_EXP {$$ = $1;} 594 | ; 595 | 596 | 597 | cond_stmt : ifexp stmt n ELSE m stmt 598 | { 599 | $$ = new Node; 600 | backpatch($1->attr_list["falselist"], stoi($5->attr["quad"])); 601 | vector *v = $2->attr_list["next"]; 602 | v->insert(v->end(), $6->attr_list["next"]->begin(), $6->attr_list["next"]->end()); 603 | v->insert(v->end(), $3->attr_list["next"]->begin(), $3->attr_list["next"]->end()); 604 | 605 | $$->attr_list["next"] = v; 606 | } 607 | | ifexp stmt p %prec _THEN_ 608 | { 609 | $$ = new Node; 610 | vector *v = $2->attr_list["next"]; 611 | v->insert(v->end(), $1->attr_list["falselist"]->begin(), $1->attr_list["falselist"]->end()); 612 | 613 | $$->attr_list["next"] = v; 614 | } 615 | 616 | 617 | ; 618 | 619 | ifexp : IF LP expr RP 620 | { 621 | $$ = new Node; 622 | $$->attr_list["falselist"] = makelist(); 623 | $$->attr_list["falselist"]->push_back(next_quad); 624 | genCode("if ("+$3->attr["tempname"]+" == 0) goto _"); 625 | } 626 | 627 | ; 628 | 629 | n : 630 | { 631 | $$ = new Node; 632 | $$->attr_list["next"] = makelist(); 633 | $$->attr_list["next"]->push_back(next_quad); 634 | 635 | genCode("goto _"); 636 | } 637 | ; 638 | 639 | m : { 640 | $$ = new Node; 641 | $$->attr["quad"] = to_string(next_quad); 642 | 643 | } 644 | ; 645 | p : 646 | ; 647 | 648 | while_stmt : while_exp stmt 649 | { 650 | $$ = new Node; 651 | $$->attr_list["next"] = $1->attr_list["falselist"]; 652 | string while_begin = $1->attr["begin"]; 653 | backpatch($2->attr_list["next"], stoi(while_begin)); 654 | genCode("goto " + while_begin); 655 | } 656 | ; 657 | 658 | while_exp : WHILE m LP expr RP 659 | { 660 | $$ = new Node; 661 | $$->attr["begin"] = $2->attr["quad"]; 662 | $$->attr_list["falselist"] = makelist(); 663 | $$->attr_list["falselist"]->push_back(next_quad); 664 | genCode("if ("+$4->attr["tempname"]+" == 0) goto _"); 665 | } 666 | 667 | 668 | return_stmt : RETURN expr SEMICOLON 669 | { 670 | string ret_type = symtab->func_name_table[active_func_ptr].result_type; 671 | if (ret_type != $2->attr["type"]) { 672 | cout << "Error: Type mismatch: returned value does not match expected return value in " << symtab->func_name_table[active_func_ptr].name<attr["tempname"]); 675 | symtab->func_name_table[active_func_ptr].returned = true; 676 | } 677 | } 678 | | RETURN SEMICOLON 679 | { 680 | string ret_type = symtab->func_name_table[active_func_ptr].result_type; 681 | if (ret_type != "void") { 682 | cout << "Function " << symtab->func_name_table[active_func_ptr].name <<" should not return any values." <func_name_table[active_func_ptr].returned = true; 686 | } 687 | } 688 | ; 689 | 690 | var_type : INT 691 | { 692 | $$ = new Node(); 693 | $$->attr["type"] = $1; 694 | } 695 | | FLOAT 696 | { 697 | $$ = new Node(); 698 | $$->attr["type"] = $1; 699 | } 700 | | CHAR 701 | { 702 | $$ = new Node(); 703 | $$->attr["type"] = $1; 704 | } 705 | ; 706 | 707 | array_elem : ID dims 708 | { 709 | // check if Id exist 710 | // check if dims doesnt have tempname as error 711 | $$ = new Node; 712 | $$->attr["type"] = "ERROR"; 713 | $$->attr["tempname"] = "ERROR"; 714 | bool found_var = false, found_param = false; 715 | int vnptr = symtab->search_var($1, active_func_ptr, current_level, &found_var); 716 | int pnptr = symtab->search_param($1, &found_param, active_func_ptr); 717 | if (!found_var && !found_param) { 718 | cout << "Error: Variable " << $1 << " not declared in this scope." << endl; 719 | } else { 720 | vector* dim_list; 721 | if (vnptr != -1) { 722 | $$->attr["type"] = symtab->func_name_table[active_func_ptr].loc_varlist_ptr[vnptr].type; 723 | dim_list = symtab->func_name_table[active_func_ptr].loc_varlist_ptr[vnptr].dimlist_ptr; 724 | } else if (pnptr != -1 ) { 725 | $$->attr["type"] = symtab->func_name_table[active_func_ptr].paramlist_ptr[pnptr].type; 726 | dim_list = symtab->func_name_table[active_func_ptr].paramlist_ptr[pnptr].dimlist_ptr; 727 | } 728 | 729 | if ($2->attr["tempname"] != "ERROR") 730 | { 731 | string addr_str = newTemp($$->attr["type"]+"*"); 732 | genCode(addr_str+" = addr("+$1+")"); 733 | 734 | $$->attr["tempname"] = newTemp($$->attr["type"]); 735 | genCode($$->attr["tempname"]+" = "+addr_str+"["+$2->attr["tempname"]+"]"); 736 | string type = $$->attr["type"]; 737 | backpatch($2->attr_list["type_offset"],sizes[type]); 738 | for (int i = 0; i < dim_list->size(); ++i) 739 | { 740 | if (i < $2->attr_list["dim_offset"]->size()) 741 | { 742 | string replacent = to_string((*dim_list)[i]); 743 | int quad_number = (*($2->attr_list["dim_offset"]))[i]; 744 | substitute(quad_number,replacent); 745 | } 746 | 747 | } 748 | } 749 | 750 | 751 | } 752 | 753 | } 754 | ; 755 | 756 | dims : LEFT_SQ_BRACKET expr RIGHT_SQ_BRACKET 757 | { 758 | $$ = new Node; 759 | $$->attr_list["type_offset"] = makelist(); 760 | $$->attr_list["dim_offset"] = makelist(); 761 | if ($2->attr["type"]!="int") 762 | { 763 | cout << "Error: Dimension should be an integer" << endl; 764 | $$->attr["tempname"] = "ERROR"; 765 | } 766 | else{ 767 | $$->attr["tempname"] = newTemp($2->attr["type"]); 768 | $$->attr_list["type_offset"]->push_back(next_quad); 769 | genCode($$->attr["tempname"] + " = " +$2->attr["tempname"]+" * _"); 770 | 771 | 772 | } 773 | } 774 | | dims LEFT_SQ_BRACKET expr RIGHT_SQ_BRACKET 775 | { 776 | $$ = new Node; 777 | if ($3->attr["type"]!="int" && $1->attr["tempname"]!="ERROR") 778 | { 779 | cout << "Error: Dimension should be an integer" << endl; 780 | $$->attr["tempname"] = "ERROR"; 781 | } 782 | else{ 783 | $$->attr_list["type_offset"] = $1->attr_list["type_offset"]; 784 | $$->attr_list["dim_offset"] = $1->attr_list["dim_offset"]; 785 | $$->attr["tempname"] = newTemp($3->attr["type"]); 786 | string offset1 = newTemp("int"); 787 | string offset2 = newTemp("int"); 788 | $$->attr_list["dim_offset"]->push_back(next_quad); 789 | genCode(offset1+" = "+$1->attr["tempname"]+" * _"); 790 | $$->attr_list["type_offset"]->push_back(next_quad); 791 | genCode(offset2+" = "+$3->attr["tempname"]+" * _"); 792 | genCode($$->attr["tempname"] + " = " +offset1+" + "+offset2); 793 | } 794 | } 795 | ; 796 | 797 | 798 | %% 799 | 800 | int main() { 801 | sizes["int"] = 4; 802 | sizes["char"] = 1; 803 | sizes["float"] = 8; 804 | int global = symtab->add_function("$global",""); 805 | curr_func_stack.push(global); // stores call 806 | yyparse(); 807 | symtab->print_symTable(); 808 | // int f = symtab->insert_function("f1","int"); 809 | // // symtab->insert_function("f2","string"); 810 | // symtab->add_param(f,"p0.1", "int"); 811 | // symtab->add_var(f,"v0.1","int",2); 812 | // symtab->add_var(f,"v0.2","int",2); 813 | // active_func_ptr = f; 814 | // // symtab->print_symTable(); 815 | // symtab->print_funcTable(f); 816 | // list var_list (1,1); 817 | // var_list.push_back(0); 818 | // symtab->patch("float",&var_list); 819 | // symtab->print_funcTable(global); 820 | // symtab->print_funcTable(1); 821 | printThreeAddressCode(); 822 | // while(!curr_func_stack.empty()) { 823 | // cout << curr_func_stack.top() << endl; 824 | // curr_func_stack.pop(); 825 | // } 826 | return 0; 827 | } 828 | 829 | 830 | void yyerror (char *s) {fprintf (stderr, "%s\n\n", s);} 831 | 832 | string newTemp(string type) { 833 | tempList[temp_num++] = type; 834 | return "t" + to_string(temp_num); 835 | } 836 | 837 | void genCode(string s) { 838 | i_code.push_back(s); 839 | next_quad++; 840 | } 841 | 842 | void printThreeAddressCode() { 843 | int i = 0; 844 | for(auto it = i_code.begin(); it != i_code.end(); it++,i++) { 845 | cout << to_string(i) << " " << *it << endl; 846 | } 847 | } 848 | 849 | int increment(string s) { 850 | return stoi(s) + 1; 851 | } 852 | 853 | vector* makelist(){ 854 | return new vector; 855 | } 856 | 857 | void backpatch(vector *list, int quad){ 858 | for (auto it = list->begin(); it!=list->end(); it++) 859 | { 860 | int index = 0; 861 | index = i_code[*it].find("_", index); 862 | if (index == string::npos) continue; 863 | i_code[*it].replace(index,1,to_string(quad)); 864 | } 865 | } 866 | 867 | void substitute(int quad_number, string replacent){ 868 | int index = 0; 869 | index = i_code[quad_number].find("_", index); 870 | if (index == string::npos) return; 871 | i_code[quad_number].replace(index,1,replacent); 872 | return; 873 | } -------------------------------------------------------------------------------- /generate_tokens.py: -------------------------------------------------------------------------------- 1 | out = open('tokens.h','w') 2 | tokens = open('tokens').readlines() 3 | i= 0 4 | for token in tokens: 5 | i += 1 6 | token = token.strip() 7 | out.write("\""+token+"\" \t\t\t\t\tRET(\""+token.upper()+"\", "+token.upper()+")\n") 8 | -------------------------------------------------------------------------------- /input: -------------------------------------------------------------------------------- 1 | int max(int a,int b){ 2 | if ( a > b ){ 3 | return a; 4 | } 5 | return b; 6 | } 7 | 8 | int main(){ 9 | int a, b; 10 | a = 2; 11 | b = 5; 12 | int c; 13 | if ( a > b) { 14 | return b; 15 | while( b > 0 ){ 16 | c = c + a*3; 17 | b = b-1; 18 | } 19 | } 20 | return 0; 21 | } -------------------------------------------------------------------------------- /symtable.h: -------------------------------------------------------------------------------- 1 | class VarNameRecord { 2 | public: 3 | string name, type, var_tag; 4 | int level; 5 | vector* dimlist_ptr; 6 | }; 7 | 8 | class FuncNameRecord { 9 | public: 10 | string name, result_type; 11 | vector paramlist_ptr, loc_varlist_ptr; 12 | int num_params; 13 | bool returned; 14 | }; 15 | 16 | class SymTable { 17 | public: 18 | vector func_name_table; 19 | int search_func(string n, bool* found); 20 | int search_param(string p, bool* found, int fnptr); 21 | int search_var(string v, int fnptr, int l, bool* found); 22 | void print_symTable(); 23 | void print_funcTable(int fnptr); 24 | int add_function(string name, string result_type 25 | ); 26 | int add_param(int fn_ptr, string param_name, string type); 27 | int add_var(int fn_ptr, string var_name, string type, int level, string var_tag, vector *dimlist_ptr); 28 | int patch(string type, list *var_list, int level); 29 | void check_param_type(int call_ptr, int param_num, string type, bool &ok); 30 | }; 31 | 32 | struct Node { 33 | // public: 34 | map attr; 35 | map* > attr_list; 36 | list *namelist; 37 | }; 38 | 39 | SymTable* symtab = new SymTable; 40 | 41 | 42 | int active_func_ptr = 0; // suggest global 43 | int current_level = 0; 44 | int call_name_ptr = 0; 45 | 46 | stack curr_func_stack; 47 | 48 | 49 | /** 50 | * Returns fnptr of the function with name n. 51 | */ 52 | int SymTable::search_func(string n, bool* found) { 53 | *found = false; 54 | 55 | for (int i=0; i<(symtab->func_name_table).size(); i++) { 56 | if (n == symtab->func_name_table[i].name) { 57 | *found = true; 58 | return i; 59 | } 60 | } 61 | 62 | return -1; 63 | } 64 | 65 | /** 66 | * Returns pnptr of the parameter of function fnptr with name p. 67 | */ 68 | int SymTable::search_param(string p, bool* found, int fnptr) { 69 | *found = false; 70 | 71 | for (int i=0; i<(symtab->func_name_table)[fnptr].paramlist_ptr.size();i++) { 72 | if (p == (symtab->func_name_table)[fnptr].paramlist_ptr[i].name) { 73 | *found = true; 74 | return i; 75 | } 76 | } 77 | 78 | return -1; 79 | } 80 | 81 | /** 82 | * Returns vnptr of the variable of function fnptr with name v. 83 | */ 84 | int SymTable::search_var(string v, int fnptr, int l, bool* found) { 85 | *found = false; 86 | int x = symtab->func_name_table[fnptr].loc_varlist_ptr.size(); 87 | for (int i=0; i<(symtab->func_name_table)[fnptr].loc_varlist_ptr.size(); i++) { 88 | if (v == (symtab->func_name_table)[fnptr].loc_varlist_ptr[i].name && l >= (symtab->func_name_table)[fnptr].loc_varlist_ptr[i].level) { 89 | *found = true; 90 | return i; 91 | } 92 | } 93 | 94 | return -1; 95 | } 96 | 97 | 98 | void SymTable::print_symTable(){ 99 | 100 | cout << "Symbol Table" << endl; 101 | for (int i=0; i<(symtab->func_name_table).size(); i++) { 102 | cout << symtab->func_name_table[i].name << "\t" << symtab->func_name_table[i].result_type << "\t" << symtab->func_name_table[i].num_params << endl; 103 | print_funcTable(i); 104 | } 105 | cout << "" << endl; 106 | } 107 | 108 | void SymTable::print_funcTable(int fnptr){ 109 | cout << "\t>>Name: " << symtab->func_name_table[fnptr].name << "\n"; 110 | cout << "\t>>Param count: " << symtab->func_name_table[fnptr].num_params << endl; 111 | cout << "\t>>Params : "; 112 | for (int i = 0; i < (symtab->func_name_table[fnptr].paramlist_ptr).size(); ++i) 113 | { 114 | cout << (symtab->func_name_table[fnptr].paramlist_ptr[i]).name << "("<<(symtab->func_name_table[fnptr].paramlist_ptr[i]).type <<")(" << (symtab->func_name_table[fnptr].paramlist_ptr[i]).level <<") "; 115 | } 116 | cout << endl <<"\t>>Var : "; 117 | auto loc_ptr = symtab->func_name_table[fnptr].loc_varlist_ptr; 118 | for (int i = 0; i < loc_ptr.size(); ++i) 119 | { 120 | cout << (loc_ptr[i]).name << "("<<(loc_ptr[i]).type <<")(" << (loc_ptr[i]).level<<")" << " " << loc_ptr[i].var_tag << " " ; 121 | for(auto it = loc_ptr[i].dimlist_ptr->begin(); it != loc_ptr[i].dimlist_ptr->end(); it++) { 122 | cout << *it << " "; 123 | } 124 | 125 | } 126 | cout << endl; 127 | } 128 | int SymTable::add_function(string name, string result_type) { 129 | int fn_ptr = symtab->func_name_table.size(); 130 | // cout << fn_ptr << endl; 131 | FuncNameRecord fn_record; 132 | fn_record.name = name; 133 | fn_record.result_type = result_type; 134 | fn_record.num_params = 0; 135 | fn_record.returned = false; 136 | symtab->func_name_table.push_back(fn_record); 137 | symtab->func_name_table[fn_ptr].loc_varlist_ptr = symtab->func_name_table[0].loc_varlist_ptr; 138 | return fn_ptr; 139 | } 140 | 141 | int SymTable::add_param(int fn_ptr, string param_name, string type) { 142 | VarNameRecord param; 143 | param.name = param_name; 144 | param.type = type; 145 | // param.var_tag = var_tag; 146 | param.level =1; 147 | symtab->func_name_table[fn_ptr].paramlist_ptr.push_back(param); 148 | symtab->func_name_table[fn_ptr].num_params += 1; 149 | return symtab->func_name_table[fn_ptr].paramlist_ptr.size() - 1; 150 | } 151 | 152 | int SymTable::add_var(int fn_ptr, string var_name, string type, int level, string var_tag, vector *dimlist_ptr) { 153 | VarNameRecord var; 154 | var.name = var_name; 155 | var.type = type; 156 | var.level =level; 157 | var.var_tag = var_tag; 158 | var.dimlist_ptr = dimlist_ptr; 159 | symtab->func_name_table[fn_ptr].loc_varlist_ptr.push_back(var); 160 | return symtab->func_name_table[fn_ptr].loc_varlist_ptr.size() - 1; 161 | } 162 | 163 | 164 | // Patch datatype to the parameter of "active" function 165 | // Returns 1 if success, 0 if fails 166 | int SymTable::patch(string type, list *var_list, int level) { 167 | list::const_iterator iter; 168 | int func_var_count = symtab->func_name_table[active_func_ptr].loc_varlist_ptr.size(); 169 | for (iter = var_list->begin(); iter != var_list->end(); ++iter) { 170 | if (*iter >= func_var_count) 171 | { 172 | return 0; 173 | } 174 | if (level == symtab->func_name_table[active_func_ptr].loc_varlist_ptr[*iter].level) 175 | { 176 | symtab->func_name_table[active_func_ptr].loc_varlist_ptr[*iter].type = type; 177 | } 178 | 179 | } 180 | return 1; 181 | } 182 | 183 | void SymTable::check_param_type(int call_ptr, int param_num, string type, bool &ok) { 184 | if (call_ptr < this->func_name_table.size() && param_num < this->func_name_table[call_ptr].num_params) 185 | { 186 | if(this->func_name_table[call_ptr].paramlist_ptr[param_num - 1].type == type) 187 | ok = true; 188 | else 189 | ok = false; 190 | } 191 | else{ 192 | ok = false; 193 | } 194 | 195 | 196 | } -------------------------------------------------------------------------------- /tokens: -------------------------------------------------------------------------------- 1 | if 2 | else 3 | while 4 | do 5 | for 6 | main 7 | struct 8 | return 9 | default 10 | const 11 | break 12 | continue 13 | goto 14 | void 15 | int 16 | float 17 | char 18 | semicolon 19 | comma 20 | left_sq_bracket 21 | right_sq_bracket 22 | left_curly_bracket 23 | right_curly_bracket 24 | lp 25 | rp 26 | plus 27 | minus 28 | asterisk 29 | divide 30 | dot 31 | dereference 32 | amp 33 | modulo 34 | assign_op 35 | and_exp 36 | or_exp 37 | not_exp 38 | right_shift 39 | left_shift 40 | and_bit 41 | or_bit 42 | lt 43 | gt 44 | eq 45 | lte 46 | gte 47 | integer 48 | char 49 | string 50 | float 51 | id -------------------------------------------------------------------------------- /tokens.h: -------------------------------------------------------------------------------- 1 | "if" RET("IF", IF) 2 | "else" RET("ELSE", ELSE) 3 | "while" RET("WHILE", WHILE) 4 | "do" RET("DO", DO) 5 | "for" RET("FOR", FOR) 6 | "main" RET("MAIN", MAIN) 7 | "struct" RET("STRUCT", STRUCT) 8 | "return" RET("RETURN", RETURN) 9 | "default" RET("DEFAULT", DEFAULT) 10 | "const" RET("CONST", CONST) 11 | "break" RET("BREAK", BREAK) 12 | "continue" RET("CONTINUE", CONTINUE) 13 | "goto" RET("GOTO", GOTO) 14 | "void" RET("VOID", VOID) 15 | "int" RET("INT", INT) 16 | "float" RET("FLOAT", FLOAT) 17 | "char" RET("CHAR", CHAR) 18 | "semicolon" RET("SEMICOLON", SEMICOLON) 19 | "comma" RET("COMMA", COMMA) 20 | "left_sq_bracket" RET("LEFT_SQ_BRACKET", LEFT_SQ_BRACKET) 21 | "right_sq_bracket" RET("RIGHT_SQ_BRACKET", RIGHT_SQ_BRACKET) 22 | "left_curly_bracket" RET("LEFT_CURLY_BRACKET", LEFT_CURLY_BRACKET) 23 | "right_curly_bracket" RET("RIGHT_CURLY_BRACKET", RIGHT_CURLY_BRACKET) 24 | "lp" RET("LP", LP) 25 | "rp" RET("RP", RP) 26 | "plus" RET("PLUS", PLUS) 27 | "minus" RET("MINUS", MINUS) 28 | "asterisk" RET("ASTERISK", ASTERISK) 29 | "divide" RET("DIVIDE", DIVIDE) 30 | "dot" RET("DOT", DOT) 31 | "dereference" RET("DEREFERENCE", DEREFERENCE) 32 | "amp" RET("AMP", AMP) 33 | "modulo" RET("MODULO", MODULO) 34 | "assign_op" RET("ASSIGN_OP", ASSIGN_OP) 35 | "and_exp" RET("AND_EXP", AND_EXP) 36 | "or_exp" RET("OR_EXP", OR_EXP) 37 | "not_exp" RET("NOT_EXP", NOT_EXP) 38 | "right_shift" RET("RIGHT_SHIFT", RIGHT_SHIFT) 39 | "left_shift" RET("LEFT_SHIFT", LEFT_SHIFT) 40 | "and_bit" RET("AND_BIT", AND_BIT) 41 | "or_bit" RET("OR_BIT", OR_BIT) 42 | "lt" RET("LT", LT) 43 | "gt" RET("GT", GT) 44 | "eq" RET("EQ", EQ) 45 | "lte" RET("LTE", LTE) 46 | "gte" RET("GTE", GTE) 47 | "integer" RET("INTEGER", INTEGER) 48 | "char" RET("CHAR", CHAR) 49 | "string" RET("STRING", STRING) 50 | "float" RET("FLOAT", FLOAT) 51 | "id" RET("ID", ID) 52 | --------------------------------------------------------------------------------