├── .gitignore ├── LICENSE ├── Makefile ├── README.md ├── defs.h ├── parser.y ├── scanner.l ├── semantic.c ├── semantic.h ├── symtab.c ├── symtab.h ├── test.txt └── translator.c /.gitignore: -------------------------------------------------------------------------------- 1 | .vagrant/* 2 | .vagrant 3 | .vagrant/ 4 | /.vagrant 5 | /.vagrant/ 6 | a.out 7 | testerr1.c 8 | y.output 9 | y.tab.c 10 | y.tab.h 11 | *.bin 12 | 13 | \.vscode/ipch/d14b84be07b9b87/translator\.ipch 14 | 15 | lex\.yy\.c 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Nikola Trivić 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | COMPILER_BUILD = lex.yy.c y.tab.c symtab.c semantic.c 2 | COMPILER_DEPENDS = $(COMPILER_BUILD) defs.h 3 | COMPILER_CLEAN = lex.yy.c y.tab.c y.tab.h y.output a.out *.?~ 4 | 5 | LEX_SRC = scanner.l 6 | YACC_SRC = parser.y 7 | 8 | .PHONY: clean 9 | .PHONY: test 10 | 11 | a.out: $(COMPILER_DEPENDS) 12 | gcc -o $@ $(COMPILER_BUILD) 13 | 14 | lex.yy.c: $(LEX_SRC) y.tab.c 15 | lex -I $< 16 | 17 | y.tab.c: $(YACC_SRC) 18 | bison -dy -v $< 19 | 20 | clean: 21 | rm -f $(COMPILER_CLEAN) 22 | 23 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Mini Java Compiler # 2 | 3 | Mini Java compiler implemented using Lex and Yacc 4 | 5 | To build compiler you need to call make script **make**. 6 | Flex and Bison must be installed before running make script! 7 | 8 | Output of make script is compiler executable file "a.out". 9 | To run compiler execute **./a.out sourceFile**. 10 | -------------------------------------------------------------------------------- /defs.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef DEFS_H 3 | #define DEFS_H 4 | 5 | #define bool int 6 | #define TRUE 1 7 | #define FALSE 0 8 | 9 | #define SYMBOL_TABLE_LENGTH 64 10 | 11 | #define NO_ATTRIBUTE -1 12 | #define NO_LEVEL -2 13 | #define NO_CLASS_ID -3 14 | 15 | //tipovi podataka (moze ih biti maksimalno 8) 16 | enum { NO_TYPE, INT_TYPE, UNSIGNED_TYPE }; 17 | 18 | // vrste simbola (moze ih biti maksimalno 32) 19 | enum { CONSTANT = 0x1, WORKING_REGISTER = 0x2, VARIABLE = 0x4, METHOD = 0x8, CLASS=0x10}; 20 | 21 | static char *symbol_kinds[] = { "CONSTANT","WORKING_REGISTER", "VARIABLE", "METHOD","CLASS" }; 22 | 23 | //konstante relacionih operatora 24 | enum { LT, GT, LE, GE, EQ, NE }; 25 | 26 | 27 | #define FUNCTION_REGISTER 13 28 | #define TYPE_BIT_SIZE 16 29 | #define CHAR_BUFFER_LENGTH 128 30 | 31 | //pomocni makroi za ispis 32 | #define printerror(args...) sprintf(char_buffer, args), yyerror(char_buffer) 33 | #define printwarning(args...) sprintf(char_buffer, args), warning(char_buffer) 34 | extern int yyerror(char *s); 35 | extern void warning(char *s); 36 | extern char char_buffer[CHAR_BUFFER_LENGTH]; 37 | 38 | #endif 39 | -------------------------------------------------------------------------------- /parser.y: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | #include 4 | #include "defs.h" 5 | #include "translator.c" 6 | #include "symtab.h" 7 | #include "semantic.h" 8 | 9 | #define YYSTYPE char* 10 | 11 | int yyparse(void); 12 | int yylex(void); 13 | int yyerror(char *s); 14 | 15 | 16 | int class_id = -1; 17 | int designator_class_id = -1; 18 | extern int line; 19 | int level = 0; 20 | char* type; 21 | extern FILE * yyin; 22 | int error_count = 0; 23 | FILE *fp; 24 | int function_index = -1; 25 | char* function_type; 26 | char* glob_designator = NULL; 27 | int par_num = 0; 28 | char* ex_type = NULL; 29 | int if_or_while = 0; 30 | int arg_num = 0; 31 | int function_call_index = -1; 32 | int glob_designator_id=-1; 33 | char* to_assign_type=NULL; 34 | int to_assign_id=-1; 35 | int return_called=0; 36 | %} 37 | 38 | %token _TYPE 39 | %token _IF 40 | %token _ELSE 41 | %token _RETURN 42 | %token _ID 43 | %token _INT_NUMBER 44 | %token _UNSIGNED_NUMBER 45 | %token _LPAREN 46 | %token _RPAREN 47 | %token _COMMA 48 | %token _LBRACKET 49 | %token _RBRACKET 50 | %token _ASSIGN 51 | %token _SEMICOLON 52 | %token _PLUS 53 | %token _MINUS 54 | %token _TIMES 55 | %token _DIV 56 | %token _MOD 57 | %token _RELOP 58 | %token _INCLUDE 59 | %token _CHAR 60 | %token _REAL 61 | %token _STRING 62 | %token _VOJD 63 | %token _WHILE 64 | %token _SCANF 65 | %token _APERSANT 66 | %token _PRINTF 67 | %token _ARRAY_VALUE 68 | %token _SWITCH 69 | %token _COLON 70 | %token _BREAK 71 | %token _RSQUARE_BRACKET 72 | %token _AND 73 | %token _OR 74 | %token _NOT 75 | %token _NOTB 76 | %token _ORB 77 | %token _PLUS_PLUS 78 | %token _MINUS_MINUS 79 | %token _PROGRAM 80 | %token _NEW 81 | %token _READ 82 | %token _CLASS 83 | %token _CONST 84 | %token _EXTENDS 85 | %token _FALSE 86 | %token _TRUE 87 | %token _DOT 88 | %token _POINT_ID 89 | %token _LSQUARE_BRACKET 90 | %token _NULL 91 | %token _START_METHOD_DECL 92 | 93 | %% 94 | program 95 | : _PROGRAM _ID { 96 | insert_symbol("eol", METHOD, "char", 0, -1); 97 | set_attribute(0, 0); 98 | 99 | insert_symbol("ord", METHOD, "int", 0, -1); 100 | set_param_type(1, 1, "char"); 101 | set_attribute(1, 1); 102 | 103 | insert_symbol("chr", METHOD, "char", 0, -1); 104 | set_param_type(2, 1, "int"); 105 | set_attribute(2, 1); 106 | 107 | insert_symbol("len", METHOD, "int", 0, -1); 108 | set_param_type(3, 1, "string"); 109 | set_attribute(3, 1); 110 | } 111 | allDeclarations _LBRACKET methodDeclarations _RBRACKET { 112 | check_main(); print_symtab();} 113 | ; 114 | 115 | allDeclarations 116 | : allDeclarations allDeclaration 117 | | 118 | ; 119 | 120 | 121 | allDeclaration 122 | : classDeclaration {} 123 | | varDeclaration {} 124 | | constDeclaration {} 125 | ; 126 | 127 | varDeclarations 128 | : varDeclarations varDeclaration 129 | | { } 130 | ; 131 | 132 | 133 | varDeclaration 134 | : type{ 135 | if (check_type_existance($1) == 1) type = $1; 136 | else { 137 | printf("Line: %d: Type does not exist", line); 138 | type = ""; 139 | } 140 | } 141 | var_enumeration _SEMICOLON 142 | ; 143 | 144 | classVarDeclarationsAndMethods 145 | : varDeclarations varDeclaration methodDeclarations 146 | | 147 | ; 148 | 149 | constDeclaration 150 | : _CONST type {type = $2; if(check_primitive_type($2) == -1) printf("Line: %d : Invalid constant type!\n", line); } clist _SEMICOLON 151 | ; 152 | 153 | clist 154 | : _ID _ASSIGN constvalue {if(strcmp(type, $3) != 0) printf("Line: %d : Invalid assignment!\n", line); 155 | try_to_insert_constant($1, type);} 156 | | clist _COMMA _ID _ASSIGN constvalue {if(strcmp(type, $5) != 0) printf("Line: %d : Invalid assignment!\n", line); 157 | try_to_insert_constant($3, type);} 158 | ; 159 | 160 | type 161 | : _TYPE 162 | | _ID 163 | ; 164 | 165 | classDeclaration 166 | : _CLASS _ID _EXTENDS _ID { 167 | class_id = register_class($2, $4); 168 | if (class_id != -1) level = 1 ; 169 | else class_id = -11; 170 | } 171 | _LBRACKET varDeclarations methodDeclarations 172 | _RBRACKET { 173 | class_id = -1; 174 | level = 0; 175 | } 176 | | _CLASS _ID _LBRACKET { 177 | class_id = register_class($2, NULL); 178 | if (class_id != -1) level = 1 ; 179 | else class_id = -11; 180 | } 181 | varDeclarations methodDeclarations _RBRACKET { 182 | class_id = -1; 183 | level = 0; 184 | } 185 | ; 186 | 187 | methodDeclarations 188 | : _START_METHOD_DECL{ 189 | function_index = insert_method(parse_method_name($1), class_id, parse_method_type($1), level); 190 | level++; 191 | } 192 | formParams { 193 | set_attribute(function_index, par_num); 194 | par_num=0; 195 | } 196 | _RPAREN varDeclarations _LBRACKET statements _RBRACKET { 197 | level--; 198 | if(strcmp(get_type(function_index),"void") != 0 && return_called <=0) 199 | printf("Line: %d: Method does not have a return call\n",line); 200 | if (function_index != -1) 201 | if (function_index != get_last_element() ) 202 | clear_symbols(function_index+1); 203 | function_index = -1; 204 | return_called=0; 205 | } 206 | methodDeclarations 207 | | 208 | ; 209 | 210 | formParams 211 | : arguments 212 | | 213 | ; 214 | 215 | arguments 216 | : type arrayOrId { 217 | if (function_index != -1){ 218 | if (check_type_existance($1) == 1){ 219 | int index; 220 | index = push_array_or_id($2, $1, class_id, level); 221 | set_initialized(index,1); 222 | par_num++; 223 | set_param_type(function_index, par_num, get_type(index)); 224 | }else{ // ne valja nam type argumenta pa brisemo sve prethodne i metodu 225 | clear_symbols(function_index); 226 | function_index = -1; //OOOOOOOOVOOOOOOOOO DOOOOOOOOOBROOOOOOO TESTIRATIIIIIIIIIII 227 | } 228 | } 229 | } 230 | | arguments _COMMA type arrayOrId { 231 | if (function_index != -1){ 232 | if (check_type_existance($3) == 1){ 233 | int index; 234 | index = push_array_or_id($4, $3, class_id, level); 235 | set_initialized(index,1); 236 | par_num++; 237 | set_param_type(function_index, par_num, get_type(index)); 238 | }else{ // ne valja nam type argumenta pa brisemo sve prethodne i metodu 239 | clear_symbols(function_index); 240 | function_index = -1; //OOOOOOOOVOOOOOOOOO DOOOOOOOOOBROOOOOOO TESTIRATIIIIIIIIIII 241 | } 242 | } 243 | } 244 | ; 245 | 246 | methodType 247 | : type 248 | | _VOJD 249 | ; 250 | 251 | var_enumeration 252 | : var_enumeration _COMMA arrayOrId { 253 | if (strcmp(type, "") != 0) 254 | push_array_or_id($3, type, class_id, level); 255 | 256 | } 257 | | arrayOrId { 258 | if (strcmp(type, "") != 0) 259 | push_array_or_id($1, type, class_id, level); 260 | } 261 | ; 262 | 263 | arrayOrId 264 | : _ID {$$ = $1;} 265 | | _ARRAY_VALUE _RSQUARE_BRACKET {$$ = strcat($1, $2);} 266 | ; 267 | 268 | designator 269 | : _ID { 270 | glob_designator = $1; 271 | designator_class_id = class_id; 272 | if((glob_designator_id=lookup_id_in_class_var(glob_designator,class_id))==-1) 273 | if((glob_designator_id=lookup_id(glob_designator,VARIABLE,0)) !=-1 || (glob_designator_id=lookup_id(glob_designator,METHOD,0)) !=-1){ 274 | designator_class_id=-1; 275 | } 276 | } 277 | designatorExt 278 | | _ARRAY_VALUE { 279 | glob_designator = $1; 280 | designator_class_id = class_id; 281 | if((glob_designator_id=lookup_id_in_class_var(glob_designator,class_id)) == -1) 282 | if((glob_designator_id=lookup_id(glob_designator,VARIABLE,0)) != -1 || (glob_designator_id=lookup_id(glob_designator,METHOD,0)) !=-1){ 283 | designator_class_id = -1; 284 | } 285 | } 286 | expression _RSQUARE_BRACKET designatorExt 287 | ; 288 | 289 | designatorExt 290 | : _POINT_ID{ 291 | int index; 292 | int glob_designator_index; 293 | //printf("Id: %d\n",glob_designator_id); 294 | if(glob_designator_id != -1){ 295 | if ((index = check_if_class_instance(glob_designator, get_class_id(glob_designator_id))) != -1){ 296 | glob_designator_index = lookup_var_in_class(glob_designator, designator_class_id); 297 | if(is_initialized(glob_designator_index) == -1) { 298 | printf("Line: %d: %s is not initialized!\n", line, glob_designator); 299 | } 300 | glob_designator = $1 + 1; 301 | designator_class_id = index; 302 | } 303 | } 304 | else{ 305 | printf("Line: %d: %s does not exist\n",line, glob_designator); 306 | designator_class_id=-1; 307 | } 308 | } 309 | | _LSQUARE_BRACKET expression _RSQUARE_BRACKET{ 310 | strcat(glob_designator,"["); 311 | } 312 | | designatorExt _POINT_ID{ 313 | int index; 314 | int glob_designator_index; 315 | if ((index = check_if_class_instance(glob_designator, designator_class_id)) != -1){ 316 | glob_designator_index = lookup_var_in_class(glob_designator, designator_class_id); 317 | if(is_initialized(glob_designator_index) == -1) { 318 | printf("Line: %d: %s is not initialized!\n", line, glob_designator); 319 | } 320 | glob_designator = $2 + 1; 321 | designator_class_id = index; 322 | //printf("glob_designator: %s\n",glob_designator); 323 | } 324 | } 325 | | designatorExt _LSQUARE_BRACKET expression _RSQUARE_BRACKET { 326 | strcat(glob_designator,"["); 327 | } 328 | | 329 | ; 330 | 331 | statement 332 | : designator {to_assign_type = glob_designator; to_assign_id = designator_class_id;}_ASSIGN 333 | expression _SEMICOLON { 334 | //printf("What id is it: %d\n",to_assign_id); 335 | char* designator_type= get_designator_type(to_assign_type,to_assign_id); 336 | //printf("Type 1: %s vs Type 2: *%s*\n",designator_type,$4); 337 | if(designator_type!=NULL){ 338 | if(get_kind(lookup_var_in_class(to_assign_type,to_assign_id)) == VARIABLE) { 339 | char *new = malloc(5); 340 | new=strncpy(new,$4,4); 341 | if(strcmp(new,"new ")==0){ 342 | if(strcmp(designator_type,$4+4)!=0){ 343 | printf("Line: %d: Wrong assignment type\n",line); 344 | } 345 | else set_initialized(lookup_var_in_class(to_assign_type,to_assign_id), 1); 346 | } 347 | else{ 348 | if(strcmp(designator_type,"int") != 0 && strcmp(designator_type,"char") != 0 && strcmp(designator_type,"bool") != 0){ 349 | if(strcmp(designator_type, $4) != 0 && strcmp($4,"null") != 0){ 350 | if(strcmp(designator_type,"char[]")!=0 || strcmp($4,"string")!=0) 351 | printf("Line: %d: Wrong assignment type!\n", line); 352 | else set_initialized(lookup_var_in_class(to_assign_type,to_assign_id), 1); 353 | } 354 | else set_initialized(lookup_var_in_class(to_assign_type,to_assign_id), 1); 355 | } 356 | else{ 357 | if(strcmp(designator_type, $4) != 0) 358 | printf("Line: %d: Wrong assignment type!\n", line); 359 | else set_initialized(lookup_var_in_class(to_assign_type,to_assign_id), 1); 360 | } 361 | } 362 | }else { 363 | printf("Line: %d: Can not assign a value to a method!\n", line); 364 | } 365 | } 366 | } 367 | | designator { 368 | char* designator_type = get_designator_type(glob_designator,designator_class_id); 369 | int index; 370 | if(designator_type != NULL) { 371 | if(get_kind(index = lookup_var_in_class(glob_designator, designator_class_id)) == METHOD){ 372 | function_call_index = index; 373 | } else 374 | printf("Line: %d: %s is not a method!\n", line, glob_designator); 375 | } 376 | } 377 | _LPAREN actParams {arg_num = 0;} _RPAREN _SEMICOLON 378 | 379 | | designator _PLUS_PLUS _SEMICOLON { 380 | int index; 381 | char* designator_type = get_designator_type(glob_designator,designator_class_id); 382 | if(get_kind(index = lookup_var_in_class(glob_designator, designator_class_id)) == VARIABLE){ 383 | if(strcmp(designator_type, "int") == 0) { 384 | if(is_initialized(index) == -1) 385 | printf("Line: %d: %s is not initialized!\n", line, glob_designator); 386 | }else { 387 | printf("Line: %d: %s is not an integer!\n", line, glob_designator); 388 | } 389 | }else { 390 | printf("Line: %d: %s is not a variable!\n", line, glob_designator); 391 | } 392 | } 393 | 394 | | designator _MINUS_MINUS _SEMICOLON { 395 | int index; 396 | char* designator_type = get_designator_type(glob_designator,designator_class_id); 397 | if(get_kind(index = lookup_var_in_class(glob_designator, designator_class_id)) == VARIABLE){ 398 | if(strcmp(designator_type, "int") == 0) { 399 | if(is_initialized(index) == -1) 400 | printf("Line: %d: %s is not initialized!\n", line, glob_designator); 401 | }else { 402 | printf("Line: %d: %s is not an integer!\n", line, glob_designator); 403 | } 404 | }else { 405 | printf("Line: %d: %s is not a variable!\n", line, glob_designator); 406 | } 407 | } 408 | | _IF _LPAREN condition _RPAREN {if_or_while++; } statement {if_or_while--; } //resen 409 | | _IF _LPAREN condition _RPAREN {if_or_while++; } statement _ELSE statement {if_or_while--; } //resen 410 | | _WHILE _LPAREN condition _RPAREN {if_or_while++; } statement {if_or_while--; } //resen 411 | | _BREAK { 412 | if(if_or_while <= 0) { 413 | printf("Line: %d: Break can not be placed here!\n", line); 414 | } 415 | } 416 | _SEMICOLON 417 | | _RETURN _SEMICOLON { 418 | if(strcmp("void", get_type(function_index)) != 0){ 419 | printf("Line: %d: Function has to return %s\n",line, get_type(function_index)); 420 | } 421 | } 422 | | _RETURN expression 423 | { 424 | if(strcmp(get_type(function_index), $2) != 0) { 425 | if(strcmp(get_type(function_index), "void") == 0) 426 | printf("Line: %d: Function does not have a return type\n", line); 427 | else 428 | printf("Line: %d: Function has to return %s \n", line, get_type(function_index)); 429 | 430 | } 431 | return_called++; 432 | } 433 | _SEMICOLON 434 | | _READ _LPAREN designator{ 435 | char* designator_type = get_designator_type(glob_designator,designator_class_id); 436 | if(get_kind(lookup_var_in_class(glob_designator, designator_class_id)) != VARIABLE) { 437 | printf("Line: %d: A value cannot be assigned to a method\n", line); 438 | } 439 | } _RPAREN _SEMICOLON 440 | | _PRINTF _LPAREN expression { 441 | if (check_primitive_type($3) == -1){ 442 | printf("Line: %d: Only primitive types can be printed\n", line); 443 | } 444 | } _RPAREN _SEMICOLON 445 | | _PRINTF _LPAREN expression{ 446 | if (check_primitive_type($3) == -1) 447 | printf("Line: %d: Only primitive types can be printed\n", line); 448 | } _COMMA _INT_NUMBER _RPAREN _SEMICOLON 449 | | _LBRACKET {level++;} 450 | statements _RBRACKET {level--;} 451 | ; 452 | 453 | statements 454 | : statements statement 455 | | 456 | ; 457 | 458 | condition 459 | : conditionTerm orConditionTerms 460 | ; 461 | 462 | orConditionTerms 463 | : _OR conditionTerm 464 | | orConditionTerms _OR conditionTerm 465 | | 466 | ; 467 | 468 | conditionTerm 469 | : conditionFactor andConditionFactors 470 | ; 471 | 472 | 473 | andConditionFactors 474 | : _AND conditionFactor 475 | | andConditionFactors _AND conditionFactor 476 | | 477 | ; 478 | 479 | conditionFactor 480 | : expression { 481 | if(strcmp($1,"bool")!=0){ 482 | printf("Line: %d: Expression is not a boolean type\n",line); 483 | } 484 | } 485 | | expression _RELOP expression{ 486 | if(strcmp($1,$3)!=0){ 487 | printf("Line: %d: Types not compatible\n",line); 488 | } 489 | } 490 | ; 491 | 492 | 493 | expression 494 | : _MINUS term addopTerms { 495 | if($3[0]!=' ') 496 | if(strcmp($2,$3+1)==0){ 497 | if($3[0]=='+'){ 498 | if(strcmp($2,"int")!=0 && strcmp($2,"string")!=0) 499 | printf("Line: %d: Not integers or strings\n",line); 500 | } 501 | else{ 502 | if(strcmp($2,"int")!=0) 503 | printf("Line: %d: Not integers\n",line); 504 | } 505 | } 506 | else{ 507 | printf("Line: %d: Types not compatible\n",line); 508 | } 509 | $$=$2; 510 | } 511 | | term addopTerms { 512 | //printf("Usli smo u expression, $1(term): %s $2(addopTerms): %s\n", $1, $2); 513 | if($2[0]!=' ') 514 | if(strcmp($1,$2+1)==0){ 515 | if($2[0]=='+'){ 516 | if(strcmp($1,"int")!=0 && strcmp($1,"string")!=0) 517 | printf("Line: %d: Not integers or strings\n",line); 518 | } 519 | else{ 520 | if(strcmp($1,"int")!=0) 521 | printf("Line: %d: Not integers\n",line); 522 | } 523 | } 524 | else{ 525 | printf("Line: %d: Types not compatible\n",line); 526 | } 527 | //printf("Ne izadje bre\n"); 528 | $$=$1; 529 | //printf("Line: %d: Jel stvarno %s\n",line,$1); 530 | } 531 | ; 532 | 533 | term 534 | : factor mulopFactors { 535 | //printf("Usli smo u term, $1(factor): %s $2(mulopFactor): *%s*\n", $1, $2); 536 | if($2[0]!=' ') 537 | if(strcmp($1,$2)==0){ 538 | if(strcmp($1,"int")!=0) 539 | printf("Line: %d: Not integers\n",line); 540 | } 541 | else{ 542 | printf("Line: %d: Types not compatible\n",line); 543 | } 544 | //printf("Ovaj %s u termu prodje\n",$1); 545 | $$=$1; 546 | } 547 | ; 548 | 549 | mulopFactors 550 | : mulop factor {$$=$2;} 551 | | mulopFactors mulop factor { 552 | if(strcmp($1,$3)==0){ 553 | if(strcmp($1,"int")!=0) 554 | printf("Line: %d: All operands should be integers\n",line); 555 | } 556 | else{ 557 | printf("Line: %d: Types not compatible\n",line); 558 | } 559 | $$=$3; 560 | } 561 | | {$$=" ";} 562 | ; 563 | 564 | mulop 565 | : _DIV 566 | | _MOD 567 | | _TIMES 568 | ; 569 | 570 | addop 571 | : _PLUS 572 | | _MINUS 573 | ; 574 | 575 | 576 | addopTerms 577 | : addop term {$$=strcat($1,$2);} 578 | | addopTerms addop term { 579 | //printf("wdlfhgfehgowefhi\n"); 580 | if(strcmp($1,$3)!=0){ 581 | if(strcmp($2,"+")==0){ 582 | if(strcmp($1,"int")!=0 && strcmp($1,"string")!=0) 583 | printf("Line: %d: Not integers or strings\n",line); 584 | }else{ 585 | if(strcmp($1,"int")!=0) 586 | printf("Line: %d: Not integers\n",line); 587 | } 588 | } 589 | else{ 590 | printf("Line: %d: Types not compatible\n",line); 591 | } 592 | $$=strcat($1,$3); 593 | } 594 | | {$$=" ";} 595 | ; 596 | 597 | 598 | factor 599 | : designator { 600 | char* designator_type; 601 | designator_type = get_designator_type(glob_designator, designator_class_id); 602 | if(designator_type != NULL) { 603 | if(get_kind(lookup_var_in_class(glob_designator, designator_class_id)) == VARIABLE) { 604 | if(is_initialized(lookup_var_in_class(glob_designator, designator_class_id)) == -1) { 605 | printf("Line: %d: %s is not initialized\n",line,glob_designator); 606 | } 607 | $$=designator_type; 608 | } else { 609 | if (glob_designator[strlen(glob_designator)-1] == '[') 610 | glob_designator[strlen(glob_designator)-1] = '\0'; 611 | printf("Line: %d: %s is not a variable!\n", line, glob_designator); 612 | } 613 | } 614 | 615 | } 616 | | designator { 617 | int index; 618 | //printf("Trivicev bug : glob_designator: %s designator_class_id: %d\n",glob_designator, designator_class_id); 619 | char* designator_type = get_designator_type(glob_designator, designator_class_id); 620 | //printf("Line: %d: tip pre %s\n",line,designator_type); 621 | if(designator_type != NULL) { 622 | if(get_kind(index = lookup_var_in_class(glob_designator, designator_class_id)) == METHOD) { 623 | $1=designator_type; 624 | //printf("Line: %d: tip %s\n",line,designator_type); 625 | function_call_index = index; 626 | } else { 627 | if (glob_designator[strlen(glob_designator)-1] == '[') 628 | glob_designator[strlen(glob_designator)-1] = '\0'; 629 | printf("Line: %d: %s is not a method!\n", line, glob_designator); 630 | } 631 | } 632 | 633 | } 634 | _LPAREN actParams{arg_num = 0;} _RPAREN { $$=$1;} 635 | | num { $$=$1; 636 | } 637 | | _NEW type { 638 | //printf("Line %d $2: %s\n", line, $2); 639 | $$ = malloc(100); 640 | strcat($$, "new "); 641 | //printf("WTF\n"); 642 | strcat($$, $2); 643 | //printf("Ispisujem nesto\n"); 644 | 645 | //printf("Line %d $$: %s\n", line, $$); 646 | } 647 | | _NEW _TYPE { 648 | $$ = malloc(100); 649 | strcat($$, "new "); 650 | //printf("WTF\n"); 651 | strcat($$, $2); 652 | } 653 | _LSQUARE_BRACKET expression _RSQUARE_BRACKET 654 | | _NEW _ARRAY_VALUE { 655 | char* type=malloc(strlen($2)+1); 656 | type[strlen($2)]=']'; 657 | $$ = malloc(100); 658 | strcat($$, "new "); 659 | strcat($$,type); 660 | } 661 | expression {} 662 | _RSQUARE_BRACKET 663 | | _LPAREN expression _RPAREN {$$=$2;} 664 | ; 665 | 666 | num 667 | : _INT_NUMBER {$$ = "int";} 668 | | _UNSIGNED_NUMBER {$$ = "int";} 669 | | _CHAR {$$ = "char";} 670 | | _STRING {$$ = "string";} 671 | | _NULL {$$ = "null";} 672 | ; 673 | 674 | constvalue 675 | : num 676 | | _FALSE {$$ = "bool";} 677 | | _TRUE {$$ = "bool";} 678 | ; 679 | 680 | 681 | actParams 682 | :{char* arg = malloc(2); 683 | arg[0]=1; 684 | arg[1]=function_call_index; 685 | $$=arg; 686 | } 687 | expression { 688 | char* tip= malloc(100); 689 | tip = $1; 690 | char* param_type = get_param_type($$[1], $$[0]); 691 | //printf("FUNCTION CALL INDEX1: %d\n", $$[1]); 692 | //printf("Expected type(%d): %s and current type: %s\n",$$[0],get_param_type($$[1],$$[0]),$2); 693 | if(strcmp(param_type,"int") != 0 && strcmp(param_type,"char") != 0 && strcmp(param_type,"bool") != 0){ 694 | if(strcmp(param_type, $2) != 0 && strcmp($2,"null") != 0) { 695 | printf("Line: %d: Incorrect argument type!\n", line); 696 | } 697 | } 698 | else{ 699 | if(strcmp(param_type, $2) != 0) { 700 | printf("Line: %d: Incorrect argument type!\n", line); 701 | } 702 | } 703 | 704 | } 705 | | actParams _COMMA expression { 706 | char* arg = malloc(2); 707 | arg[0]=$1[0]+1; 708 | arg[1]=$1[1]; 709 | $$=arg; 710 | char* tip=$3; 711 | char* param_type=get_param_type($$[1], $$[0]); 712 | //printf("FUNCTION CALL INDEX2: %d\n", $$[1]); 713 | //printf("Expected type(%d): %s and current type: %s\n",$$[0],get_param_type($$[1],$$[0]),$3); 714 | if(strcmp(param_type,"int") != 0 && strcmp(param_type,"char") != 0 && strcmp(param_type,"bool") != 0){ 715 | if(strcmp(param_type, $3) != 0 && strcmp($3,"null") != 0){ 716 | printf("Line: %d: Incorrect argument type!\n", line); 717 | } 718 | } 719 | else{ 720 | if(strcmp(param_type, $3) != 0) { 721 | printf("Line: %d: Incorrect argument type!\n", line); 722 | } 723 | } 724 | } 725 | | 726 | ; 727 | 728 | 729 | %% 730 | 731 | int yyerror(char *s) { 732 | fprintf(stderr, "\nERROR (%d): %s", line, s); 733 | error_count++; 734 | return 0; 735 | } 736 | 737 | int main(int argc, char *argv[]) { 738 | yyin = fopen(argv[1], "r"); 739 | yyparse(); 740 | return error_count; 741 | } 742 | -------------------------------------------------------------------------------- /scanner.l: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | #include "y.tab.h" 4 | 5 | #define YYSTYPE char* 6 | 7 | int line = 1; 8 | %} 9 | 10 | letter [a-zA-Z] 11 | digit [0-9] 12 | 13 | %% 14 | 15 | [ \t\r]+ { /* skip */ } 16 | "."{letter}({letter}|{digit}|"_")* { yylval = strdup(yytext); return _POINT_ID;} 17 | {letter}({letter}|{digit}|"_")*"[" { yylval = strdup(yytext); return _ARRAY_VALUE;} 18 | 19 | "eol" { yylval = strdup(yytext); return _CHAR; } 20 | "switch" { yylval = strdup(yytext); return _SWITCH; } 21 | "void" {yylval = strdup(yytext); return _VOJD;} 22 | "while" { yylval = strdup(yytext); return _WHILE; } 23 | "break" { yylval = strdup(yytext); return _BREAK; } 24 | "null" { yylval = strdup(yytext); return _NULL; } 25 | "print" { yylval = strdup(yytext); return _PRINTF; } 26 | "program" { yylval = strdup(yytext); return _PROGRAM;} 27 | "class" { yylval = strdup(yytext); return _CLASS; } 28 | "const" { yylval = strdup(yytext); return _CONST; } 29 | "new" { yylval = strdup(yytext); return _NEW; } 30 | "read" { yylval = strdup(yytext); return _READ;} 31 | "extends" { yylval = strdup(yytext); return _EXTENDS; } 32 | "false" { yylval = strdup(yytext); return _FALSE; } 33 | "true" { yylval = strdup(yytext); return _TRUE; } 34 | "if" { yylval = strdup(yytext); return _IF; } 35 | "else" { yylval = strdup(yytext); return _ELSE; } 36 | "return" { yylval = strdup(yytext); return _RETURN; } 37 | 38 | ("int"|"void"|"char"|"bool"|"string"|({letter}({letter}|{digit}|"_")*))(" ")+({letter}({letter}|{digit}|"_")*)"(" { yylval = strdup(yytext); return _START_METHOD_DECL;} 39 | "(" {yylval = strdup(yytext); return _LPAREN; } 40 | ")" {yylval = strdup(yytext); return _RPAREN;} 41 | "[" {yylval = strdup(yytext); return _LSQUARE_BRACKET; } 42 | "]" {yylval = strdup(yytext); return _RSQUARE_BRACKET; } 43 | 44 | "." { yylval = strdup(yytext); return _DOT; } 45 | 46 | "string" { yylval = strdup(yytext); return _TYPE; } 47 | "bool" { yylval = strdup(yytext); return _TYPE; } 48 | "int" { yylval = strdup(yytext); return _TYPE; } 49 | "unsigned" { yylval = strdup(yytext); return _TYPE; } 50 | "char" { yylval = strdup(yytext); return _TYPE; } 51 | "double" { yylval = strdup(yytext); return _TYPE; } 52 | "float" { yylval = strdup(yytext); return _TYPE; } 53 | 54 | 55 | "'"."'" { yylval = strdup(yytext); return _CHAR; } 56 | digit*(.digit*)? { yylval = strdup(yytext); return _REAL; } 57 | 58 | {letter}({letter}|{digit}|"_")* { yylval = strdup(yytext); return _ID; } 59 | 60 | {digit}{1,5}[uU] { yylval = strdup(yytext); return _UNSIGNED_NUMBER; } 61 | {digit}{1,5} { yylval = strdup(yytext); return _INT_NUMBER; } 62 | 63 | "~" {yylval = strdup(yytext); return _NOTB;} 64 | "&&" {yylval = strdup(yytext); return _AND;} 65 | "||" {yylval = strdup(yytext); return _OR;} 66 | "|" {yylval = strdup(yytext); return _ORB;} 67 | "&" {yylval = strdup(yytext); return _APERSANT; } 68 | "\""[^\"]*"\"" {yylval = strdup(yytext); return _STRING; } 69 | "," {yylval = strdup(yytext); return _COMMA; } 70 | ":" {yylval = strdup(yytext); return _COLON; } 71 | "{" { yylval = strdup(yytext); return _LBRACKET; } 72 | "}" { yylval = strdup(yytext); return _RBRACKET; } 73 | "=" {yylval = strdup(yytext); return _ASSIGN; } 74 | ";" {yylval = strdup(yytext); return _SEMICOLON; } 75 | "++" { yylval = strdup(yytext); return _PLUS_PLUS; } 76 | "--" { yylval = strdup(yytext); return _MINUS_MINUS; } 77 | "+" {yylval = strdup(yytext); return _PLUS; } 78 | "-" {yylval = strdup(yytext); return _MINUS; } 79 | "*" {yylval = strdup(yytext); return _TIMES; } 80 | "/" {yylval = strdup(yytext); return _DIV; } 81 | "%" {yylval = strdup(yytext); return _MOD; } 82 | "<" {yylval = strdup(yytext); return _RELOP; } 83 | ">" {yylval = strdup(yytext); return _RELOP; } 84 | "<=" {yylval = strdup(yytext); return _RELOP; } 85 | ">=" {yylval = strdup(yytext); return _RELOP; } 86 | "==" {yylval = strdup(yytext); return _RELOP; } 87 | "!=" {yylval = strdup(yytext); return _RELOP; } 88 | "!" {yylval = strdup(yytext); return _NOT; } 89 | 90 | 91 | "" 92 | 93 | "#include <"(.*)">" {yylval = strdup(yytext); return _INCLUDE; } 94 | 95 | "/*" { 96 | int in_comment = 1; 97 | char c; 98 | while(in_comment) { 99 | c = input(); 100 | if(c == '*') { 101 | char ch = input(); 102 | if(ch == '/') in_comment = 0; 103 | else unput(ch); 104 | } 105 | else if(c == '\n') line++; 106 | else if(c == EOF) { 107 | printf("\nERROR (%d): Unterminated comment", line); 108 | in_comment = 0; 109 | } 110 | } 111 | } 112 | 113 | \/\/.* { /* skip */ } 114 | 115 | "\n" { line++; } 116 | . { yylval = strdup(yytext); printf("\nLEXICAL ERROR on character %d (line %d)\n", yytext[0], line); } 117 | 118 | %% 119 | 120 | int yywrap() { 121 | return 1; 122 | } 123 | -------------------------------------------------------------------------------- /semantic.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include "semantic.h" 4 | 5 | extern char char_buffer[CHAR_BUFFER_LENGTH]; 6 | extern int line; 7 | 8 | // Proverava da li se ime main nalazi u tabeli simbola ili ne, 9 | // i da li je njen tip 'int'. 10 | void check_main() { 11 | int index; 12 | if((index = lookup_id_strict_kind("main", METHOD, 0)) == -1) 13 | printf("No main!\n"); 14 | else 15 | if(strcmp(get_type(index),"void") != 0) 16 | printf("Return type of 'main' is not void\n"); 17 | } 18 | // Proverava da li su isti tipovi elemenata tabele simbola. 19 | bool check_types(int first_index, int second_index) { 20 | char* t1 = get_type(first_index); 21 | char* t2 = get_type(second_index); 22 | if(strcmp(t1, t2)) 23 | return TRUE; 24 | else 25 | return FALSE; 26 | } 27 | 28 | // Proverava da li n-ti argument po tipu odgovara n-tom parametru funkcije 29 | bool check_argument_type(int function_call_index, int arg_index, int arg_num) { 30 | if(get_param_type(function_call_index, arg_num) == get_type(arg_index)) 31 | return TRUE; 32 | printf("incompatible type for argument %d in '%s'", arg_num, get_name(function_call_index)); 33 | return FALSE; 34 | } 35 | 36 | // Proverava da li broj argumenata poziva funkcije 37 | // odgovara broju parametara funkcije 38 | bool check_arguments_number(int function_call_index, int arg_num) { 39 | if(get_attribute(function_call_index) == arg_num) 40 | return TRUE; 41 | printf("wrong number of arguments to function '%s'", get_name(function_call_index)); 42 | return FALSE; 43 | } 44 | -------------------------------------------------------------------------------- /semantic.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef SEMANTIC_H 3 | #define SEMANTIC_H 4 | 5 | #include 6 | #include 7 | #include "defs.h" 8 | #include "symtab.h" 9 | 10 | 11 | void check_main(void); 12 | int check_types(int first_index, int second_index); 13 | bool check_argument_type(int function_call_index, int arg_index, int arg_num); 14 | bool check_arguments_number(int function_call_index, int arg_num); 15 | 16 | #endif 17 | -------------------------------------------------------------------------------- /symtab.c: -------------------------------------------------------------------------------- 1 | 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "defs.h" 7 | #include "symtab.h" 8 | 9 | #define MAX_UNSIGNED_NUMBER (1L << TYPE_BIT_SIZE) - 1 10 | #define MIN_INT_NUMBER (-(1L << (TYPE_BIT_SIZE - 1))) 11 | #define MAX_INT_NUMBER ((1L << (TYPE_BIT_SIZE - 1)) - 1) 12 | 13 | SYMBOL_ENTRY symbol_table[SYMBOL_TABLE_LENGTH]; 14 | 15 | int first_empty = 0; 16 | extern int line; 17 | 18 | // Vraca indeks prvog sledeceg praznog elementa. 19 | int get_next_empty_element(void) { 20 | if(first_empty < SYMBOL_TABLE_LENGTH) 21 | return first_empty++; 22 | else { 23 | printf("Line: %d : Compiler error! Symbol table overflow!", line); 24 | exit(EXIT_FAILURE); 25 | } 26 | } 27 | 28 | // Vraca indeks poslednjeg zauzetog elementa. 29 | int get_last_element(void) { 30 | return first_empty-1; 31 | } 32 | 33 | // Ubacuje simbol sa datom oznakom simbola i tipom simbola i vraca indeks ubacenog elementa u tabeli simbola ili -1. 34 | int insert_symbol(char *name, unsigned kind, char* type, int level,int class_id) { 35 | int index = get_next_empty_element(); 36 | symbol_table[index].name = name; 37 | symbol_table[index].kind = kind; 38 | symbol_table[index].type = type; 39 | symbol_table[index].level = level; 40 | symbol_table[index].class_id = class_id; 41 | symbol_table[index].initialized = -1; 42 | return index; 43 | } 44 | 45 | char* parse_method_type(char* str){ 46 | int i=0; 47 | char* val=malloc(strlen(str)); 48 | while(str[i]!=' '){ 49 | val[i]=str[i]; 50 | i++; 51 | } 52 | return val; 53 | } 54 | 55 | char* parse_method_name(char* str){ 56 | int i=0; 57 | int j=0; 58 | int max=strlen(str); 59 | char* val=malloc(max); 60 | while(str[i]!=' ') 61 | i++; 62 | while(str[i]==' ') 63 | i++; 64 | while(i MAX_INT_NUMBER) 97 | printf("Line: %d : constant out of range\n", line); 98 | index = insert_symbol(str, CONSTANT, type, 0,-1); 99 | 100 | } 101 | else 102 | printf("Line: %d : redefinition of '%s' \n",line, str); 103 | return index; 104 | } 105 | 106 | void set_initialized(int index, int value) { 107 | if(index > -1 && index < SYMBOL_TABLE_LENGTH) 108 | symbol_table[index].initialized = value; 109 | } 110 | 111 | int is_initialized(int index){ 112 | if(index > -1 && index < SYMBOL_TABLE_LENGTH) 113 | return symbol_table[index].initialized; 114 | return -1; 115 | } 116 | 117 | //Vraca indeks pronadjenog simbola ili vraca -1. 118 | int lookup_global(char* name){ 119 | int i; 120 | for(i =0 ; i < first_empty; i++) { 121 | if(strcmp(symbol_table[i].name, name) == 0 && symbol_table[i].level == 0) 122 | return i; 123 | } 124 | return -1; 125 | } 126 | 127 | 128 | //Vraca pomenljivu 129 | lookup_var_in_class(char* name, int class_id){ 130 | int i; 131 | for(i = first_empty - 1; i >= 0; i--) { 132 | if(strcmp(symbol_table[i].name, name) == 0 && symbol_table[i].class_id == class_id) 133 | return i; 134 | } 135 | return -1; 136 | } 137 | 138 | // 139 | lookup_var_in_scope(char* name, int class_id, int level){ 140 | int i; 141 | for(i = first_empty - 1; i >= 0; i--) { 142 | if(strcmp(symbol_table[i].name, name) == 0 && symbol_table[i].class_id == class_id && symbol_table[i].level == level) 143 | return i; 144 | } 145 | return -1; 146 | } 147 | 148 | // Vraca indeks pronadjenog simbola ili vraca -1. 149 | int lookup_id(char *name, unsigned kind, int level) { 150 | int i; 151 | for(i = first_empty - 1; i >= 0; i--) { 152 | if(strcmp(symbol_table[i].name, name) == 0 && symbol_table[i].level <= level && symbol_table[i].kind == kind) 153 | return i; 154 | /*printf("For %d\n",i); 155 | printf("name: %s, table name: %s\n",name,symbol_table[i].name); 156 | printf("level: %d, table level: %d\n",level,symbol_table[i].level);*/ 157 | } 158 | return -1; 159 | } 160 | 161 | int lookup_id_nokind(char *name, int level) { 162 | int i; 163 | for(i = first_empty - 1; i >= 0; i--) { 164 | if(strcmp(symbol_table[i].name, name) == 0 && symbol_table[i].level <= level) 165 | return i; 166 | } 167 | return -1; 168 | } 169 | 170 | int lookup_id_in_class(char* name, int class_id) { 171 | int i; 172 | for(i = first_empty - 1; i >= 0; i--) { 173 | if(strcmp(symbol_table[i].name, name) == 0 && symbol_table[i].class_id == class_id) 174 | return i; 175 | } 176 | return -1; 177 | } 178 | 179 | int lookup_id_in_class_var(char* name, int class_id) { 180 | int i; 181 | for(i = first_empty - 1; i >= 0; i--) { 182 | if(strcmp(symbol_table[i].name, name) == 0 && symbol_table[i].class_id == class_id && symbol_table[i].kind == VARIABLE) 183 | return i; 184 | } 185 | return -1; 186 | } 187 | 188 | int lookup_id_strict(char *name, int level) { 189 | int i; 190 | for(i = first_empty - 1; i >= 0; i--) { 191 | if((strcmp(symbol_table[i].name, name) == 0) && (symbol_table[i].level == level)){ 192 | //printf("level: %d, level iz tabele: %d \n", level, symbol_table[i].level); 193 | return i; 194 | } 195 | } 196 | return -1; 197 | } 198 | 199 | int lookup_id_strict_by_class(char *name, int level, int class_id) { 200 | int i; 201 | for(i = first_empty - 1; i >= 0; i--) { 202 | if((strcmp(symbol_table[i].name, name) == 0) && (symbol_table[i].level == level) && (symbol_table[i].class_id == class_id)){ 203 | //printf("level: %d, level iz tabele: %d \n", level, symbol_table[i].level); 204 | return i; 205 | } 206 | } 207 | return -1; 208 | } 209 | 210 | int lookup_class_existance(char* name){ 211 | int i; 212 | for(i = first_empty - 1; i >= 0; i--) { 213 | if((strcmp(symbol_table[i].name, name) == 0) && (symbol_table[i].kind == CLASS)){ 214 | return i; 215 | } 216 | } 217 | return -1; 218 | } 219 | 220 | int lookup_id_strict_kind(char *name, unsigned kind, int level) { 221 | int i; 222 | for(i = first_empty - 1; i >= 0; i--) { 223 | if((strcmp(symbol_table[i].name, name) == 0) && (symbol_table[i].level == level) && (symbol_table[i].kind == kind)){ 224 | //printf("level: %d, level iz tabele: %d \n", level, symbol_table[i].level); 225 | return i; 226 | } 227 | } 228 | return -1; 229 | } 230 | 231 | // Vraca indeks pronadjenog simbola (konstante) ili vraca -1. 232 | int lookup_constant(char *name) { 233 | int i; 234 | for(i = first_empty - 1; i >= 0; i--) { 235 | if(strcmp(symbol_table[i].name, name) == 0 && symbol_table[i].kind == CONSTANT) 236 | return i; 237 | } 238 | return -1; 239 | } 240 | 241 | int check_primitive_type(char* type) { 242 | if(strcmp(type, "int") == 0 || strcmp(type, "char") == 0 || strcmp(type, "bool") == 0 || strcmp(type, "string") == 0) 243 | return 1; 244 | else 245 | return -1; 246 | 247 | } 248 | 249 | char *get_name(int index) { 250 | if(index > -1 && index < SYMBOL_TABLE_LENGTH) 251 | return symbol_table[index].name; 252 | return "?"; 253 | } 254 | 255 | unsigned get_kind(int index) { 256 | if(index > -1 && index < SYMBOL_TABLE_LENGTH) 257 | return symbol_table[index].kind; 258 | return 0; 259 | } 260 | 261 | char* get_type(int index) { 262 | if(index > -1 && index < SYMBOL_TABLE_LENGTH) 263 | return symbol_table[index].type; 264 | return ""; 265 | } 266 | 267 | void set_attribute(int index, int attribute) { 268 | if(index > -1 && index < SYMBOL_TABLE_LENGTH) 269 | symbol_table[index].attribute = attribute; 270 | } 271 | 272 | unsigned get_attribute(int index) { 273 | if(index > -1 && index < SYMBOL_TABLE_LENGTH) 274 | return symbol_table[index].attribute; 275 | return NO_ATTRIBUTE; 276 | } 277 | 278 | void set_level(int index, int level) { 279 | if(index > -1 && index < SYMBOL_TABLE_LENGTH) 280 | symbol_table[index].level = level; 281 | } 282 | 283 | int get_level(int index){ 284 | if(index > -1 && index < SYMBOL_TABLE_LENGTH) 285 | return symbol_table[index].level; 286 | return NO_LEVEL; 287 | } 288 | 289 | void set_class_id(int index, int class_id) { 290 | if(index > -1 && index < SYMBOL_TABLE_LENGTH) 291 | symbol_table[index].class_id = class_id; 292 | } 293 | 294 | int get_class_id(int index){ 295 | if(index > -1 && index < SYMBOL_TABLE_LENGTH) 296 | return symbol_table[index].class_id; 297 | return NO_CLASS_ID; 298 | } 299 | 300 | void set_param_type(int index, unsigned number, char* type) { 301 | if(index > -1 && index < SYMBOL_TABLE_LENGTH) { 302 | if(symbol_table[index].param_types == 0) { 303 | symbol_table[index].param_types = malloc(sizeof(char) * PARAM_NUMBER*20); 304 | int i; 305 | for(i = 0; i < PARAM_NUMBER; i++) 306 | symbol_table[index].param_types[i] = ""; 307 | } 308 | if(number > 0 && number <= PARAM_NUMBER) 309 | symbol_table[index].param_types[number - 1] = type; 310 | } 311 | } 312 | 313 | char* get_param_type(int index, unsigned number) { 314 | if(index > -1 && index < SYMBOL_TABLE_LENGTH) 315 | if(symbol_table[index].param_types && number > 0 && number <= PARAM_NUMBER) 316 | return symbol_table[index].param_types[number - 1]; 317 | return " "; 318 | } 319 | 320 | void set_register_type(int register_index, char* type) { 321 | if(register_index >= 0 && register_index <= FUNCTION_REGISTER) 322 | symbol_table[register_index].type = type; 323 | } 324 | 325 | // Brise elemente tabele simbola od pocetnog indeksa do kraja tabele 326 | void clear_symbols(unsigned begin_index) { 327 | int i; 328 | if(begin_index >= first_empty) { 329 | printf("Line: %d : Compiler error! Wrong clear symbols argument\n", line); 330 | exit(EXIT_FAILURE); 331 | } 332 | for(i = begin_index; i < first_empty; i++) { 333 | if(symbol_table[i].name) 334 | free(symbol_table[i].name); 335 | symbol_table[i].name = 0; 336 | symbol_table[i].kind = 0; 337 | symbol_table[i].type = ""; 338 | symbol_table[i].attribute = 0; 339 | if(symbol_table[i].param_types) 340 | free(symbol_table[i].param_types); 341 | symbol_table[i].param_types = 0; 342 | } 343 | first_empty = begin_index; 344 | } 345 | 346 | // Brise sve elemente tabele simbola. 347 | void clear_symtab(void) { 348 | first_empty = SYMBOL_TABLE_LENGTH - 1; 349 | clear_symbols(0); 350 | } 351 | 352 | // Ispisuje sve elemente tabele simbola. 353 | void print_symtab(void) { 354 | int i,j; 355 | printf("\n\nSYMBOL TABLE\n"); 356 | printf("\n name kind type attr p1 p2 p3 p4 p5 p6 p7"); 357 | printf("\n-- ---------------- ---------------- ---- ---- -- -- -- -- --"); 358 | for(i = 0; i < first_empty; i++) { 359 | printf("\n%2d %-16s %16s %16s %4d %4d %4d ", i, 360 | symbol_table[i].name, 361 | symbol_kinds[(int)(logarithm2(symbol_table[i].kind))], 362 | symbol_table[i].type, 363 | symbol_table[i].level, 364 | symbol_table[i].class_id, 365 | symbol_table[i].attribute); 366 | if(symbol_table[i].param_types) { 367 | for(j = 0; j < PARAM_NUMBER; j++) 368 | printf("%s ", symbol_table[i].param_types[j]); 369 | } 370 | else 371 | printf(" -"); 372 | } 373 | printf("\n\n"); 374 | } 375 | 376 | unsigned logarithm2(unsigned value) { 377 | unsigned mask = 1; 378 | int i = 0; 379 | for(i = 0; i < 32; i++) { 380 | if(value & mask) 381 | return i; 382 | mask <<= 1; 383 | } 384 | return 0; // ovo ne bi smelo da se desi; indeksiraj string "NONE" 385 | } 386 | 387 | // Inicijalizacija tabele simbola. 388 | void init_symtab(void) { 389 | clear_symtab(); 390 | 391 | int i = 0; 392 | char s[4]; 393 | for(i = 0; i < 14; i++) { 394 | sprintf(s, "%%%d", i); 395 | insert_symbol(strdup(s), WORKING_REGISTER, NO_TYPE, 0,-1); 396 | } 397 | } 398 | 399 | //=============================================================== 400 | 401 | int push_array_or_id(char* name, char* type, int class_id, int level){ 402 | int index = -1; 403 | char* new_type = malloc(strlen(type)); 404 | strcpy(new_type,type); 405 | if (level > 0 && class_id == -11) return -1; 406 | if (name[strlen(name)-1] == '[') { 407 | name[strlen(name)-1] = '\0'; 408 | strcat(new_type,"[]"); 409 | }else if(name[strlen(name)-1] == ']'){ 410 | name[strlen(name)-2] = '\0'; 411 | strcat(new_type,"[]"); 412 | } 413 | if( (index = lookup_constant(name)) == -1 && (index = lookup_id_strict_by_class(name, level,class_id)) == -1){ 414 | index = insert_symbol(name, VARIABLE, new_type, level,class_id); 415 | //printf("Ubacujem: %s sa levelom: %d \n",name,level); 416 | if(strcmp(new_type, "int") == 0 || strcmp(new_type, "bool") == 0 || strcmp(new_type, "char") == 0) { 417 | set_initialized(index,1); 418 | } 419 | } 420 | else 421 | printf("Line: %d : Redefinition of '%s' \n",line, name); 422 | return index; 423 | } 424 | 425 | int register_class(char* name, char* extends_name){ 426 | int ex_class_check = 1; 427 | if (extends_name != NULL && lookup_class_existance(extends_name) == -1){ 428 | printf("Line: %d: Extended class not existing\n", line); 429 | ex_class_check = 0; 430 | } 431 | if (lookup_global(name) == -1 && ex_class_check){ 432 | int index; 433 | index = insert_symbol(name, CLASS, "class", 0, -1); 434 | if (extends_name != NULL){ 435 | symbol_table[index].attribute = lookup_class_existance(extends_name); 436 | } else 437 | symbol_table[index].attribute = -1; 438 | int this_ind = push_array_or_id("this", name, index, 1); //ubacili this promenljivu za tu klasu i ona je tipa te klase 439 | set_initialized(this_ind,1); 440 | return index; 441 | }else{ 442 | printf("Line: %d: Redefinition of %s\n", line, name); 443 | } 444 | return -1; 445 | } 446 | 447 | int insert_method(char* name, int class_id, char* function_type, int level){ 448 | int index = -1; 449 | if (level > 0 && class_id == -11) return index; 450 | if ((strcmp(function_type,"void") != 0) && (check_type_existance(function_type) == -1)){ 451 | return -1; 452 | } 453 | if (check_method_name(name, class_id) == -1){ 454 | index = insert_symbol(name, METHOD, function_type, level, class_id); 455 | }else{ 456 | printf("Line: %d: Redefinition of %s\n", line, name); 457 | } 458 | return index; 459 | } 460 | 461 | int check_method_name(char* name, int class_id){ 462 | int i; 463 | for(i = first_empty - 1; i >= 0; i--) { 464 | if(strcmp(symbol_table[i].name, name) == 0 && symbol_table[i].level <= get_level(class_id)+1 && 465 | (class_id == symbol_table[i].class_id || symbol_table[i].class_id == -1)){ 466 | return i; 467 | } 468 | } 469 | return -1; 470 | } 471 | 472 | int check_type_existance(char* name){ 473 | int i; 474 | if (check_primitive_type(name) == 1) return 1; 475 | for(i = first_empty - 1; i >= 0; i--) { 476 | if(strcmp(symbol_table[i].name, name) == 0 && symbol_table[i].kind == CLASS) 477 | return 1; 478 | } 479 | printf("Line: %d: Type %s does not exist\n", line, name); 480 | return -1; 481 | } 482 | 483 | int lookup_global_no_class(char* name){ 484 | int i; 485 | for(i =0 ; i < first_empty; i++) { //NISMO SIGURNI ZA OVO, AKO NE VALJA GRIZ i PEDJA SU KRIVI 486 | if(strcmp(symbol_table[i].name, name) == 0 && symbol_table[i].level == 0 && symbol_table[i].kind != CLASS) 487 | return i; 488 | } 489 | return -1; 490 | } 491 | 492 | int check_if_class_instance(char* name, int class_id){ 493 | int index = -1; 494 | while(1){ 495 | index = check_if_class_instance_h(name,class_id); 496 | if (index != -1) 497 | return index; 498 | if (symbol_table[class_id].attribute != -1){ 499 | class_id = symbol_table[class_id].attribute; 500 | } else { 501 | return -1; 502 | } 503 | } 504 | return -1; 505 | } 506 | 507 | int check_if_class_instance_h(char* name, int class_id){ 508 | char* new_name = malloc(strlen(name)); 509 | int class_index; 510 | int index = -1; 511 | if (name[strlen(name)-1] == '['){ 512 | strncpy(new_name,name,strlen(name)-1); 513 | if ((index = lookup_id_in_class(new_name, class_id)) == -1 && (index = lookup_global(new_name)) == -1){ 514 | printf("Line: %d: %s does not exist\n", line, new_name); 515 | }else{ 516 | if (get_kind(index) == VARIABLE){ 517 | char* our_type = malloc(strlen(get_type(index))); 518 | our_type = get_type(index); 519 | if (our_type[strlen(our_type)-1] == ']'){ 520 | char* new_type = malloc(strlen(our_type)); 521 | strncpy(new_type,our_type,strlen(our_type)-2); 522 | if ((class_index = lookup_class_existance(new_type)) != -1){ 523 | return class_index; 524 | }else{ 525 | printf("Line: %d: Variable %s is not an array of instances of class\n", line, new_name); 526 | } 527 | }else{ 528 | printf("Line: %d: %s is not an array\n",line, new_name ); 529 | } 530 | }else{ 531 | printf("Line: %d: %s is not a variable\n", line, new_name); 532 | } 533 | } 534 | } 535 | else{ 536 | strcpy(new_name,name); 537 | if ((index = lookup_id_in_class(new_name, class_id)) == -1 && (index = lookup_global(new_name)) == -1){ 538 | printf("Line: %d: %s does not exist\n", line, new_name); 539 | }else { 540 | if (get_kind(index) == VARIABLE){ 541 | if ((class_index = lookup_class_existance(get_type(index))) != -1){ 542 | return class_index; 543 | }else{ 544 | printf("Line: %d: Variable %s is not an instance of class\n", line, new_name); 545 | } 546 | }else{ 547 | printf("Line: %d: %s is not a variable\n", line, new_name); 548 | } 549 | } 550 | } 551 | return -1; 552 | } 553 | 554 | 555 | int check_if_int(char* name, int class_id){ 556 | char* our_name = name; 557 | int index = -1; 558 | if (our_name[strlen(our_name)-1] == '['){ 559 | our_name[strlen(our_name)-1] = '\0'; 560 | 561 | if ((index = lookup_id_in_class(our_name, class_id)) != -1){ 562 | char* our_type = get_type(index); 563 | if (our_type[strlen(our_type)-1] == ']'){ 564 | char* new_type = malloc(strlen(our_type)); 565 | strncpy(new_type,our_type,strlen(our_type)-2); 566 | if (strcmp(new_type,"int") == 0){ 567 | return index; 568 | }else{ 569 | printf("Line: %d: %s is not an array of integers\n", line, our_name); 570 | } 571 | }else{ 572 | printf("Line: %d: %s is not an array\n", line, our_name); 573 | } 574 | }else{ 575 | printf("Line: %d: %s does not exist in class %s\n",line, our_name, get_name(class_id)); 576 | } 577 | }else{ 578 | if ((index = lookup_id_in_class(our_name, class_id)) != -1){ 579 | char* our_type = get_type(index); 580 | if (strcmp(our_type,"int") == 0){ 581 | return index; 582 | }else{ 583 | printf("Line: %d: %s is not an integer\n", line, our_name); 584 | } 585 | }else{ 586 | printf("Line: %d: %s does not exist in class %s\n",line, our_name, get_name(class_id)); 587 | } 588 | } 589 | 590 | return index; 591 | } 592 | 593 | int check_opperation_for_type(char opp, char* type){ 594 | if (opp == '+'){ 595 | if (strcmp(type, "string") == 0 || strcmp(type, "int") == 0){ 596 | return 1; 597 | }else{ 598 | return -1; 599 | } 600 | }else{ 601 | if (strcmp(type, "int") == 0){ 602 | return 1; 603 | }else{ 604 | return -1; 605 | } 606 | } 607 | return -1; 608 | } 609 | 610 | char* get_designator_type(char* glob_designator, int designator_class_id){ 611 | int index; 612 | if (glob_designator[strlen(glob_designator)-1] == '['){ //AKO JE ZADNJI CLAN NIZA 613 | glob_designator[strlen(glob_designator)-1] = '\0'; // MOZDA OVDE PUCA JER NIJE NOVA PROMENLJIVA //odsekli mu [ da dobijemo ime 614 | if ((index = lookup_var_in_class(glob_designator, designator_class_id)) != -1){ 615 | char* new_type = get_type(index); 616 | if (new_type[strlen(new_type)-1] == ']' || strcmp("string", new_type) == 0){ 617 | if (strcmp("string", new_type) == 0){ 618 | return "char"; 619 | }else{ //ako nije string vec niz 620 | new_type[strlen(new_type) - 2] = '\0'; 621 | return new_type; 622 | } 623 | }else{ 624 | printf("Line: %d: %s is not an array or string\n", line, get_name(index)); 625 | } 626 | }else{ 627 | printf("Line: %d: %s does not exist in class %s\n", line, glob_designator, get_name(designator_class_id)); 628 | } 629 | }else{ // AKO ZADNJI NIJE CLAN NIZA 630 | if ((index = lookup_var_in_class(glob_designator, designator_class_id)) != -1){ 631 | return get_type(index); 632 | }else{ 633 | printf("Line: %d: %s does not exist in class %s\n", line, glob_designator, get_name(designator_class_id)); 634 | 635 | } 636 | } 637 | return NULL; 638 | } 639 | -------------------------------------------------------------------------------- /symtab.h: -------------------------------------------------------------------------------- 1 | 2 | #ifndef SYMTAB_H 3 | #define SYMTAB_H 4 | 5 | #define PARAM_NUMBER 10 6 | extern int line; 7 | 8 | // Element tabele simbola 9 | typedef struct sym_entry { 10 | int level; // na kom nivou je simbol 11 | char *name; // ime simbola 12 | unsigned kind; // vrsta simbola 13 | char* type; // tip vrednosti simbola 14 | int attribute; // dodatni attribut 15 | char**param_types; // tipovi parametara 16 | int class_id; // kojoj klasi pripada 17 | int initialized; 18 | } SYMBOL_ENTRY; 19 | 20 | // Vraca indeks prvog sledeceg praznog elementa. 21 | int get_next_empty_element(void); 22 | 23 | int check_primitive_type(char* type); 24 | 25 | int lookup_id_nokind(char *name, int level); 26 | 27 | int lookup_id_in_class(char* name, int class_id); 28 | 29 | int lookup_id_strict_kind(char *name, unsigned kind, int level); 30 | 31 | // Da li je instanca klase ili niza inicijalizovana 32 | int is_initialized(int index); 33 | 34 | char* parse_method_name(char* str); 35 | 36 | char* parse_method_type(char* str); 37 | 38 | // Postavlja vrednost na inicijalizovanu 39 | void set_initialized(int index, int value); 40 | 41 | // Vraca indeks poslednjeg zauzetog elementa. 42 | int get_last_element(void); 43 | 44 | // Ubacuje simbol sa datom oznakom simbola i tipom simbola i vraca indeks ubacenog elementa u tabeli simbola ili -1. 45 | int insert_symbol(char *name, unsigned kind, char* type, int level,int class_id); 46 | 47 | // Proverava da li se simbol vec nalazi u tabeli simbola, ako se ne nalazi ubacuje ga, ako se nalazi ispisuje gresku. 48 | // Vraca indeks elementa u tabeli simbola. 49 | int try_to_insert_id(char *name, unsigned kind, char* type, int level,int class_id); 50 | 51 | // Ubacuje konstantu u tabelu simbola (ako vec ne postoji). 52 | int try_to_insert_constant(char *str, char* type); 53 | 54 | // Vraca indeks pronadjenog simbola ili vraca -1. 55 | int lookup_id(char *name, unsigned kind ,int level); 56 | 57 | // Vraca indeks pronadjenog simbola ili vraca -1 58 | int lookup_id_strict(char *name, int level); 59 | 60 | // Vraca indeks pronadjenog simbola (konstante) ili vraca -1. 61 | int lookup_constant(char *name); 62 | 63 | // set i get metode za polja jednog elementa tabele simbola 64 | char* get_name(int index); 65 | unsigned get_kind(int index); 66 | char* get_type(int index); 67 | void set_attribute(int index, int attribute); 68 | unsigned get_attribute(int index); 69 | void set_param_type(int index, unsigned number, char* type); 70 | char* get_param_type(int index, unsigned number); 71 | void set_register_type(int register_index, char* type); 72 | 73 | 74 | char* get_designator_type(char* glob_designator, int designator_class_id); 75 | 76 | // Brise elemente tabele simbola od pocetnog indeksa do kraja tabele 77 | void clear_symbols(unsigned begin_index); 78 | 79 | // Brise sve elemente tabele simbola. 80 | void clear_symtab(void); 81 | 82 | // Ispisuje sve elemente tabele simbola. 83 | void print_symtab(void); 84 | unsigned logarithm2(unsigned value); 85 | 86 | // Inicijalizacija tabele simbola. 87 | void init_symtab(void); 88 | 89 | #endif 90 | -------------------------------------------------------------------------------- /test.txt: -------------------------------------------------------------------------------- 1 | program mojprogram 2 | 3 | int a, b, c; 4 | char d[]; 5 | const int efg = 5; 6 | 7 | class A{ 8 | bool is; 9 | void check() 10 | { 11 | d="gsodkg"; 12 | } 13 | 14 | int testOv(A klasa, int c, string s) 15 | int a; 16 | { 17 | a = 5; 18 | return a; 19 | } 20 | } 21 | 22 | class B extends A 23 | { 24 | A zam; 25 | A mb(){ 26 | zam = new A; 27 | return zam; 28 | } 29 | 30 | char testOv() 31 | char c; 32 | { 33 | c = 'c'; 34 | return c; 35 | } 36 | } 37 | 38 | class C 39 | { 40 | B klasaB; 41 | char v; 42 | int o; 43 | C mc(int a, int b){ 44 | return this; 45 | } 46 | A vracaKlasuA(B b,A a){ 47 | o = 25+52; 48 | a=b.mb(); 49 | this.klasaB = b; 50 | this.v = this.klasaB.testOv(); 51 | a=this.vracaKlasuA(b,a); 52 | a=this.vracaKlasuA(null,this.vracaKlasuA(this.klasaB,this.klasaB.zam)); 53 | o = this.klasaB.zam.testOv(a, o, "sfasdf"); 54 | } 55 | } 56 | 57 | class D extends A{ 58 | B bb; 59 | int ma(B b, C c){ 60 | return 1; 61 | } 62 | B vb(){ 63 | bb = new B; 64 | return bb; 65 | } 66 | } 67 | 68 | 69 | { 70 | void main() 71 | D ddd; 72 | C ccc; 73 | int yo; 74 | { 75 | ddd = new D; 76 | ccc = new C; 77 | yo = ddd.ma(ddd.vb(), ccc.mc(5,6)); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /translator.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | char* izbaciNL(char *s){ 7 | char *ps; 8 | char *sn; 9 | int pn=0; 10 | int br=2; 11 | sn=malloc(strlen(s)); 12 | ps=s; 13 | while(*(ps+1)!='\0'){ 14 | while(*(ps+br)=='\t'|| *(ps+br)=='\r') 15 | br++; 16 | if ((*ps=='\n')&&(*(ps+br)=='\n')){ 17 | ps+=br; 18 | br=2; 19 | } 20 | else{ 21 | sn[pn]=*ps; 22 | pn++; 23 | ps++; 24 | br=2; 25 | } 26 | } 27 | sn[pn]=*ps; 28 | sn[pn+1]='\0'; 29 | return sn; 30 | } 31 | 32 | char* append2(char* a, char*b){ 33 | char* result; 34 | if(a==NULL) 35 | a=""; 36 | if(b==NULL) 37 | b=""; 38 | result = malloc(strlen(a)+strlen(b)+5); 39 | result = strcat(result, a); 40 | result = strcat(result, b); 41 | if (result == "") return "\r\n"; 42 | return result; 43 | } 44 | 45 | char* append3(char* a, char*b, char* c){ 46 | char* result; 47 | if(a==NULL) 48 | a=""; 49 | if(b==NULL) 50 | b=""; 51 | if(c==NULL) 52 | c=""; 53 | result = malloc(strlen(a)+strlen(b)+strlen(c)+5); 54 | result = strcat(result, a); 55 | result = strcat(result, b); 56 | result = strcat(result, c); 57 | if (result == "") return "\r\n"; 58 | return result; 59 | } 60 | 61 | char* append4(char* a, char*b, char* c, char* d){ 62 | char* result; 63 | if(a==NULL) 64 | a=""; 65 | if(b==NULL) 66 | b=""; 67 | if(c==NULL) 68 | c=""; 69 | if(d==NULL) 70 | d=""; 71 | result = malloc(strlen(a)+strlen(b)+strlen(c)+strlen(d)+ 5); 72 | result = strcat(result, a); 73 | result = strcat(result, b); 74 | result = strcat(result, c); 75 | result = strcat(result, d); 76 | if (result == "") return "\r\n"; 77 | return result; 78 | } 79 | 80 | char* append5(char* a, char* b, char* c, char* d, char* e){ 81 | char* result; 82 | if(a==NULL) 83 | a=""; 84 | if(b==NULL) 85 | b=""; 86 | if(c==NULL) 87 | c=""; 88 | if(d==NULL) 89 | d=""; 90 | if(e==NULL) 91 | e=""; 92 | result = malloc(strlen(a)+strlen(b)+strlen(c)+strlen(d)+strlen(e)+ 5); 93 | result = strcat(result, a); 94 | result = strcat(result, b); 95 | result = strcat(result, c); 96 | result = strcat(result, d); 97 | result = strcat(result, e); 98 | if (result == "") return "\r\n"; 99 | return result; 100 | } 101 | 102 | char* append6(char* a, char*b, char* c, char* d,char* e, char* f){ 103 | char* result; 104 | char* q=a; 105 | char* g=c; 106 | char* k=f; 107 | char* j=e; 108 | char* w=b; 109 | char* h=d; 110 | if(a==NULL) 111 | q=""; 112 | if(b==NULL) 113 | w=""; 114 | if(c==NULL) 115 | g=""; 116 | if(d==NULL) 117 | h=""; 118 | if(e==NULL) 119 | j=""; 120 | if(f==NULL) 121 | k=""; 122 | result = malloc(strlen(q)+strlen(w)+strlen(g)+strlen(h)+ 123 | strlen(j)+strlen(k)+ 5); 124 | result = strcat(result, q); 125 | result = strcat(result, w); 126 | result = strcat(result, g); 127 | result = strcat(result, h); 128 | result = strcat(result, j); 129 | result = strcat(result, k); 130 | if (result == "") return "\r\n"; 131 | return result; 132 | } 133 | --------------------------------------------------------------------------------