├── .gitignore ├── AST.c ├── AST.h ├── Makefile ├── README.md ├── codegen.c ├── codegen.h ├── globals.h ├── main ├── main.c ├── raw ├── parse.y └── scan.l ├── symtab.c ├── symtab.h ├── test ├── test0.cm ├── test0.cm.tm ├── test1.cm ├── test1.cm.tm ├── test2.cm └── test2.cm.tm ├── tm └── tm.c /.gitignore: -------------------------------------------------------------------------------- 1 | # Object files 2 | *.o 3 | 4 | # Libraries 5 | *.lib 6 | *.a 7 | 8 | # Shared objects (inc. Windows DLLs) 9 | *.dll 10 | *.so 11 | *.so.* 12 | *.dylib 13 | 14 | # Executables 15 | *.exe 16 | *.out 17 | *.app 18 | -------------------------------------------------------------------------------- /AST.c: -------------------------------------------------------------------------------- 1 | /*generate a systax tree 2 | *also perform type check 3 | */ 4 | 5 | 6 | #include "globals.h" 7 | #include "parse.h" 8 | #include "symtab.h" 9 | #include "AST.h" 10 | 11 | 12 | TreeNode * ASTRoot; /*Root of syntax tree*/ 13 | 14 | static Scope current_scope = GLOBAL; /* record current scope for variable declaration */ 15 | static FunSymbol* current_fun = NULL; /* which function's body are we in ?*/ 16 | 17 | /* Add declaration as sibling*/ 18 | TreeNode* newDecList(TreeNode* decList, TreeNode* declaration) 19 | { 20 | 21 | TreeNode* node = decList; 22 | 23 | while(node->sibling != NULL) 24 | node = node->sibling; 25 | node->sibling = declaration; 26 | 27 | 28 | return decList; 29 | } 30 | 31 | TreeNode* newTypeSpe(ExpType type, int lineno) 32 | { 33 | TreeNode* root = newASTNode(TYPE_AST, lineno); 34 | root->type = type; 35 | return root; 36 | } 37 | 38 | 39 | 40 | TreeNode* newVarDec(TreeNode* typeSpecifier, char* ID, int lineno) 41 | { 42 | 43 | ASSERT(typeSpecifier->type == TYPE_INTEGER){ 44 | fprintf(stderr, "Error: @line %d, type specifier of variable %s must be int.\n", lineno, ID); 45 | } 46 | 47 | if(current_scope == LOCAL){ 48 | pushTable(CompoundST); 49 | } 50 | 51 | ASSERT(lookup_var_top(ID) == NULL){ 52 | fprintf(stderr, "Error: @line %d, duplicate declarations of variable %s.\n", lineno, ID); 53 | } 54 | 55 | TreeNode* root = newASTNode(VARDEC_AST, lineno); 56 | root->child[0] = typeSpecifier; 57 | root->attr.name = strdup(ID); 58 | root->type = TYPE_INTEGER; 59 | 60 | if(current_scope == LOCAL){ 61 | insert_var(root->attr.name, LOCAL, tables->size++, TYPE_INTEGER); 62 | popTable(); 63 | } 64 | else{ 65 | insert_var(root->attr.name, GLOBAL, tables->size++, TYPE_INTEGER); 66 | } 67 | 68 | return root; 69 | } 70 | // var_declaration: type_specifier ID LSB NUMBER RSB SEMI 71 | TreeNode* newArrayDec(TreeNode* typeSpecifier, char* ID, int size, int lineno) 72 | { 73 | 74 | ASSERT(typeSpecifier->type == TYPE_INTEGER){ 75 | fprintf(stderr, "Error: @line %d, type specifier of variable %s must be int.\n", lineno, ID); 76 | } 77 | 78 | if(current_scope == LOCAL){ 79 | pushTable(CompoundST); 80 | } 81 | 82 | ASSERT(lookup_var_top(ID) == NULL){ 83 | fprintf(stderr, "Error: @line %d, duplicate declarations of variable %s.\n", lineno, ID); 84 | } 85 | 86 | TreeNode* root = newASTNode(ARRAYDEC_AST, lineno); 87 | root->child[0] = typeSpecifier; 88 | root->attr.name = strdup(ID); 89 | root->type = TYPE_ARRAY; 90 | root->attr.value = size; 91 | 92 | 93 | if(current_scope == LOCAL){ 94 | insert_var(root->attr.name, LOCAL, tables->size, TYPE_ARRAY); 95 | tables->size += size; 96 | popTable(); 97 | } 98 | else{ 99 | insert_var(root->attr.name, GLOBAL, tables->size, TYPE_ARRAY); 100 | tables->size += size; 101 | } 102 | 103 | return root; 104 | } 105 | 106 | TreeNode* newFunDec(TreeNode* funHead, TreeNode* funBody, int lineno) 107 | { 108 | 109 | TreeNode* root = newASTNode(FUNDEC_AST, lineno); 110 | root->child[0] = funHead; 111 | root->child[1] = funBody; 112 | 113 | 114 | 115 | /* DEBUG: print symbol table of this compount statement */ 116 | #ifdef DEBUG_SYM 117 | fprintf(listing, "symbo table of Compound\n"); 118 | printSymTab(CompoundST); 119 | #endif 120 | 121 | funBody->symbolTable = CompoundST; 122 | CompoundST = newSymbolTable(LOCAL); 123 | 124 | /* leave function*/ 125 | popTable(); 126 | current_scope = GLOBAL; 127 | current_fun = NULL; 128 | 129 | return root; 130 | } 131 | 132 | 133 | TreeNode* newFunHead(TreeNode* typeSpecifier, char* ID, TreeNode* params, int lineno) 134 | { 135 | 136 | ASSERT(lookup_fun(ID) == NULL){ 137 | fprintf(stderr, "Error: @line %d, duplicate declarations of function %s.\n", lineno, ID); 138 | } 139 | 140 | TreeNode* root = newASTNode(FUNHEAD_AST, lineno); 141 | root->attr.name = strdup(ID); 142 | root->type = typeSpecifier->type; 143 | root->child[0] = typeSpecifier; 144 | root->child[1] = params; 145 | 146 | /* print symbol table to test */ 147 | #ifdef DEBUG_SYM 148 | fprintf(listing, "symbol table of function: %s\n", root->attr.name); 149 | printSymTab(ParamST); 150 | #endif 151 | insert_fun(ID, ParamST, ParamST->size, root->type); 152 | 153 | /* For processing function body*/ 154 | pushTable(ParamST); 155 | current_scope = LOCAL; 156 | current_fun = lookup_fun(ID); 157 | 158 | ParamST = newSymbolTable(PARAM); 159 | 160 | 161 | return root; 162 | } 163 | 164 | 165 | TreeNode* newParamList(TreeNode* paramList, TreeNode* param) 166 | { 167 | // param_list: param_list SEMI param 168 | TreeNode* node = paramList; 169 | if(paramList != NULL) 170 | { 171 | while(node->sibling != NULL) 172 | node = node->sibling; 173 | node->sibling = param; 174 | return paramList; 175 | } 176 | else // param_list: param 177 | { 178 | return param; 179 | } 180 | } 181 | 182 | 183 | TreeNode* newParam(TreeNode* typeSpecifier, char* ID, int isArray, int lineno) 184 | { 185 | 186 | ASSERT(typeSpecifier->type == TYPE_INTEGER){ 187 | fprintf(stderr, "Error: @line %d, type specifier of param %s must be int.\n", lineno, ID); 188 | } 189 | 190 | pushTable(ParamST); 191 | ASSERT(lookup_var_top(ID) == NULL){ 192 | fprintf(stderr, "Error: @line %d, duplicate declarations of variable %s.\n", lineno, ID); 193 | } 194 | 195 | TreeNode* root; 196 | if(!isArray) // param: type_specifier ID 197 | { 198 | root = newASTNode(PARAMID_AST, lineno); 199 | root->child[0] = typeSpecifier; 200 | root->attr.name = strdup(ID); 201 | root->type = TYPE_INTEGER; 202 | 203 | insert_var(root->attr.name, PARAM, ParamST->size++ , TYPE_INTEGER); 204 | 205 | 206 | } 207 | else // param: type_specifier ID [] 208 | { 209 | root = newASTNode(PARAMARRAY_AST, lineno); 210 | root->child[0] = typeSpecifier; 211 | root->attr.name = strdup(ID); 212 | root->type = TYPE_ARRAY; 213 | 214 | insert_var(root->attr.name, PARAM, ParamST->size++ , TYPE_ARRAY); 215 | 216 | } 217 | 218 | popTable(); 219 | return root; 220 | } 221 | TreeNode* newCompound(TreeNode* localDecs, TreeNode* stmtList, int lineno) 222 | { 223 | 224 | TreeNode* root = newASTNode(COMPOUND_AST, lineno); 225 | root->child[0] = localDecs; 226 | root->child[1] = stmtList; 227 | 228 | /* assign type of Return to Compound */ 229 | if(stmtList != NULL && stmtList->type != TYPE_UNDEFINED) /* has return stmt */ 230 | root->type = stmtList->type; 231 | else 232 | root->type = TYPE_VOID; 233 | 234 | 235 | return root; 236 | } 237 | TreeNode* newLocalDecs(TreeNode* localDecs, TreeNode* varDec) 238 | { 239 | 240 | if(localDecs == NULL) 241 | return varDec; 242 | 243 | TreeNode* node = localDecs; 244 | while(node->sibling != NULL) 245 | node = node->sibling; 246 | node->sibling = varDec; 247 | return localDecs; 248 | } 249 | TreeNode* newStmtList(TreeNode* stmtList, TreeNode* stmt, int lineno) 250 | { 251 | 252 | if(stmtList == NULL) 253 | return stmt; 254 | 255 | TreeNode* node = stmtList; 256 | while(node->sibling != NULL) 257 | node = node->sibling; 258 | node->sibling = stmt; 259 | 260 | return stmtList; 261 | } 262 | 263 | /* if-else*/ 264 | TreeNode* newSelectStmt(TreeNode* expression, TreeNode* stmt, TreeNode* elseStmt, int lineno) 265 | { 266 | 267 | ASSERT(expression->type == TYPE_INTEGER){ 268 | fprintf(stderr, "Error: @line %d, test condition expression not integer.\n", lineno); 269 | } 270 | 271 | 272 | TreeNode* root = newASTNode(SELESTMT_AST, lineno); 273 | root->child[0] = expression; 274 | root->child[1] = stmt; 275 | root->child[2] = elseStmt; 276 | 277 | 278 | return root; 279 | } 280 | 281 | /*while*/ 282 | TreeNode* newIterStmt(TreeNode* expression, TreeNode* stmt, int lineno) 283 | { 284 | 285 | ASSERT(expression->type == TYPE_INTEGER){ 286 | fprintf(stderr, "Error: @line %d, test condition expression not integer.\n", lineno); 287 | } 288 | 289 | TreeNode* root = newASTNode(ITERSTMT_AST, lineno); 290 | root->child[0] = expression; 291 | root->child[1] = stmt; 292 | 293 | 294 | return root; 295 | } 296 | 297 | /*return*/ 298 | TreeNode* newRetStmt(TreeNode* expression, int lineno) 299 | { 300 | ExpType type; 301 | if(expression!= NULL) 302 | type = expression->type; 303 | else 304 | type = TYPE_VOID; 305 | 306 | ASSERT(type == current_fun->type){ 307 | fprintf(stderr, "Error: @line %d, return type mis-match.\n", lineno); 308 | 309 | } 310 | 311 | TreeNode* root = newASTNode(RETSTMT_AST, lineno); 312 | root->child[0] = expression; 313 | root->type = type; 314 | 315 | return root; 316 | } 317 | 318 | /* var = expression */ 319 | TreeNode* newAssignExp(TreeNode* var, TreeNode* expression, int lineno) 320 | { 321 | 322 | ASSERT(var->type==TYPE_INTEGER && expression->type==TYPE_INTEGER){ 323 | fprintf(stderr, "Error: @line %d, only can assign int to int.\n", lineno); 324 | } 325 | 326 | TreeNode* root = newASTNode(ASSIGN_AST, lineno); 327 | root->child[0] = var; 328 | root->child[1] = expression; 329 | root->type = TYPE_INTEGER; 330 | 331 | return root; 332 | } 333 | 334 | /*Use variables (not declaration)*/ 335 | TreeNode* newVar(char* ID, int lineno) 336 | { 337 | 338 | 339 | /*Check declaration*/ 340 | pushTable(CompoundST); 341 | VarSymbol* vs = lookup_var(ID); 342 | ASSERT( vs != NULL){ 343 | fprintf(stderr, "Error: @line %d, variable %s not defined before.\n", lineno, ID); 344 | } 345 | popTable(); 346 | 347 | TreeNode* root = newASTNode(VAR_AST, lineno); 348 | root->attr.name = vs->name; 349 | root->type = vs->type; 350 | 351 | return root; 352 | } 353 | TreeNode* newArrayVar(char* ID, TreeNode* expression, int lineno) 354 | { 355 | 356 | ASSERT(expression->type == TYPE_INTEGER){ 357 | fprintf(stderr, "Error: @line %d, array %s: index is not integer.\n", lineno, ID); 358 | 359 | } 360 | 361 | /*Check declaration */ 362 | pushTable(CompoundST); 363 | VarSymbol* vs = lookup_var(ID); 364 | ASSERT( vs != NULL){ 365 | fprintf(stderr, "Error: @line %d, variable %s not defined before.\n", lineno, ID); 366 | } 367 | popTable(); 368 | 369 | 370 | ASSERT( vs->type == TYPE_ARRAY){ 371 | fprintf(stderr, "Error: @line %d, variable %s is not an array.\n", lineno, ID); 372 | } 373 | 374 | 375 | TreeNode* root = newASTNode(ARRAYVAR_AST, lineno); 376 | root->child[0] = expression; 377 | root->attr.name = vs->name; 378 | root->type = TYPE_INTEGER; /*array element must be int*/ 379 | 380 | return root; 381 | } 382 | TreeNode* newSimpExp(TreeNode* addExp1, int relop, TreeNode* addExp2, int lineno) 383 | { 384 | 385 | ASSERT(addExp1->type == TYPE_INTEGER && addExp2->type == TYPE_INTEGER){ 386 | fprintf(stderr, "Error: @line %d, only can compare integers.\n", lineno); 387 | } 388 | 389 | TreeNode* root = newASTNode(EXP_AST, lineno); 390 | root->child[0] = addExp1; 391 | root->child[1] = addExp2; 392 | root->attr.op = relop; 393 | root->type = TYPE_INTEGER;/*use int as boolean*/ 394 | 395 | 396 | return root; 397 | } 398 | 399 | TreeNode* newAddExp(TreeNode* addExp, int addop, TreeNode* term, int lineno) 400 | { 401 | ASSERT(addExp->type == TYPE_INTEGER && term->type == TYPE_INTEGER){ 402 | fprintf(stderr, "Error: @line %d, only can calculate integers.\n", lineno); 403 | } 404 | 405 | TreeNode* root = newASTNode(EXP_AST, lineno); 406 | root->child[0] = addExp; 407 | root->child[1] = term; 408 | root->attr.op = addop; 409 | root->type = TYPE_INTEGER; 410 | 411 | return root; 412 | } 413 | 414 | TreeNode* newTerm(TreeNode* term, int mulop, TreeNode* factor, int lineno) 415 | { 416 | ASSERT(term->type == TYPE_INTEGER && factor->type == TYPE_INTEGER){ 417 | fprintf(stderr, "Error: @line %d, only can calculate integers.\n", lineno); 418 | 419 | } 420 | 421 | TreeNode* root = newASTNode(EXP_AST, lineno); 422 | root->child[0] = term; 423 | root->child[1] = factor; 424 | root->attr.op = mulop; 425 | root->type = TYPE_INTEGER; 426 | 427 | 428 | return root; 429 | } 430 | 431 | TreeNode* newNumNode(int value, int lineno) 432 | { 433 | TreeNode* root = newASTNode(NUM_AST, lineno); 434 | root->attr.value = value; 435 | root->type = TYPE_INTEGER; 436 | 437 | return root; 438 | } 439 | 440 | TreeNode* newCall(char* ID, TreeNode* args, int lineno) 441 | { 442 | FunSymbol* fun = lookup_fun(ID); 443 | ASSERT(fun != NULL){ 444 | fprintf(stderr, "Error: @line %d, call function %s which is not defined.\n", lineno, ID); 445 | } 446 | 447 | 448 | VarSymbol* var = fun->symbolTable->varList; 449 | TreeNode* tmp = args; 450 | 451 | while(var && tmp){ 452 | ASSERT(var->type == tmp->type){ 453 | fprintf(stderr, "Error: @line %d, call function %s : parameter type mis-match.\n", lineno, ID); 454 | } 455 | var = var->next_FIFO; 456 | tmp = tmp->sibling; 457 | } 458 | 459 | ASSERT(!var && !tmp){ 460 | fprintf(stderr, "Error: @line %d, call function %s : parameter number mis-match.\n", lineno, ID); 461 | } 462 | 463 | /*Check finished*/ 464 | 465 | TreeNode* root = newASTNode(CALL_AST, lineno); 466 | root->child[0] = args; 467 | root->attr.name = strdup(ID); 468 | root->type = fun->type; 469 | 470 | return root; 471 | } 472 | 473 | /* Add the exp as sibling*/ 474 | TreeNode* newArgList(TreeNode* argList, TreeNode* expression) 475 | { 476 | TreeNode* node = argList; 477 | while(node->sibling != NULL) 478 | node = node->sibling; 479 | node->sibling = expression; 480 | return argList; 481 | } 482 | TreeNode* newASTNode(ASTType type, int lineno) 483 | { 484 | int i; 485 | 486 | TreeNode* node = (TreeNode*)malloc(sizeof(TreeNode)); 487 | ASSERT(node != NULL){ 488 | fprintf(stderr, "Failed to malloc for TreeNode @line%d.\n", lineno); 489 | } 490 | 491 | for(i=0; ichild[i] = NULL; 493 | } 494 | node->sibling = NULL; 495 | node->astType = type; 496 | node->type = TYPE_UNDEFINED; 497 | node->lineno = lineno; 498 | return node; 499 | } 500 | 501 | void printNodeKind(TreeNode* node) 502 | { 503 | if(node == NULL) 504 | return; 505 | switch(node->astType) 506 | { 507 | case VARDEC_AST: 508 | printf("Var declaration \n"); 509 | break; 510 | case ARRAYDEC_AST: 511 | printf("Array declaration \n"); 512 | break; 513 | case FUNDEC_AST: 514 | printf("Function declaration \n"); 515 | break; 516 | case TYPE_AST: 517 | printf("Type specifier \n"); 518 | break; 519 | case PARAMID_AST: 520 | printf("Param of ID \n"); 521 | break; 522 | case PARAMARRAY_AST: 523 | printf("Param of Array \n"); 524 | break; 525 | case COMPOUND_AST: 526 | printf("Counpound statements \n"); 527 | break; 528 | case EXPSTMT_AST: 529 | printf("Expression statement\n"); 530 | break; 531 | case SELESTMT_AST: 532 | printf("Select statement\n"); 533 | break; 534 | case ITERSTMT_AST: 535 | printf("Iteration statement\n"); 536 | break; 537 | case RETSTMT_AST: 538 | printf("Return statement\n"); 539 | break; 540 | case ASSIGN_AST: 541 | printf("Assign statement\n"); 542 | break; 543 | case EXP_AST: 544 | printf("Expression \n"); 545 | break; 546 | case VAR_AST: 547 | printf("Var \n"); 548 | break; 549 | case ARRAYVAR_AST: 550 | printf("Array var ASt\n"); 551 | break; 552 | case FACTOR_AST: 553 | printf("Factor \n"); 554 | break; 555 | case CALL_AST: 556 | printf("Call stement \n"); 557 | break; 558 | default: 559 | printf("No such AST type\n"); 560 | break; 561 | } 562 | } 563 | void printAST(TreeNode* root, int indent) 564 | { 565 | TreeNode* node = root; 566 | int i; 567 | while(node != NULL) 568 | { 569 | for (i = 0; ichild[0], indent+4); 575 | printAST(node->child[1], indent+4); 576 | printAST(node->child[2], indent+4); 577 | printAST(node->child[3], indent+4); 578 | node = node->sibling; 579 | } 580 | } 581 | -------------------------------------------------------------------------------- /AST.h: -------------------------------------------------------------------------------- 1 | /*generate a systax tree 2 | *also perform type check 3 | */ 4 | 5 | 6 | #ifndef AST_H 7 | #define AST_H 8 | 9 | #include "globals.h" 10 | 11 | 12 | /* make a new raw AST tree node */ 13 | TreeNode* newASTNode(ASTType asttype, int lineno); 14 | 15 | TreeNode* newDecList(TreeNode* decList, TreeNode* declaration); // decList==NULL => declaration 16 | TreeNode* newDec(TreeNode* declaration, int type); // type: 0=var, 1=fun 17 | TreeNode* newVarDec(TreeNode* typeSpecifier, char* ID, int lineno); 18 | TreeNode* newArrayDec(TreeNode* typeSpecifier, char* ID, int size, int lineno); 19 | TreeNode* newTypeSpe(ExpType type, int lineno); 20 | TreeNode* newFunDec(TreeNode* funHead, TreeNode* funBody, int lineno); 21 | TreeNode* newFunHead(TreeNode* typeSpecifier, char* ID, TreeNode* params, int lineno); 22 | TreeNode* newParamList(TreeNode* paramList, TreeNode* param); // paramList==NULL => param_list:param 23 | TreeNode* newParam(TreeNode* typeSpecifier, char* ID, int type, int lineno); // type: 1=id is array 0=otherwise 24 | TreeNode* newCompound(TreeNode* localDecs, TreeNode* stmtList, int lineno); 25 | TreeNode* newLocalDecs(TreeNode* localDecs, TreeNode* varDec); 26 | TreeNode* newStmtList(TreeNode* stmtList, TreeNode* stmt, int lineno); 27 | TreeNode* newExpStmt(TreeNode* expression,int lineno); // stmt==NULL => expression_stmt: SEMI 28 | TreeNode* newSelectStmt(TreeNode* expression, TreeNode* stmt, TreeNode* elseStmt, int lineno); 29 | TreeNode* newIterStmt(TreeNode* expression, TreeNode* stmt, int lineno); 30 | TreeNode* newRetStmt(TreeNode* expression, int lineno); // expression=NULL => return_stmt: RETURN SEMI; 31 | 32 | 33 | TreeNode* newAssignExp(TreeNode* var, TreeNode* expressio, int linenon); 34 | 35 | 36 | TreeNode* newVar(char* ID, int lineno); 37 | TreeNode* newArrayVar(char* ID, TreeNode* expression, int lineno); 38 | 39 | 40 | TreeNode* newSimpExp(TreeNode* addExp1, int relop, TreeNode* addExp2, int lineno); 41 | TreeNode* newAddExp(TreeNode* addExp, int addop, TreeNode* term, int lineno); 42 | TreeNode* newTerm(TreeNode* term, int mulop, TreeNode* factor, int lineno); 43 | TreeNode* newNumNode(int num, int lineno); 44 | TreeNode* newCall(char* ID, TreeNode* args, int lineno); 45 | TreeNode* newArgList(TreeNode* argList, TreeNode* expression); 46 | 47 | 48 | /* prints a formatted listing of the syntax tree contents */ 49 | void printAST(TreeNode* root, int indent); 50 | 51 | 52 | #endif 53 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for the C-Minus Compiler 2 | # Author: TZX, HJN, LHY, TJG 3 | # 4 | CC = gcc 5 | CFLAGS = -Wall 6 | LDFLAGS = -ll -ly 7 | 8 | LEX = flex 9 | LFLAGS = 10 | YACC = bison 11 | YFLAGS = -d 12 | 13 | SRC = main.c scan.c parse.c AST.c symtab.c codegen.c 14 | 15 | 16 | all: main tm 17 | 18 | main: $(SRC) 19 | $(CC) $(CFLAGS) $(SRC) -o $@ -g 20 | tm: tm.c 21 | $(CC) $(CFLAGS) $< -o $@ 22 | 23 | 24 | ## For Lex and Yacc 25 | scan.c: raw/scan.l globals.h parse.h 26 | $(LEX) $(LFLAGS) -o $@ $< 27 | 28 | 29 | parse.c parse.h: raw/parse.y globals.h AST.h 30 | $(YACC) $(YFLAGS) -o $@ $< 31 | 32 | ## 33 | 34 | 35 | clean: 36 | rm -f *.o 37 | rm -f scan.c 38 | rm -f parse.c 39 | rm -f parse.h 40 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | C-Compiler 2 | ========== 3 | 4 | A simple compiler aim at C-minus language and TM vitrual machine. 5 | 6 | File Structure 7 | ============== 8 | 9 | 1. main.c 10 | -- main code file 11 | 12 | 2. globals.h 13 | -- define data structures and macros 14 | 15 | 3. raw/scan.l raw/parse.y 16 | -- lex and yacc source code for quick scanning & parsing 17 | 18 | 4. AST.c 19 | -- define routine functions for parsing a syntax tree, making type-check and error-handling at meanwhile. 20 | 21 | 5. symtab.c 22 | -- define data structures for symbol tables (for variables & functions) 23 | 24 | 6. codegen.c 25 | -- code generator, which recursively generates TM-machine code by syntax tree travesal. 26 | 27 | Usage 28 | ===== 29 | 30 | 1. To compile the compiler: 31 | 32 | `make clean` 33 | `make` 34 | 35 | 2. To compile for C-minus code: 36 | 37 | `main [filepath]` 38 | e.g. `main test1.cm` 39 | 40 | 3. To run TM codes: 41 | 42 | `tm [filepath]` 43 | e.g. `tm test1.cm.tm` 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /codegen.c: -------------------------------------------------------------------------------- 1 | /*code generator 2 | * - To generate utimate TM codes from syntax tree and symbol tables. 3 | */ 4 | 5 | #include "globals.h" 6 | #include "parse.h" 7 | #include "symtab.h" 8 | #include "codegen.h" 9 | 10 | /* stack used for call */ 11 | TreeNode* paramStack[SIZE]; 12 | int top = 0; 13 | 14 | /* stack routines*/ 15 | int pushParam(TreeNode* param) 16 | { 17 | if(top == SIZE) 18 | return 1; 19 | 20 | paramStack[top++] = param; 21 | return 0; 22 | } 23 | 24 | TreeNode* popParam() 25 | { 26 | if(top == 0) 27 | return NULL; 28 | 29 | return paramStack[--top]; 30 | } 31 | 32 | /* current location */ 33 | int emitLoc = 0 ; 34 | 35 | /* Highest TM location emitted so far */ 36 | int highEmitLoc = 0; 37 | 38 | /* skips "howMany" locations for later backpatch 39 | * returns the current code position 40 | */ 41 | int emitSkip( int howMany) 42 | { int i = emitLoc; 43 | emitLoc += howMany ; 44 | if (highEmitLoc < emitLoc) highEmitLoc = emitLoc ; 45 | return i; 46 | } 47 | 48 | /* backs up to a previously skipped location */ 49 | void emitBackup( int loc) 50 | { if (loc > highEmitLoc) emitComment("BUG in emitBackup"); 51 | emitLoc = loc ; 52 | } 53 | 54 | /* restores the current position to the highest previous position*/ 55 | void emitRestore(void) 56 | { emitLoc = highEmitLoc;} 57 | 58 | /* prints a comment line */ 59 | void emitComment( char * c ) 60 | { if (TraceCode) fprintf(code,"* %s\n",c);} 61 | 62 | /* emits a register-only TM instruction 63 | * op = the opcode 64 | * r = target register 65 | * s = 1st source register 66 | * t = 2nd source register 67 | * c = a comment to be printed if TraceCode is TRUE 68 | */ 69 | void emitRO( char *op, int r, int s, int t, char *c) 70 | { fprintf(code,"%3d: %5s %d,%d,%d ",emitLoc++,op,r,s,t); 71 | if (TraceCode) fprintf(code,"\t%s",c) ; 72 | fprintf(code,"\n") ; 73 | if (highEmitLoc < emitLoc) highEmitLoc = emitLoc ; 74 | } 75 | 76 | /* emits a register-to-memory TM instruction 77 | * op = the opcode 78 | * r = target register 79 | * d = the offset 80 | * s = the base register 81 | * c = a comment to be printed if TraceCode is TRUE 82 | */ 83 | void emitRM( char * op, int r, int d, int s, char *c) 84 | { fprintf(code,"%3d: %5s %d,%d(%d) ",emitLoc++,op,r,d,s); 85 | if (TraceCode) fprintf(code,"\t%s",c) ; 86 | fprintf(code,"\n") ; 87 | if (highEmitLoc < emitLoc) highEmitLoc = emitLoc ; 88 | } 89 | 90 | /*******************************/ 91 | 92 | /* generate standard prelude */ 93 | void emitPrelude() 94 | { 95 | if (TraceCode) emitComment("Begin prelude"); 96 | emitRM("LD",gp,0,zero,"load from location 0"); 97 | emitRM("ST",zero,0,zero,"clear location 0"); 98 | emitRM("LDA",sp,-(topTable()->size),gp,"allocate for global variables"); 99 | if (TraceCode) emitComment("End of prelude"); 100 | } 101 | 102 | /* generate codes for input() */ 103 | void emitInput() 104 | { 105 | 106 | if (TraceCode) emitComment("Begin input()"); 107 | FunSymbol* fun = lookup_fun("input"); 108 | fun->offset = emitSkip(0); 109 | emitRO("IN",ax,0,0,"read input into ax"); 110 | emitRM("LDA",sp,1,sp,"pop prepare"); 111 | emitRM("LD",pc,-1,sp,"pop return addr"); 112 | if (TraceCode) emitComment("End input()"); 113 | } 114 | 115 | /* generate codes for output() */ 116 | void emitOutput() 117 | { 118 | 119 | if (TraceCode) emitComment("Begin output()"); 120 | FunSymbol* fun = lookup_fun("output"); 121 | fun->offset = emitSkip(0); 122 | emitRM("LD",ax,1,sp,"load param into ax"); 123 | emitRO("OUT",ax,0,0,"output using ax"); 124 | emitRM("LDA",sp,1,sp,"pop prepare"); 125 | emitRM("LD",pc,-1,sp,"pop return addr"); 126 | if (TraceCode) emitComment("End output()"); 127 | } 128 | 129 | 130 | /* emit one instruction to get the address of a var, 131 | * store the address in bx, 132 | * we can access the var by bx[0] 133 | */ 134 | void emitGetAddr(VarSymbol *var) 135 | { 136 | 137 | switch(var->scope){ 138 | case GLOBAL: 139 | if(var->type == TYPE_ARRAY){ 140 | emitRM("LDA",bx,-(var->offset),gp,"get global array address"); 141 | } 142 | else{ 143 | emitRM("LDA",bx,-1-(var->offset),gp,"get global address"); 144 | } 145 | break; 146 | case LOCAL: 147 | if(var->type == TYPE_ARRAY){ 148 | emitRM("LDA",bx,-(var->offset),bp,"get local array address"); 149 | } 150 | else{ 151 | emitRM("LDA",bx,-1-(var->offset),bp,"get local address"); 152 | } 153 | break; 154 | case PARAM: 155 | if(var->type == TYPE_ARRAY){ 156 | emitRM("LD",bx,2+(var->offset),bp,"get param array address"); 157 | } 158 | else{ 159 | emitRM("LDA",bx,2+(var->offset),bp,"get param variable address"); 160 | } 161 | break; 162 | } 163 | } 164 | 165 | 166 | /* emits 5 instructions to call a function, 167 | * before this we have pushed all parameters 168 | */ 169 | void emitCall(FunSymbol *fun) 170 | { 171 | 172 | emitRM("LDA",ax,3,pc,"store returned PC"); 173 | emitRM("LDA",sp,-1,sp,"push prepare"); 174 | emitRM("ST",ax,0,sp,"push returned PC"); 175 | emitRM("LDC",pc,fun->offset,0,"jump to function"); 176 | emitRM("LDA",sp,fun->paramNum,sp,"release parameters"); 177 | } 178 | 179 | 180 | /* getValue: 181 | * 1 - store value in ax 182 | * 0 - store address in bx 183 | */ 184 | static int getValue = 1; 185 | 186 | /* isRecursive: 187 | * 1 - cGen will recurse on sibling 188 | * 0 - cGen won't recurse on sibling 189 | */ 190 | static int isRecursive = 1; 191 | 192 | /* recursively generates code by tree traversal */ 193 | void cGen( TreeNode * tree) 194 | { 195 | int tmp; 196 | TreeNode * p1, * p2, * p3; 197 | int savedLoc1,savedLoc2,currentLoc; 198 | 199 | VarSymbol *var; 200 | FunSymbol *fun; 201 | 202 | while(tree){ 203 | 204 | 205 | switch (tree->astType) { 206 | 207 | case FUNDEC_AST: 208 | 209 | if (TraceCode) emitComment("-> function:"); 210 | 211 | p1 = tree->child[0];/*head*/ 212 | p2 = tree->child[1];/*body*/ 213 | 214 | fun = lookup_fun(p1->attr.name); 215 | fun->offset = emitSkip(0); 216 | 217 | 218 | /*prepare bp & sp*/ 219 | emitRM("LDA",sp,-1,sp,"push prepare"); 220 | emitRM("ST",bp,0,sp,"push old bp"); 221 | emitRM("LDA",bp,0,sp,"let bp == sp"); 222 | emitRM("LDA",sp,-(p2->symbolTable->size),sp,"allocate for local variables"); 223 | 224 | /*push param symtab, prepare for body*/ 225 | 226 | pushTable(fun->symbolTable); 227 | /*generate body*/ 228 | cGen(p2); 229 | popTable(); 230 | 231 | /*generate return code for void functions*/ 232 | if(p1->type == TYPE_VOID){ 233 | /*return*/ 234 | emitRM("LDA",sp,0,bp,"let sp == bp"); 235 | emitRM("LDA",sp,2,sp,"pop prepare"); 236 | emitRM("LD",bp,-2,sp,"pop old bp"); 237 | emitRM("LD",pc,-1,sp,"pop return addr"); 238 | } 239 | 240 | if (TraceCode) emitComment("<- function"); 241 | 242 | break; 243 | 244 | case COMPOUND_AST: 245 | 246 | if (TraceCode) emitComment("-> compound"); 247 | p1 = tree->child[1];/*statements*/ 248 | 249 | if(tree->symbolTable) 250 | pushTable(tree->symbolTable); 251 | 252 | cGen(p1); 253 | 254 | if(tree->symbolTable) 255 | popTable(); 256 | if (TraceCode) emitComment("<- compound"); 257 | break; 258 | 259 | case SELESTMT_AST : 260 | if (TraceCode) emitComment("-> if") ; 261 | p1 = tree->child[0] ; 262 | p2 = tree->child[1] ; 263 | p3 = tree->child[2] ; 264 | /* generate code for test expression */ 265 | cGen(p1); 266 | savedLoc1 = emitSkip(1) ; 267 | emitComment("jump to else "); 268 | /* recurse on then part */ 269 | cGen(p2); 270 | savedLoc2 = emitSkip(1) ; 271 | emitComment("jump to end"); 272 | currentLoc = emitSkip(0) ; 273 | emitBackup(savedLoc1) ; 274 | emitRM("JEQ",ax,currentLoc,zero,"if: jmp to else"); 275 | emitRestore() ; 276 | /* recurse on else part */ 277 | cGen(p3); 278 | currentLoc = emitSkip(0) ; 279 | emitBackup(savedLoc2) ; 280 | emitRM("LDA",pc,currentLoc,zero,"jmp to end") ; 281 | emitRestore() ; 282 | if (TraceCode) emitComment("<- if") ; 283 | break; 284 | 285 | case ITERSTMT_AST: 286 | if (TraceCode) emitComment("-> while") ; 287 | p1 = tree->child[0] ; 288 | p2 = tree->child[1] ; 289 | savedLoc1 = emitSkip(0); 290 | emitComment("jump here after body"); 291 | /* generate code for test */ 292 | cGen(p1); 293 | savedLoc2 = emitSkip(1); 294 | emitComment("jump to end if test fails"); 295 | /* generate code for body */ 296 | cGen(p2); 297 | emitRM("LDA",pc,savedLoc1,zero,"jump to test"); 298 | currentLoc = emitSkip(0); 299 | emitBackup(savedLoc2); 300 | emitRM("JEQ",ax,currentLoc,zero,"jump to end"); 301 | emitRestore(); 302 | if (TraceCode) emitComment("<- while") ; 303 | break; 304 | 305 | case RETSTMT_AST: 306 | if (TraceCode) emitComment("-> return"); 307 | p1 = tree->child[0]; 308 | /*Only calculate non-voild value*/ 309 | if(tree->type != TYPE_VOID) 310 | cGen(p1); 311 | 312 | /*return*/ 313 | emitRM("LDA",sp,0,bp,"let sp == bp"); 314 | emitRM("LDA",sp,2,sp,"pop prepare"); 315 | emitRM("LD",bp,-2,sp,"pop old bp"); 316 | emitRM("LD",pc,-1,sp,"pop return addr"); 317 | 318 | if (TraceCode) emitComment("<- return"); 319 | break; 320 | 321 | 322 | case NUM_AST: 323 | if(TraceCode) emitComment("-> number"); 324 | emitRM("LDC",ax,tree->attr.value,0,"store number"); 325 | if(TraceCode) emitComment("<- number"); 326 | break; 327 | 328 | case VAR_AST: 329 | if(TraceCode) emitComment("-> variable"); 330 | 331 | var = lookup_var(tree->attr.name); 332 | emitGetAddr(var); 333 | 334 | if(getValue){ 335 | if(var->type == TYPE_ARRAY) 336 | emitRM("LDA",ax,0,bx,"get array variable value( == address)"); 337 | else 338 | emitRM("LD",ax,0,bx,"get variable value"); 339 | 340 | } 341 | if(TraceCode) emitComment("<- variable"); 342 | break; 343 | 344 | case ARRAYVAR_AST: 345 | if(TraceCode) emitComment("-> array element"); 346 | p1 = tree->child[0];/*index expression*/ 347 | 348 | var = lookup_var(tree->attr.name); 349 | emitGetAddr(var); 350 | 351 | /* protect bx*/ 352 | emitRM("LDA",sp,-1,sp,"push prepare"); 353 | emitRM("ST",bx,0,sp,"protect array address"); 354 | 355 | tmp = getValue; 356 | getValue = 1; 357 | cGen(p1); 358 | getValue = tmp; 359 | 360 | /* recover bx*/ 361 | emitRM("LDA",sp,1,sp,"pop prepare"); 362 | emitRM("LD",bx,-1,sp,"recover array address"); 363 | 364 | emitRO("SUB",bx,bx,ax,"get address of array element"); 365 | if(getValue) 366 | emitRM("LD",ax,0,bx,"get value of array element"); 367 | 368 | if(TraceCode) emitComment("<- array element"); 369 | break; 370 | 371 | 372 | 373 | 374 | case ASSIGN_AST: 375 | if (TraceCode) emitComment("-> assign") ; 376 | p1 = tree->child[0];/*left*/ 377 | p2 = tree->child[1];/*right*/ 378 | /* left value (get its address -> bx)*/ 379 | getValue = 0; 380 | cGen(p1); 381 | /* protect bx*/ 382 | emitRM("LDA",sp,-1,sp,"push prepare"); 383 | emitRM("ST",bx,0,sp,"protect bx"); 384 | /* right value -> ax*/ 385 | getValue = 1; 386 | cGen(p2); 387 | /* recover bx*/ 388 | emitRM("LDA",sp,1,sp,"pop prepare"); 389 | emitRM("LD",bx,-1,sp,"recover bx"); 390 | /* now we can assign*/ 391 | emitRM("ST",ax,0,bx,"assign: store"); 392 | if (TraceCode) emitComment("<- assign") ; 393 | break; 394 | 395 | case EXP_AST: 396 | if (TraceCode) emitComment("-> op") ; 397 | p1 = tree->child[0];/*left*/ 398 | p2 = tree->child[1];/*right*/ 399 | 400 | cGen(p1); 401 | /* store left operand */ 402 | emitRM("LDA",sp,-1,sp,"push prepare"); 403 | emitRM("ST",ax,0,sp,"op: protect left"); 404 | 405 | cGen(p2); 406 | /* now load left operand */ 407 | emitRM("LDA",sp,1,sp,"pop prepare"); 408 | emitRM("LD",bx,-1,sp,"op: recover left"); 409 | switch (tree->attr.op) { 410 | case PLUS : 411 | emitRO("ADD",ax,bx,ax,"op +"); 412 | break; 413 | case MINUS : 414 | emitRO("SUB",ax,bx,ax,"op -"); 415 | break; 416 | case MULTI : 417 | emitRO("MUL",ax,bx,ax,"op *"); 418 | break; 419 | case DIV : 420 | emitRO("DIV",ax,bx,ax,"op /"); 421 | break; 422 | case EQ : 423 | emitRO("SUB",ax,bx,ax,"op ==") ; 424 | emitRM("JEQ",ax,2,pc,"br if true") ; 425 | emitRM("LDC",ax,0,0,"false case") ; 426 | emitRM("LDA",pc,1,pc,"unconditional jmp") ; 427 | emitRM("LDC",ax,1,0,"true case") ; 428 | break; 429 | case NE : 430 | emitRO("SUB",ax,bx,ax,"op !=") ; 431 | emitRM("JNE",ax,2,pc,"br if true") ; 432 | emitRM("LDC",ax,0,0,"false case") ; 433 | emitRM("LDA",pc,1,pc,"unconditional jmp") ; 434 | emitRM("LDC",ax,1,0,"true case") ; 435 | break; 436 | case LT : 437 | emitRO("SUB",ax,bx,ax,"op <") ; 438 | emitRM("JLT",ax,2,pc,"br if true") ; 439 | emitRM("LDC",ax,0,0,"false case") ; 440 | emitRM("LDA",pc,1,pc,"unconditional jmp") ; 441 | emitRM("LDC",ax,1,0,"true case") ; 442 | break; 443 | case GT : 444 | emitRO("SUB",ax,bx,ax,"op >") ; 445 | emitRM("JGT",ax,2,pc,"br if true") ; 446 | emitRM("LDC",ax,0,0,"false case") ; 447 | emitRM("LDA",pc,1,pc,"unconditional jmp") ; 448 | emitRM("LDC",ax,1,0,"true case") ; 449 | break; 450 | case LE : 451 | emitRO("SUB",ax,bx,ax,"op <=") ; 452 | emitRM("JLE",ax,2,pc,"br if true") ; 453 | emitRM("LDC",ax,0,0,"false case") ; 454 | emitRM("LDA",pc,1,pc,"unconditional jmp") ; 455 | emitRM("LDC",ax,1,0,"true case") ; 456 | break; 457 | case GE : 458 | emitRO("SUB",ax,bx,ax,"op >=") ; 459 | emitRM("JGE",ax,2,pc,"br if true") ; 460 | emitRM("LDC",ax,0,0,"false case") ; 461 | emitRM("LDA",pc,1,pc,"unconditional jmp") ; 462 | emitRM("LDC",ax,1,0,"true case") ; 463 | break; 464 | default: 465 | emitComment("BUG: Unknown operator"); 466 | break; 467 | } 468 | if (TraceCode) emitComment("<- op") ; 469 | break; 470 | 471 | 472 | case CALL_AST: 473 | if (TraceCode) emitComment("-> call") ; 474 | p1 = tree->child[0];/*arguments*/ 475 | 476 | while(p1 != NULL){ 477 | pushParam(p1); 478 | p1 = p1->sibling; 479 | } 480 | 481 | /* first - push parameters */ 482 | isRecursive = 0; 483 | while( (p1 = popParam()) != NULL){ 484 | cGen(p1); 485 | emitRM("LDA",sp,-1,sp,"push prepare"); 486 | emitRM("ST",ax,0,sp,"push parameters"); 487 | } 488 | isRecursive = 1; 489 | 490 | /*second - call function*/ 491 | fun = lookup_fun(tree->attr.name); 492 | emitCall(fun); 493 | 494 | 495 | if (TraceCode) emitComment("<- call") ; 496 | break; 497 | 498 | default: 499 | break; 500 | } 501 | 502 | if(isRecursive) 503 | tree = tree->sibling; 504 | else 505 | break; 506 | } 507 | } 508 | 509 | 510 | 511 | /* the primary function of the code generator */ 512 | void codeGen() 513 | { 514 | 515 | 516 | emitPrelude(); 517 | 518 | 519 | /* Jump to main() */ 520 | if (TraceCode) emitComment("Jump to main()"); 521 | int loc = emitSkip(6); /*A call consumes 5 instructions, and we need halt after main()*/ 522 | 523 | 524 | emitInput(); 525 | emitOutput(); 526 | 527 | 528 | cGen(ASTRoot); 529 | 530 | /* Fill up jump-to-main code */ 531 | emitBackup(loc); 532 | FunSymbol* fun = lookup_fun("main"); 533 | emitCall(fun); 534 | emitRO("HALT",0,0,0,"END OF PROGRAM"); 535 | 536 | } -------------------------------------------------------------------------------- /codegen.h: -------------------------------------------------------------------------------- 1 | /*code generator 2 | * - To generate utimate TM codes from syntax tree and symbol tables. 3 | */ 4 | 5 | #ifndef CODEGEN_H 6 | #define CODEGEN_H 7 | 8 | #include "globals.h" 9 | 10 | /*debug flag*/ 11 | #define TraceCode TRUE 12 | 13 | /*data register*/ 14 | #define zero 0 15 | #define ax 1 16 | #define bx 2 17 | 18 | /*pointer register*/ 19 | #define sp 4 20 | #define bp 5 21 | #define gp 6 22 | #define pc 7 23 | 24 | 25 | /* code emitting utilities */ 26 | 27 | /* prints a comment line with comment c in the code file 28 | */ 29 | void emitComment( char * c ); 30 | 31 | /* emits a register-only TM instruction 32 | * op = the opcode 33 | * r = target register 34 | * s = 1st source register 35 | * t = 2nd source register 36 | * c = a comment to be printed if TraceCode is TRUE 37 | */ 38 | void emitRO( char *op, int r, int s, int t, char *c); 39 | 40 | /* emits a register-to-memory TM instruction 41 | * op = the opcode 42 | * r = target register 43 | * d = the offset 44 | * s = the base register 45 | * c = a comment to be printed if TraceCode is TRUE 46 | */ 47 | void emitRM( char * op, int r, int d, int s, char *c); 48 | 49 | /* skips "howMany" code locations for later backpatch. 50 | * It also returns the current code position 51 | */ 52 | int emitSkip( int howMany); 53 | 54 | /* backs up to loc = a previously skipped location 55 | */ 56 | void emitBackup( int loc); 57 | 58 | /* restores the current code position to the highest previously unemitted position 59 | */ 60 | void emitRestore(void); 61 | 62 | 63 | /* generate standard prelude */ 64 | void emitPrelude(); 65 | 66 | /* generate codes for input() */ 67 | void emitInput(); 68 | 69 | /* generate codes for output() */ 70 | void emitOutput(); 71 | 72 | /* emit one instruction to get the address of a symbol */ 73 | void emitGetAddr(VarSymbol* var); 74 | 75 | /* emits 5 instructions to call a function*/ 76 | void emitCall(FunSymbol* fun); 77 | 78 | 79 | 80 | 81 | /* recursively generates code by tree traversal */ 82 | void cGen( TreeNode * tree); 83 | 84 | /* primary function 85 | * visit the syntax tree and generate codes 86 | */ 87 | void codeGen(); 88 | 89 | 90 | #endif -------------------------------------------------------------------------------- /globals.h: -------------------------------------------------------------------------------- 1 | #ifndef GLOBALS_H 2 | #define GLOBALS_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | 10 | #ifndef FALSE 11 | #define FALSE 0 12 | #endif 13 | 14 | #ifndef TRUE 15 | #define TRUE 1 16 | #endif 17 | 18 | 19 | #define ASSERT(x) for(;!(x);assert(x)) 20 | 21 | 22 | /* SIZE is the size of the hash table */ 23 | #define SIZE 211 24 | /* SHIFT is the power of two used as multiplier in hash function */ 25 | #define SHIFT 4 26 | 27 | #define DEBUG_SYM 28 | 29 | 30 | /* From main.c*/ 31 | extern FILE* source; /* source code text file */ 32 | extern FILE* listing; /* listing output text file */ 33 | extern FILE* code; /* code text file for TM simulator */ 34 | 35 | 36 | 37 | /**************************************************/ 38 | /*********** Syntax tree for parsing ************/ 39 | /**************************************************/ 40 | 41 | #define MAXCHILDREN 4 42 | 43 | 44 | typedef enum{GLOBAL, LOCAL, PARAM} Scope; 45 | /* ExpType is used for type checking */ 46 | typedef enum {TYPE_INTEGER, TYPE_VOID, TYPE_ARRAY, TYPE_UNDEFINED} ExpType; 47 | 48 | typedef enum { TYPE_AST, VARDEC_AST, ARRAYDEC_AST, FUNDEC_AST, 49 | FUNHEAD_AST, PARAMID_AST, PARAMARRAY_AST, 50 | COMPOUND_AST, 51 | EXPSTMT_AST, SELESTMT_AST, ITERSTMT_AST, RETSTMT_AST, ASSIGN_AST, 52 | EXP_AST, VAR_AST, ARRAYVAR_AST, 53 | FACTOR_AST, 54 | CALL_AST, NUM_AST} ASTType; 55 | 56 | typedef struct var_symbol VarSymbol; 57 | struct var_symbol { 58 | char* name; 59 | Scope scope; 60 | ExpType type; 61 | int offset; 62 | struct var_symbol* next;/*used in hashTable*/ 63 | struct var_symbol* next_FIFO;/*used in FIFO*/ 64 | }; 65 | 66 | typedef struct symbol_table SymbolTable; 67 | struct symbol_table { 68 | int size; 69 | Scope scope; 70 | VarSymbol* hashTable[SIZE]; 71 | /* FIFO queue used to record orders of variables*/ 72 | VarSymbol* varList; 73 | struct symbol_table* next; 74 | }; 75 | 76 | typedef struct fun_symbol FunSymbol; 77 | struct fun_symbol { 78 | char* name; 79 | ExpType type; 80 | int offset; 81 | int paramNum; 82 | SymbolTable* symbolTable; 83 | struct fun_symbol* next; 84 | }; 85 | 86 | typedef struct ASTNode TreeNode; 87 | struct ASTNode{ 88 | int lineno; 89 | struct ASTNode* child[MAXCHILDREN]; 90 | struct ASTNode* sibling; 91 | ASTType astType; 92 | ExpType type; /* for type checking of exps */ 93 | struct{ 94 | int op; 95 | int value; 96 | char* name; 97 | } attr; 98 | SymbolTable* symbolTable; 99 | 100 | }; 101 | 102 | 103 | /* From symtab.c */ 104 | extern SymbolTable* tables; 105 | extern FunSymbol* funs; 106 | extern SymbolTable* CompoundST; 107 | extern SymbolTable* ParamST; 108 | 109 | /* From AST.c*/ 110 | extern TreeNode *ASTRoot; 111 | 112 | 113 | #endif 114 | -------------------------------------------------------------------------------- /main: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koyabr/C-Compiler/4ba98e20b3f6ac02eb0ec1faf90d1f637828010c/main -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | /*************************** 2 | C-minus Compiler - 3 | Compiler Design Course Project 4 | ***************************/ 5 | 6 | #include "globals.h" 7 | #include "parse.h" 8 | #include "symtab.h" 9 | #include "codegen.h" 10 | 11 | #define FILE_NAME_LEN 100 12 | 13 | FILE* source; /* source code text file */ 14 | FILE* listing; /* listing output text file */ 15 | FILE* code; /* code text file for TM simulator */ 16 | 17 | int main(int argc, char *argv[]) 18 | { 19 | 20 | char sourcefile[FILE_NAME_LEN]; /* source code file name */ 21 | 22 | if (argc != 2){ 23 | fprintf(stderr,"usage: %s \n",argv[0]); 24 | strcpy(sourcefile,"./test/test0.cm") ; 25 | } 26 | else{ 27 | strcpy(sourcefile,argv[1]) ; 28 | } 29 | 30 | source = fopen(sourcefile,"r"); 31 | ASSERT(source != NULL){ 32 | fprintf(stderr,"File %s not found.\n",sourcefile); 33 | } 34 | 35 | listing = stdout; /* send listing to screen */ 36 | fprintf(listing,"\nC-minus Compiler\ntarget: %s\n",sourcefile); 37 | 38 | initTable(); 39 | yyrestart(source); 40 | yyparse(); 41 | fclose(source); 42 | 43 | fprintf(listing,"\nParsing Finished...\n"); 44 | fprintf(listing,"\nSemantic Analysis Finished...\n"); 45 | 46 | char * codefile = (char *) calloc(strlen(sourcefile), sizeof(char)); 47 | strcpy(codefile,sourcefile); 48 | strcat(codefile,".tm"); 49 | code = fopen(codefile,"w"); 50 | ASSERT(code != NULL){ 51 | fprintf(stderr, "Unable to open %s for output.\n",codefile); 52 | } 53 | codeGen(); 54 | fclose(code); 55 | 56 | fprintf(listing,"\nCode Generation Finished...\n"); 57 | fprintf(listing, "\nSee %s for result codes.\n", codefile); 58 | 59 | return 0; 60 | } 61 | 62 | 63 | -------------------------------------------------------------------------------- /raw/parse.y: -------------------------------------------------------------------------------- 1 | /*Yacc Parser*/ 2 | 3 | %{ 4 | #define YYPARSER 5 | 6 | #include "globals.h" 7 | #include "AST.h" 8 | 9 | extern int yylineno; 10 | extern char* yytext; 11 | 12 | %} 13 | 14 | /* if else return while int void */ 15 | %token IF ELSE RETURN WHILE INT VOID 16 | /* ( ) { } " [ ] , ; = */ 17 | %token LBracket RBracket LBrace RBrace Quote LSB RSB COMMA SEMI ASSIGN 18 | 19 | 20 | /* - + * / | & */ 21 | %left MINUS PLUS MULTI DIV 22 | /* > < >= <= == != */ 23 | %left GT LT GE LE EQ NE 24 | 25 | 26 | 27 | 28 | %token NUMBER 29 | %token ID 30 | 31 | %type program declaration_list declaration 32 | %type var_declaration fun_declaration type_specifier 33 | %type fun_head params param_list param compound_stmt 34 | %type local_declarations statement_list statement 35 | %type expression_stmt selection_stmt iteration_stmt return_stmt 36 | %type expression var 37 | %type simple_expression additive_expression term factor call args arg_list 38 | %type relop addop mulop 39 | 40 | %union{ 41 | char* name; /* terminal token: for symbol's name */ 42 | int value; /* terminal token: for number */ 43 | struct ASTNode* node; /* unterminal token: abstract syntax tree node */ 44 | } 45 | 46 | 47 | %% 48 | program: declaration_list {ASTRoot = $1;} 49 | ; 50 | 51 | declaration_list: declaration_list declaration {$$ = newDecList($1, $2);} 52 | | declaration {$$ = $1;} 53 | ; 54 | 55 | declaration: var_declaration {$$ = $1;} 56 | | fun_declaration {$$ = $1;} 57 | ; 58 | 59 | type_specifier: INT {$$ = newTypeSpe(TYPE_INTEGER, yylineno);} 60 | | VOID {$$ = newTypeSpe(TYPE_VOID, yylineno);} 61 | ; 62 | 63 | var_declaration: type_specifier ID SEMI {$$ = newVarDec($1, $2, yylineno);} 64 | | type_specifier ID LSB NUMBER RSB SEMI {$$ = newArrayDec($1, $2, $4, yylineno);} 65 | ; 66 | 67 | fun_declaration: fun_head compound_stmt {$$ = newFunDec($1, $2, yylineno);} 68 | ; 69 | 70 | fun_head: type_specifier ID LBracket params RBracket {$$ = newFunHead($1, $2, $4, yylineno);} 71 | ; 72 | 73 | compound_stmt: LBrace local_declarations statement_list RBrace {$$ = newCompound($2, $3, yylineno);} 74 | ; 75 | 76 | params: param_list {$$ = $1;} 77 | | VOID {$$ = NULL;} 78 | ; 79 | 80 | param_list: param_list COMMA param {$$ = newParamList($1, $3);} 81 | | param {$$ = newParamList(NULL, $1);} 82 | ; 83 | 84 | param: type_specifier ID {$$ = newParam($1, $2, 0, yylineno);} 85 | | type_specifier ID LSB RSB {$$ = newParam($1, $2, 1, yylineno);} 86 | ; 87 | 88 | 89 | 90 | local_declarations: local_declarations var_declaration {$$ = newLocalDecs($1, $2);} 91 | | {$$ = NULL;} 92 | ; 93 | 94 | statement_list: statement_list statement {$$ = newStmtList($1, $2, yylineno);} 95 | | {$$ = NULL;} 96 | ; 97 | 98 | statement: expression_stmt {$$ = $1;} 99 | | compound_stmt {$$ = $1;} 100 | | selection_stmt {$$ = $1;} 101 | | iteration_stmt {$$ = $1;} 102 | | return_stmt {$$ = $1;} 103 | ; 104 | 105 | expression_stmt: expression SEMI {$$ = $1;} 106 | | SEMI {$$ = NULL;} 107 | ; 108 | 109 | selection_stmt: IF LBracket expression RBracket statement {$$ = newSelectStmt($3,$5,NULL, yylineno);} 110 | | IF LBracket expression RBracket statement ELSE statement {$$ = newSelectStmt($3,$5,$7, yylineno);} 111 | ; 112 | 113 | iteration_stmt: WHILE LBracket expression RBracket statement {$$ = newIterStmt($3, $5, yylineno);} 114 | ; 115 | 116 | return_stmt: RETURN SEMI {$$ = newRetStmt(NULL, yylineno);} 117 | | RETURN expression SEMI {$$ = newRetStmt($2, yylineno);} 118 | ; 119 | 120 | expression: var ASSIGN expression {$$ = newAssignExp($1, $3, yylineno);} 121 | | simple_expression {$$ = $1;} 122 | ; 123 | 124 | var: ID {$$ = newVar($1, yylineno);} 125 | | ID LSB expression RSB {$$ = newArrayVar($1, $3, yylineno);} 126 | ; 127 | 128 | simple_expression: additive_expression relop additive_expression {$$ = newSimpExp($1, $2, $3, yylineno);} 129 | | additive_expression {$$ = $1;} 130 | ; 131 | 132 | relop: GT {$$ = GT;} 133 | | LT {$$ = LT;} 134 | | GE {$$ = GE;} 135 | | LE {$$ = LE;} 136 | | EQ {$$ = EQ;} 137 | | NE {$$ = NE;} 138 | ; 139 | 140 | additive_expression: additive_expression addop term {$$ = newAddExp($1, $2, $3, yylineno);} 141 | | term {$$ = $1;} 142 | ; 143 | 144 | addop: PLUS {$$ = PLUS;} 145 | | MINUS {$$ = MINUS;} 146 | ; 147 | 148 | term: term mulop factor {$$ = newTerm($1, $2, $3, yylineno);} 149 | | factor {$$ = $1;} 150 | ; 151 | 152 | mulop: MULTI {$$ = MULTI;} 153 | | DIV {$$ = DIV;} 154 | ; 155 | 156 | factor: LBracket expression RBracket {$$ = $2;} 157 | | var {$$ = $1;} 158 | | call {$$ = $1;} 159 | | NUMBER {$$ = newNumNode($1, yylineno);} 160 | ; 161 | 162 | call: ID LBracket args RBracket {$$ = newCall($1, $3, yylineno);} 163 | ; 164 | 165 | args: arg_list {$$ = $1;} 166 | | {$$ = NULL;} 167 | ; 168 | 169 | arg_list: arg_list COMMA expression {$$ = newArgList($1, $3);} 170 | | expression {$$ = $1;} 171 | ; 172 | 173 | %% 174 | 175 | 176 | int yyerror(char *errmsg) 177 | { 178 | fprintf(stderr, "%d: %s at '%s' \n", yylineno, errmsg, yytext); 179 | return 0; 180 | } 181 | 182 | -------------------------------------------------------------------------------- /raw/scan.l: -------------------------------------------------------------------------------- 1 | /* Lex Scanner */ 2 | 3 | %{ 4 | #include "globals.h" 5 | #include "parse.h" 6 | %} 7 | %option noyywrap 8 | %option yylineno 9 | 10 | digit [0-9] 11 | number {digit}+ 12 | letter [a-zA-Z] 13 | identifier {letter}+ 14 | newline \n 15 | whitespace [ \t]+ 16 | 17 | %x C_COMMENT 18 | 19 | %% 20 | 21 | 22 | "/*" { BEGIN(C_COMMENT); } 23 | "*/" { BEGIN(INITIAL); } 24 | . { } 25 | 26 | 27 | 28 | "if" {return IF;} 29 | "else" {return ELSE;} 30 | "return" {return RETURN;} 31 | "while" {return WHILE;} 32 | "=" {return ASSIGN;} 33 | 34 | "int" {return INT;} 35 | "void" {return VOID;} 36 | 37 | "(" return LBracket; 38 | ")" {return RBracket;} 39 | "{" {return LBrace;} 40 | "}" {return RBrace;} 41 | "\"" {return Quote;} 42 | "[" {return LSB;} 43 | "]" {return RSB;} 44 | "," {return COMMA;} 45 | ";" {return SEMI;} 46 | "\n" {} 47 | 48 | "-" {return MINUS;} 49 | "+" {return PLUS;} 50 | "*" {return MULTI;} 51 | "/" {return DIV;} 52 | 53 | ">" {return GT;} 54 | "<" {return LT;} 55 | ">=" {return GE;} 56 | "<=" {return LE;} 57 | "==" {return EQ;} 58 | "!=" {return NE;} 59 | 60 | {number} { 61 | yylval.value = atoi(yytext); 62 | return NUMBER; 63 | } 64 | 65 | {identifier} { 66 | yylval.name = strdup(yytext); 67 | return ID; 68 | } 69 | 70 | {whitespace} {/* skip */} 71 | 72 | 73 | 74 | 75 | . {fprintf(stderr, "MISS MATCH: %c\n", yytext[0]);} 76 | %% 77 | -------------------------------------------------------------------------------- /symtab.c: -------------------------------------------------------------------------------- 1 | /*build symbol tables 2 | * and function tables 3 | */ 4 | 5 | #include "globals.h" 6 | #include "symtab.h" 7 | 8 | /* tables store different symbol tables, 9 | * incluidng global, local and param. 10 | */ 11 | SymbolTable* tables = NULL; 12 | /* funs store all function symbols */ 13 | FunSymbol* funs = NULL; 14 | 15 | 16 | 17 | /* temporary table used to allocate small symtabs for Compound & Param */ 18 | SymbolTable* CompoundST; 19 | SymbolTable* ParamST; 20 | 21 | 22 | 23 | /* the hash function */ 24 | int hash ( char * key ) 25 | { 26 | int temp = 0; 27 | int i = 0; 28 | while (key[i] != '\0') 29 | { temp = ((temp << SHIFT) + key[i]) % SIZE; 30 | ++i; 31 | } 32 | return temp; 33 | } 34 | 35 | /* Note: we insert for input()&output() here*/ 36 | void initTable() 37 | { 38 | CompoundST = newSymbolTable(LOCAL); 39 | ParamST = newSymbolTable(PARAM); 40 | tables = newSymbolTable(GLOBAL); 41 | 42 | insert_fun("input", ParamST, 0, TYPE_INTEGER); 43 | ParamST = newSymbolTable(PARAM); 44 | 45 | pushTable(ParamST); 46 | insert_var("i", PARAM, ParamST->size++, TYPE_INTEGER); 47 | popTable(); 48 | insert_fun("output", ParamST, ParamST->size, TYPE_VOID); 49 | ParamST = newSymbolTable(PARAM); 50 | } 51 | 52 | /* create a new symbol table of certain scope */ 53 | SymbolTable* newSymbolTable(Scope scope) 54 | { 55 | int i; 56 | SymbolTable* st = (SymbolTable*)malloc(sizeof(SymbolTable)); 57 | ASSERT(st != NULL){ 58 | fprintf(stderr, "Failed to malloc for symbal table.\n"); 59 | } 60 | st->scope = scope; 61 | st->size = 0; 62 | st->next = NULL; 63 | st->varList = NULL; 64 | for(i = 0;ihashTable[i] = NULL; 66 | return st; 67 | } 68 | 69 | 70 | /* manipulate the symbol table stack*/ 71 | SymbolTable* topTable() 72 | { 73 | return tables; 74 | } 75 | 76 | SymbolTable* popTable() 77 | { 78 | ASSERT(tables != NULL){ 79 | fprintf(stderr, "Pop an empty table list.\n"); 80 | } 81 | SymbolTable* st = tables; 82 | tables = tables->next; 83 | return st; 84 | } 85 | void pushTable(SymbolTable* st) 86 | { 87 | ASSERT(st != NULL){ 88 | fprintf(stderr, "Push an null table.\n"); 89 | } 90 | st->next = tables; 91 | tables = st; 92 | } 93 | 94 | 95 | /* look up for variables in top symbol table*/ 96 | VarSymbol* lookup_var_top(char* name) 97 | { 98 | if(tables == NULL) 99 | return NULL; 100 | 101 | VarSymbol* l; 102 | int h = hash(name); 103 | for(l = tables->hashTable[h]; l!=NULL; l=l->next){ 104 | if(strcmp(l->name, name) == 0 ) 105 | break; 106 | } 107 | 108 | return l; 109 | } 110 | 111 | /* lookup for all tables in the stack */ 112 | VarSymbol* lookup_var (char * name) 113 | { 114 | if(tables == NULL) 115 | return NULL; 116 | 117 | 118 | int h = hash(name); 119 | SymbolTable* st; 120 | VarSymbol* l; 121 | 122 | for(st = tables; st!=NULL; st=st->next) /* iteration of all symbol tables in stack */ 123 | { 124 | for(l = st->hashTable[h]; l!=NULL; l=l->next) /* iteration of all linkedlist in a symboltable */ 125 | { 126 | if(strcmp(l->name, name)==0) 127 | return l; 128 | } 129 | } 130 | return NULL; /* may be NULL */ 131 | } 132 | 133 | /* look up for a function symbol*/ 134 | FunSymbol* lookup_fun(char * name) 135 | { 136 | if(funs == NULL) 137 | return NULL; 138 | FunSymbol* fs; 139 | for(fs=funs;fs!=NULL; fs = fs->next) 140 | { 141 | if(strcmp(fs->name, name)==0) 142 | break; 143 | } 144 | return fs; 145 | } 146 | 147 | /* Always insert var into the top symbol table*/ 148 | int insert_var(char * name, Scope scope, int offset, ExpType type) 149 | { 150 | VarSymbol* l, *tmp; 151 | int h = hash(name); 152 | 153 | /*Check duplication*/ 154 | if(tables == NULL){ 155 | l = NULL; 156 | } 157 | else{ 158 | l = tables->hashTable[h]; 159 | while ((l != NULL) && (strcmp(name,l->name) != 0)) 160 | l = l->next; 161 | } 162 | 163 | 164 | if (l != NULL){ 165 | fprintf(stderr, "Duplicate declarations of variable: %s.\n", name); 166 | return 1; 167 | } 168 | 169 | l = (VarSymbol*) malloc(sizeof(VarSymbol)); 170 | ASSERT(l != NULL){ 171 | fprintf(stderr, "Failed to malloc for VarSymbol.\n" ); 172 | } 173 | l->name = strdup(name); 174 | l->scope = scope; 175 | l->type = type; 176 | l->offset = offset; 177 | l->next = tables->hashTable[h]; 178 | tables->hashTable[h] = l; 179 | l->next_FIFO = NULL; 180 | if(tables->varList == NULL){ /*First insertion*/ 181 | tables->varList = l; 182 | } 183 | else{ 184 | for(tmp=tables->varList; tmp->next_FIFO != NULL; tmp = tmp->next_FIFO); 185 | tmp->next_FIFO = l; 186 | } 187 | 188 | return 0; 189 | 190 | } 191 | 192 | int insert_fun(char* name, SymbolTable* st, int num, ExpType type) 193 | { 194 | FunSymbol* fs; 195 | 196 | /*Check duplication*/ 197 | if(lookup_fun(name) != NULL){ 198 | fprintf(stderr, "Duplicate declarations of function: %s\n", name); 199 | return 1; 200 | } 201 | fs = (FunSymbol*)malloc(sizeof(FunSymbol)); 202 | ASSERT(fs != NULL){ 203 | fprintf(stderr, "Failed to malloc for FunSymbol.\n"); 204 | } 205 | fs->name = strdup(name); 206 | fs->type = type; 207 | fs->paramNum = num; 208 | fs->symbolTable = st; 209 | fs->next = funs; 210 | funs = fs; 211 | 212 | return 0; 213 | } 214 | 215 | 216 | 217 | 218 | void printSymTab(SymbolTable* st) 219 | { 220 | int i; 221 | fprintf(listing,"Variable Name Offset\n"); 222 | fprintf(listing,"------------- ------\n"); 223 | VarSymbol* vs = NULL; 224 | for (i=0;ihashTable[i]; vs != NULL; vs=vs->next) 227 | { 228 | fprintf(listing, "%-14s", vs->name); 229 | fprintf(listing, "%-8d", vs->offset); 230 | fprintf(listing, "\n"); 231 | } 232 | } 233 | 234 | fprintf(listing, "\n"); 235 | } 236 | 237 | 238 | 239 | 240 | 241 | -------------------------------------------------------------------------------- /symtab.h: -------------------------------------------------------------------------------- 1 | /*build symbol tables 2 | * and function tables 3 | */ 4 | 5 | #ifndef SYMTAB_H 6 | #define SYMTAB_H 7 | 8 | #include "globals.h" 9 | 10 | /* the hash function */ 11 | int hash ( char * key ); 12 | 13 | /* initialize symbol tables*/ 14 | void initTable(); 15 | 16 | /* create a new symbol table of certain scope */ 17 | SymbolTable* newSymbolTable(Scope s); 18 | 19 | /* manipulate the symbol table stack*/ 20 | SymbolTable* topTable(); 21 | SymbolTable* popTable(); 22 | void pushTable(SymbolTable* st); 23 | 24 | /* look up for a symbol entry*/ 25 | VarSymbol* lookup_var_top(char* name); 26 | VarSymbol* lookup_var(char * name); 27 | FunSymbol* lookup_fun(char * name); 28 | 29 | /* insert symbol entries */ 30 | int insert_var(char * name, Scope s, int offset, ExpType type); 31 | int insert_fun(char* name, SymbolTable* st, int num, ExpType type); 32 | 33 | 34 | 35 | /* prints a formatted listing of the symbol table */ 36 | void printSymTab(SymbolTable* st); 37 | 38 | 39 | 40 | #endif 41 | 42 | -------------------------------------------------------------------------------- /test/test0.cm: -------------------------------------------------------------------------------- 1 | int main(void) 2 | { 3 | int aa; 4 | int bb; 5 | int cc; 6 | 7 | aa = 3; 8 | bb = 2; 9 | cc = 1; 10 | 11 | cc = bb+cc*aa/bb-cc; 12 | output(cc); 13 | 14 | return 1; 15 | } 16 | -------------------------------------------------------------------------------- /test/test0.cm.tm: -------------------------------------------------------------------------------- 1 | * Begin prelude 2 | 0: LD 6,0(0) load from location 0 3 | 1: ST 0,0(0) clear location 0 4 | 2: LDA 4,0(6) allocate for global variables 5 | * End of prelude 6 | * Jump to main() 7 | * Begin input() 8 | 9: IN 1,0,0 read input into ax 9 | 10: LDA 4,1(4) pop prepare 10 | 11: LD 7,-1(4) pop return addr 11 | * End input() 12 | * Begin output() 13 | 12: LD 1,1(4) load param into ax 14 | 13: OUT 1,0,0 output using ax 15 | 14: LDA 4,1(4) pop prepare 16 | 15: LD 7,-1(4) pop return addr 17 | * End output() 18 | * -> function: 19 | 16: LDA 4,-1(4) push prepare 20 | 17: ST 5,0(4) push old bp 21 | 18: LDA 5,0(4) let bp == sp 22 | 19: LDA 4,-3(4) allocate for local variables 23 | * -> compound 24 | * -> assign 25 | * -> variable 26 | 20: LDA 2,-1(5) get local address 27 | * <- variable 28 | 21: LDA 4,-1(4) push prepare 29 | 22: ST 2,0(4) protect bx 30 | * -> number 31 | 23: LDC 1,3(0) store number 32 | * <- number 33 | 24: LDA 4,1(4) pop prepare 34 | 25: LD 2,-1(4) recover bx 35 | 26: ST 1,0(2) assign: store 36 | * <- assign 37 | * -> assign 38 | * -> variable 39 | 27: LDA 2,-2(5) get local address 40 | * <- variable 41 | 28: LDA 4,-1(4) push prepare 42 | 29: ST 2,0(4) protect bx 43 | * -> number 44 | 30: LDC 1,2(0) store number 45 | * <- number 46 | 31: LDA 4,1(4) pop prepare 47 | 32: LD 2,-1(4) recover bx 48 | 33: ST 1,0(2) assign: store 49 | * <- assign 50 | * -> assign 51 | * -> variable 52 | 34: LDA 2,-3(5) get local address 53 | * <- variable 54 | 35: LDA 4,-1(4) push prepare 55 | 36: ST 2,0(4) protect bx 56 | * -> number 57 | 37: LDC 1,1(0) store number 58 | * <- number 59 | 38: LDA 4,1(4) pop prepare 60 | 39: LD 2,-1(4) recover bx 61 | 40: ST 1,0(2) assign: store 62 | * <- assign 63 | * -> assign 64 | * -> variable 65 | 41: LDA 2,-3(5) get local address 66 | * <- variable 67 | 42: LDA 4,-1(4) push prepare 68 | 43: ST 2,0(4) protect bx 69 | * -> op 70 | * -> op 71 | * -> variable 72 | 44: LDA 2,-2(5) get local address 73 | 45: LD 1,0(2) get variable value 74 | * <- variable 75 | 46: LDA 4,-1(4) push prepare 76 | 47: ST 1,0(4) op: protect left 77 | * -> op 78 | * -> op 79 | * -> variable 80 | 48: LDA 2,-3(5) get local address 81 | 49: LD 1,0(2) get variable value 82 | * <- variable 83 | 50: LDA 4,-1(4) push prepare 84 | 51: ST 1,0(4) op: protect left 85 | * -> variable 86 | 52: LDA 2,-1(5) get local address 87 | 53: LD 1,0(2) get variable value 88 | * <- variable 89 | 54: LDA 4,1(4) pop prepare 90 | 55: LD 2,-1(4) op: recover left 91 | 56: MUL 1,2,1 op * 92 | * <- op 93 | 57: LDA 4,-1(4) push prepare 94 | 58: ST 1,0(4) op: protect left 95 | * -> variable 96 | 59: LDA 2,-2(5) get local address 97 | 60: LD 1,0(2) get variable value 98 | * <- variable 99 | 61: LDA 4,1(4) pop prepare 100 | 62: LD 2,-1(4) op: recover left 101 | 63: DIV 1,2,1 op / 102 | * <- op 103 | 64: LDA 4,1(4) pop prepare 104 | 65: LD 2,-1(4) op: recover left 105 | 66: ADD 1,2,1 op + 106 | * <- op 107 | 67: LDA 4,-1(4) push prepare 108 | 68: ST 1,0(4) op: protect left 109 | * -> variable 110 | 69: LDA 2,-3(5) get local address 111 | 70: LD 1,0(2) get variable value 112 | * <- variable 113 | 71: LDA 4,1(4) pop prepare 114 | 72: LD 2,-1(4) op: recover left 115 | 73: SUB 1,2,1 op - 116 | * <- op 117 | 74: LDA 4,1(4) pop prepare 118 | 75: LD 2,-1(4) recover bx 119 | 76: ST 1,0(2) assign: store 120 | * <- assign 121 | * -> call 122 | * -> variable 123 | 77: LDA 2,-3(5) get local address 124 | 78: LD 1,0(2) get variable value 125 | * <- variable 126 | 79: LDA 4,-1(4) push prepare 127 | 80: ST 1,0(4) push parameters 128 | 81: LDA 1,3(7) store returned PC 129 | 82: LDA 4,-1(4) push prepare 130 | 83: ST 1,0(4) push returned PC 131 | 84: LDC 7,12(0) jump to function 132 | 85: LDA 4,1(4) release parameters 133 | * <- call 134 | * -> return 135 | * -> number 136 | 86: LDC 1,1(0) store number 137 | * <- number 138 | 87: LDA 4,0(5) let sp == bp 139 | 88: LDA 4,2(4) pop prepare 140 | 89: LD 5,-2(4) pop old bp 141 | 90: LD 7,-1(4) pop return addr 142 | * <- return 143 | * <- compound 144 | * <- function 145 | 3: LDA 1,3(7) store returned PC 146 | 4: LDA 4,-1(4) push prepare 147 | 5: ST 1,0(4) push returned PC 148 | 6: LDC 7,16(0) jump to function 149 | 7: LDA 4,0(4) release parameters 150 | 8: HALT 0,0,0 END OF PROGRAM 151 | -------------------------------------------------------------------------------- /test/test1.cm: -------------------------------------------------------------------------------- 1 | /* 2 | A program to perform Euclid's 3 | algorithm to compute gcd. 4 | */ 5 | 6 | int gcd(int u, int v){ 7 | if(v == 0) 8 | return u; 9 | else 10 | return gcd(v, u-u/v*v); 11 | /* u-u/v*v == u mod v */ 12 | } 13 | 14 | void main(void){ 15 | int x; 16 | int y; 17 | x = input(); 18 | y = input(); 19 | output(gcd(x,y)); 20 | } -------------------------------------------------------------------------------- /test/test1.cm.tm: -------------------------------------------------------------------------------- 1 | * Begin prelude 2 | 0: LD 6,0(0) load from location 0 3 | 1: ST 0,0(0) clear location 0 4 | 2: LDA 4,0(6) allocate for global variables 5 | * End of prelude 6 | * Jump to main() 7 | * Begin input() 8 | 9: IN 1,0,0 read input into ax 9 | 10: LDA 4,1(4) pop prepare 10 | 11: LD 7,-1(4) pop return addr 11 | * End input() 12 | * Begin output() 13 | 12: LD 1,1(4) load param into ax 14 | 13: OUT 1,0,0 output using ax 15 | 14: LDA 4,1(4) pop prepare 16 | 15: LD 7,-1(4) pop return addr 17 | * End output() 18 | * -> function: 19 | 16: LDA 4,-1(4) push prepare 20 | 17: ST 5,0(4) push old bp 21 | 18: LDA 5,0(4) let bp == sp 22 | 19: LDA 4,0(4) allocate for local variables 23 | * -> compound 24 | * -> if 25 | * -> op 26 | * -> variable 27 | 20: LDA 2,3(5) get param variable address 28 | 21: LD 1,0(2) get variable value 29 | * <- variable 30 | 22: LDA 4,-1(4) push prepare 31 | 23: ST 1,0(4) op: protect left 32 | * -> number 33 | 24: LDC 1,0(0) store number 34 | * <- number 35 | 25: LDA 4,1(4) pop prepare 36 | 26: LD 2,-1(4) op: recover left 37 | 27: SUB 1,2,1 op == 38 | 28: JEQ 1,2(7) br if true 39 | 29: LDC 1,0(0) false case 40 | 30: LDA 7,1(7) unconditional jmp 41 | 31: LDC 1,1(0) true case 42 | * <- op 43 | * jump to else 44 | * -> return 45 | * -> variable 46 | 33: LDA 2,2(5) get param variable address 47 | 34: LD 1,0(2) get variable value 48 | * <- variable 49 | 35: LDA 4,0(5) let sp == bp 50 | 36: LDA 4,2(4) pop prepare 51 | 37: LD 5,-2(4) pop old bp 52 | 38: LD 7,-1(4) pop return addr 53 | * <- return 54 | * jump to end 55 | 32: JEQ 1,40(0) if: jmp to else 56 | * -> return 57 | * -> call 58 | * -> op 59 | * -> variable 60 | 40: LDA 2,2(5) get param variable address 61 | 41: LD 1,0(2) get variable value 62 | * <- variable 63 | 42: LDA 4,-1(4) push prepare 64 | 43: ST 1,0(4) op: protect left 65 | * -> op 66 | * -> op 67 | * -> variable 68 | 44: LDA 2,2(5) get param variable address 69 | 45: LD 1,0(2) get variable value 70 | * <- variable 71 | 46: LDA 4,-1(4) push prepare 72 | 47: ST 1,0(4) op: protect left 73 | * -> variable 74 | 48: LDA 2,3(5) get param variable address 75 | 49: LD 1,0(2) get variable value 76 | * <- variable 77 | 50: LDA 4,1(4) pop prepare 78 | 51: LD 2,-1(4) op: recover left 79 | 52: DIV 1,2,1 op / 80 | * <- op 81 | 53: LDA 4,-1(4) push prepare 82 | 54: ST 1,0(4) op: protect left 83 | * -> variable 84 | 55: LDA 2,3(5) get param variable address 85 | 56: LD 1,0(2) get variable value 86 | * <- variable 87 | 57: LDA 4,1(4) pop prepare 88 | 58: LD 2,-1(4) op: recover left 89 | 59: MUL 1,2,1 op * 90 | * <- op 91 | 60: LDA 4,1(4) pop prepare 92 | 61: LD 2,-1(4) op: recover left 93 | 62: SUB 1,2,1 op - 94 | * <- op 95 | 63: LDA 4,-1(4) push prepare 96 | 64: ST 1,0(4) push parameters 97 | * -> variable 98 | 65: LDA 2,3(5) get param variable address 99 | 66: LD 1,0(2) get variable value 100 | * <- variable 101 | 67: LDA 4,-1(4) push prepare 102 | 68: ST 1,0(4) push parameters 103 | 69: LDA 1,3(7) store returned PC 104 | 70: LDA 4,-1(4) push prepare 105 | 71: ST 1,0(4) push returned PC 106 | 72: LDC 7,16(0) jump to function 107 | 73: LDA 4,2(4) release parameters 108 | * <- call 109 | 74: LDA 4,0(5) let sp == bp 110 | 75: LDA 4,2(4) pop prepare 111 | 76: LD 5,-2(4) pop old bp 112 | 77: LD 7,-1(4) pop return addr 113 | * <- return 114 | 39: LDA 7,78(0) jmp to end 115 | * <- if 116 | * <- compound 117 | * <- function 118 | * -> function: 119 | 78: LDA 4,-1(4) push prepare 120 | 79: ST 5,0(4) push old bp 121 | 80: LDA 5,0(4) let bp == sp 122 | 81: LDA 4,-2(4) allocate for local variables 123 | * -> compound 124 | * -> assign 125 | * -> variable 126 | 82: LDA 2,-1(5) get local address 127 | * <- variable 128 | 83: LDA 4,-1(4) push prepare 129 | 84: ST 2,0(4) protect bx 130 | * -> call 131 | 85: LDA 1,3(7) store returned PC 132 | 86: LDA 4,-1(4) push prepare 133 | 87: ST 1,0(4) push returned PC 134 | 88: LDC 7,9(0) jump to function 135 | 89: LDA 4,0(4) release parameters 136 | * <- call 137 | 90: LDA 4,1(4) pop prepare 138 | 91: LD 2,-1(4) recover bx 139 | 92: ST 1,0(2) assign: store 140 | * <- assign 141 | * -> assign 142 | * -> variable 143 | 93: LDA 2,-2(5) get local address 144 | * <- variable 145 | 94: LDA 4,-1(4) push prepare 146 | 95: ST 2,0(4) protect bx 147 | * -> call 148 | 96: LDA 1,3(7) store returned PC 149 | 97: LDA 4,-1(4) push prepare 150 | 98: ST 1,0(4) push returned PC 151 | 99: LDC 7,9(0) jump to function 152 | 100: LDA 4,0(4) release parameters 153 | * <- call 154 | 101: LDA 4,1(4) pop prepare 155 | 102: LD 2,-1(4) recover bx 156 | 103: ST 1,0(2) assign: store 157 | * <- assign 158 | * -> call 159 | * -> call 160 | * -> variable 161 | 104: LDA 2,-2(5) get local address 162 | 105: LD 1,0(2) get variable value 163 | * <- variable 164 | 106: LDA 4,-1(4) push prepare 165 | 107: ST 1,0(4) push parameters 166 | * -> variable 167 | 108: LDA 2,-1(5) get local address 168 | 109: LD 1,0(2) get variable value 169 | * <- variable 170 | 110: LDA 4,-1(4) push prepare 171 | 111: ST 1,0(4) push parameters 172 | 112: LDA 1,3(7) store returned PC 173 | 113: LDA 4,-1(4) push prepare 174 | 114: ST 1,0(4) push returned PC 175 | 115: LDC 7,16(0) jump to function 176 | 116: LDA 4,2(4) release parameters 177 | * <- call 178 | 117: LDA 4,-1(4) push prepare 179 | 118: ST 1,0(4) push parameters 180 | 119: LDA 1,3(7) store returned PC 181 | 120: LDA 4,-1(4) push prepare 182 | 121: ST 1,0(4) push returned PC 183 | 122: LDC 7,12(0) jump to function 184 | 123: LDA 4,1(4) release parameters 185 | * <- call 186 | * <- compound 187 | 124: LDA 4,0(5) let sp == bp 188 | 125: LDA 4,2(4) pop prepare 189 | 126: LD 5,-2(4) pop old bp 190 | 127: LD 7,-1(4) pop return addr 191 | * <- function 192 | 3: LDA 1,3(7) store returned PC 193 | 4: LDA 4,-1(4) push prepare 194 | 5: ST 1,0(4) push returned PC 195 | 6: LDC 7,78(0) jump to function 196 | 7: LDA 4,0(4) release parameters 197 | 8: HALT 0,0,0 END OF PROGRAM 198 | -------------------------------------------------------------------------------- /test/test2.cm: -------------------------------------------------------------------------------- 1 | /* 2 | A program to perform selection sort 3 | on a 10 element array. 4 | */ 5 | 6 | int x[10]; 7 | 8 | int minloc(int a[], int low, int high) { 9 | int i; 10 | int x; 11 | int k; 12 | 13 | k = low; 14 | x = a[low]; 15 | i = low + 1; 16 | 17 | while(i < high) { 18 | if(a[i] < x) { 19 | x = a[i]; 20 | k = i; 21 | } 22 | i = i + 1; 23 | } 24 | return k; 25 | } 26 | 27 | void sort(int a[], int low, int high) { 28 | int i; 29 | int k; 30 | 31 | i = low; 32 | while(i < high - 1) { 33 | int t; 34 | k = minloc(a, i, high); 35 | t = a[k]; 36 | a[k] = a[i]; 37 | a[i] = t; 38 | i = i + 1; 39 | } 40 | 41 | } 42 | 43 | void main(void) { 44 | int i; 45 | 46 | i = 0; 47 | while(i < 10) { 48 | x[i] = input(); 49 | i = i + 1; 50 | } 51 | 52 | sort(x, 0, 10); 53 | 54 | i = 0; 55 | while(i < 10) { 56 | output(x[i]); 57 | i = i + 1; 58 | } 59 | 60 | } -------------------------------------------------------------------------------- /test/test2.cm.tm: -------------------------------------------------------------------------------- 1 | * Begin prelude 2 | 0: LD 6,0(0) load from location 0 3 | 1: ST 0,0(0) clear location 0 4 | 2: LDA 4,-10(6) allocate for global variables 5 | * End of prelude 6 | * Jump to main() 7 | * Begin input() 8 | 9: IN 1,0,0 read input into ax 9 | 10: LDA 4,1(4) pop prepare 10 | 11: LD 7,-1(4) pop return addr 11 | * End input() 12 | * Begin output() 13 | 12: LD 1,1(4) load param into ax 14 | 13: OUT 1,0,0 output using ax 15 | 14: LDA 4,1(4) pop prepare 16 | 15: LD 7,-1(4) pop return addr 17 | * End output() 18 | * -> function: 19 | 16: LDA 4,-1(4) push prepare 20 | 17: ST 5,0(4) push old bp 21 | 18: LDA 5,0(4) let bp == sp 22 | 19: LDA 4,-3(4) allocate for local variables 23 | * -> compound 24 | * -> assign 25 | * -> variable 26 | 20: LDA 2,-3(5) get local address 27 | * <- variable 28 | 21: LDA 4,-1(4) push prepare 29 | 22: ST 2,0(4) protect bx 30 | * -> variable 31 | 23: LDA 2,3(5) get param variable address 32 | 24: LD 1,0(2) get variable value 33 | * <- variable 34 | 25: LDA 4,1(4) pop prepare 35 | 26: LD 2,-1(4) recover bx 36 | 27: ST 1,0(2) assign: store 37 | * <- assign 38 | * -> assign 39 | * -> variable 40 | 28: LDA 2,-2(5) get local address 41 | * <- variable 42 | 29: LDA 4,-1(4) push prepare 43 | 30: ST 2,0(4) protect bx 44 | * -> array element 45 | 31: LD 2,2(5) get param array address 46 | 32: LDA 4,-1(4) push prepare 47 | 33: ST 2,0(4) protect array address 48 | * -> variable 49 | 34: LDA 2,3(5) get param variable address 50 | 35: LD 1,0(2) get variable value 51 | * <- variable 52 | 36: LDA 4,1(4) pop prepare 53 | 37: LD 2,-1(4) recover array address 54 | 38: SUB 2,2,1 get address of array element 55 | 39: LD 1,0(2) get value of array element 56 | * <- array element 57 | 40: LDA 4,1(4) pop prepare 58 | 41: LD 2,-1(4) recover bx 59 | 42: ST 1,0(2) assign: store 60 | * <- assign 61 | * -> assign 62 | * -> variable 63 | 43: LDA 2,-1(5) get local address 64 | * <- variable 65 | 44: LDA 4,-1(4) push prepare 66 | 45: ST 2,0(4) protect bx 67 | * -> op 68 | * -> variable 69 | 46: LDA 2,3(5) get param variable address 70 | 47: LD 1,0(2) get variable value 71 | * <- variable 72 | 48: LDA 4,-1(4) push prepare 73 | 49: ST 1,0(4) op: protect left 74 | * -> number 75 | 50: LDC 1,1(0) store number 76 | * <- number 77 | 51: LDA 4,1(4) pop prepare 78 | 52: LD 2,-1(4) op: recover left 79 | 53: ADD 1,2,1 op + 80 | * <- op 81 | 54: LDA 4,1(4) pop prepare 82 | 55: LD 2,-1(4) recover bx 83 | 56: ST 1,0(2) assign: store 84 | * <- assign 85 | * -> while 86 | * jump here after body 87 | * -> op 88 | * -> variable 89 | 57: LDA 2,-1(5) get local address 90 | 58: LD 1,0(2) get variable value 91 | * <- variable 92 | 59: LDA 4,-1(4) push prepare 93 | 60: ST 1,0(4) op: protect left 94 | * -> variable 95 | 61: LDA 2,4(5) get param variable address 96 | 62: LD 1,0(2) get variable value 97 | * <- variable 98 | 63: LDA 4,1(4) pop prepare 99 | 64: LD 2,-1(4) op: recover left 100 | 65: SUB 1,2,1 op < 101 | 66: JLT 1,2(7) br if true 102 | 67: LDC 1,0(0) false case 103 | 68: LDA 7,1(7) unconditional jmp 104 | 69: LDC 1,1(0) true case 105 | * <- op 106 | * jump to end if test fails 107 | * -> compound 108 | * -> if 109 | * -> op 110 | * -> array element 111 | 71: LD 2,2(5) get param array address 112 | 72: LDA 4,-1(4) push prepare 113 | 73: ST 2,0(4) protect array address 114 | * -> variable 115 | 74: LDA 2,-1(5) get local address 116 | 75: LD 1,0(2) get variable value 117 | * <- variable 118 | 76: LDA 4,1(4) pop prepare 119 | 77: LD 2,-1(4) recover array address 120 | 78: SUB 2,2,1 get address of array element 121 | 79: LD 1,0(2) get value of array element 122 | * <- array element 123 | 80: LDA 4,-1(4) push prepare 124 | 81: ST 1,0(4) op: protect left 125 | * -> variable 126 | 82: LDA 2,-2(5) get local address 127 | 83: LD 1,0(2) get variable value 128 | * <- variable 129 | 84: LDA 4,1(4) pop prepare 130 | 85: LD 2,-1(4) op: recover left 131 | 86: SUB 1,2,1 op < 132 | 87: JLT 1,2(7) br if true 133 | 88: LDC 1,0(0) false case 134 | 89: LDA 7,1(7) unconditional jmp 135 | 90: LDC 1,1(0) true case 136 | * <- op 137 | * jump to else 138 | * -> compound 139 | * -> assign 140 | * -> variable 141 | 92: LDA 2,-2(5) get local address 142 | * <- variable 143 | 93: LDA 4,-1(4) push prepare 144 | 94: ST 2,0(4) protect bx 145 | * -> array element 146 | 95: LD 2,2(5) get param array address 147 | 96: LDA 4,-1(4) push prepare 148 | 97: ST 2,0(4) protect array address 149 | * -> variable 150 | 98: LDA 2,-1(5) get local address 151 | 99: LD 1,0(2) get variable value 152 | * <- variable 153 | 100: LDA 4,1(4) pop prepare 154 | 101: LD 2,-1(4) recover array address 155 | 102: SUB 2,2,1 get address of array element 156 | 103: LD 1,0(2) get value of array element 157 | * <- array element 158 | 104: LDA 4,1(4) pop prepare 159 | 105: LD 2,-1(4) recover bx 160 | 106: ST 1,0(2) assign: store 161 | * <- assign 162 | * -> assign 163 | * -> variable 164 | 107: LDA 2,-3(5) get local address 165 | * <- variable 166 | 108: LDA 4,-1(4) push prepare 167 | 109: ST 2,0(4) protect bx 168 | * -> variable 169 | 110: LDA 2,-1(5) get local address 170 | 111: LD 1,0(2) get variable value 171 | * <- variable 172 | 112: LDA 4,1(4) pop prepare 173 | 113: LD 2,-1(4) recover bx 174 | 114: ST 1,0(2) assign: store 175 | * <- assign 176 | * <- compound 177 | * jump to end 178 | 91: JEQ 1,116(0) if: jmp to else 179 | 115: LDA 7,116(0) jmp to end 180 | * <- if 181 | * -> assign 182 | * -> variable 183 | 116: LDA 2,-1(5) get local address 184 | * <- variable 185 | 117: LDA 4,-1(4) push prepare 186 | 118: ST 2,0(4) protect bx 187 | * -> op 188 | * -> variable 189 | 119: LDA 2,-1(5) get local address 190 | 120: LD 1,0(2) get variable value 191 | * <- variable 192 | 121: LDA 4,-1(4) push prepare 193 | 122: ST 1,0(4) op: protect left 194 | * -> number 195 | 123: LDC 1,1(0) store number 196 | * <- number 197 | 124: LDA 4,1(4) pop prepare 198 | 125: LD 2,-1(4) op: recover left 199 | 126: ADD 1,2,1 op + 200 | * <- op 201 | 127: LDA 4,1(4) pop prepare 202 | 128: LD 2,-1(4) recover bx 203 | 129: ST 1,0(2) assign: store 204 | * <- assign 205 | * <- compound 206 | 130: LDA 7,57(0) jump to test 207 | 70: JEQ 1,131(0) jump to end 208 | * <- while 209 | * -> return 210 | * -> variable 211 | 131: LDA 2,-3(5) get local address 212 | 132: LD 1,0(2) get variable value 213 | * <- variable 214 | 133: LDA 4,0(5) let sp == bp 215 | 134: LDA 4,2(4) pop prepare 216 | 135: LD 5,-2(4) pop old bp 217 | 136: LD 7,-1(4) pop return addr 218 | * <- return 219 | * <- compound 220 | * <- function 221 | * -> function: 222 | 137: LDA 4,-1(4) push prepare 223 | 138: ST 5,0(4) push old bp 224 | 139: LDA 5,0(4) let bp == sp 225 | 140: LDA 4,-3(4) allocate for local variables 226 | * -> compound 227 | * -> assign 228 | * -> variable 229 | 141: LDA 2,-1(5) get local address 230 | * <- variable 231 | 142: LDA 4,-1(4) push prepare 232 | 143: ST 2,0(4) protect bx 233 | * -> variable 234 | 144: LDA 2,3(5) get param variable address 235 | 145: LD 1,0(2) get variable value 236 | * <- variable 237 | 146: LDA 4,1(4) pop prepare 238 | 147: LD 2,-1(4) recover bx 239 | 148: ST 1,0(2) assign: store 240 | * <- assign 241 | * -> while 242 | * jump here after body 243 | * -> op 244 | * -> variable 245 | 149: LDA 2,-1(5) get local address 246 | 150: LD 1,0(2) get variable value 247 | * <- variable 248 | 151: LDA 4,-1(4) push prepare 249 | 152: ST 1,0(4) op: protect left 250 | * -> op 251 | * -> variable 252 | 153: LDA 2,4(5) get param variable address 253 | 154: LD 1,0(2) get variable value 254 | * <- variable 255 | 155: LDA 4,-1(4) push prepare 256 | 156: ST 1,0(4) op: protect left 257 | * -> number 258 | 157: LDC 1,1(0) store number 259 | * <- number 260 | 158: LDA 4,1(4) pop prepare 261 | 159: LD 2,-1(4) op: recover left 262 | 160: SUB 1,2,1 op - 263 | * <- op 264 | 161: LDA 4,1(4) pop prepare 265 | 162: LD 2,-1(4) op: recover left 266 | 163: SUB 1,2,1 op < 267 | 164: JLT 1,2(7) br if true 268 | 165: LDC 1,0(0) false case 269 | 166: LDA 7,1(7) unconditional jmp 270 | 167: LDC 1,1(0) true case 271 | * <- op 272 | * jump to end if test fails 273 | * -> compound 274 | * -> assign 275 | * -> variable 276 | 169: LDA 2,-2(5) get local address 277 | * <- variable 278 | 170: LDA 4,-1(4) push prepare 279 | 171: ST 2,0(4) protect bx 280 | * -> call 281 | * -> variable 282 | 172: LDA 2,4(5) get param variable address 283 | 173: LD 1,0(2) get variable value 284 | * <- variable 285 | 174: LDA 4,-1(4) push prepare 286 | 175: ST 1,0(4) push parameters 287 | * -> variable 288 | 176: LDA 2,-1(5) get local address 289 | 177: LD 1,0(2) get variable value 290 | * <- variable 291 | 178: LDA 4,-1(4) push prepare 292 | 179: ST 1,0(4) push parameters 293 | * -> variable 294 | 180: LD 2,2(5) get param array address 295 | 181: LDA 1,0(2) get array variable value( == address) 296 | * <- variable 297 | 182: LDA 4,-1(4) push prepare 298 | 183: ST 1,0(4) push parameters 299 | 184: LDA 1,3(7) store returned PC 300 | 185: LDA 4,-1(4) push prepare 301 | 186: ST 1,0(4) push returned PC 302 | 187: LDC 7,16(0) jump to function 303 | 188: LDA 4,3(4) release parameters 304 | * <- call 305 | 189: LDA 4,1(4) pop prepare 306 | 190: LD 2,-1(4) recover bx 307 | 191: ST 1,0(2) assign: store 308 | * <- assign 309 | * -> assign 310 | * -> variable 311 | 192: LDA 2,-3(5) get local address 312 | * <- variable 313 | 193: LDA 4,-1(4) push prepare 314 | 194: ST 2,0(4) protect bx 315 | * -> array element 316 | 195: LD 2,2(5) get param array address 317 | 196: LDA 4,-1(4) push prepare 318 | 197: ST 2,0(4) protect array address 319 | * -> variable 320 | 198: LDA 2,-2(5) get local address 321 | 199: LD 1,0(2) get variable value 322 | * <- variable 323 | 200: LDA 4,1(4) pop prepare 324 | 201: LD 2,-1(4) recover array address 325 | 202: SUB 2,2,1 get address of array element 326 | 203: LD 1,0(2) get value of array element 327 | * <- array element 328 | 204: LDA 4,1(4) pop prepare 329 | 205: LD 2,-1(4) recover bx 330 | 206: ST 1,0(2) assign: store 331 | * <- assign 332 | * -> assign 333 | * -> array element 334 | 207: LD 2,2(5) get param array address 335 | 208: LDA 4,-1(4) push prepare 336 | 209: ST 2,0(4) protect array address 337 | * -> variable 338 | 210: LDA 2,-2(5) get local address 339 | 211: LD 1,0(2) get variable value 340 | * <- variable 341 | 212: LDA 4,1(4) pop prepare 342 | 213: LD 2,-1(4) recover array address 343 | 214: SUB 2,2,1 get address of array element 344 | * <- array element 345 | 215: LDA 4,-1(4) push prepare 346 | 216: ST 2,0(4) protect bx 347 | * -> array element 348 | 217: LD 2,2(5) get param array address 349 | 218: LDA 4,-1(4) push prepare 350 | 219: ST 2,0(4) protect array address 351 | * -> variable 352 | 220: LDA 2,-1(5) get local address 353 | 221: LD 1,0(2) get variable value 354 | * <- variable 355 | 222: LDA 4,1(4) pop prepare 356 | 223: LD 2,-1(4) recover array address 357 | 224: SUB 2,2,1 get address of array element 358 | 225: LD 1,0(2) get value of array element 359 | * <- array element 360 | 226: LDA 4,1(4) pop prepare 361 | 227: LD 2,-1(4) recover bx 362 | 228: ST 1,0(2) assign: store 363 | * <- assign 364 | * -> assign 365 | * -> array element 366 | 229: LD 2,2(5) get param array address 367 | 230: LDA 4,-1(4) push prepare 368 | 231: ST 2,0(4) protect array address 369 | * -> variable 370 | 232: LDA 2,-1(5) get local address 371 | 233: LD 1,0(2) get variable value 372 | * <- variable 373 | 234: LDA 4,1(4) pop prepare 374 | 235: LD 2,-1(4) recover array address 375 | 236: SUB 2,2,1 get address of array element 376 | * <- array element 377 | 237: LDA 4,-1(4) push prepare 378 | 238: ST 2,0(4) protect bx 379 | * -> variable 380 | 239: LDA 2,-3(5) get local address 381 | 240: LD 1,0(2) get variable value 382 | * <- variable 383 | 241: LDA 4,1(4) pop prepare 384 | 242: LD 2,-1(4) recover bx 385 | 243: ST 1,0(2) assign: store 386 | * <- assign 387 | * -> assign 388 | * -> variable 389 | 244: LDA 2,-1(5) get local address 390 | * <- variable 391 | 245: LDA 4,-1(4) push prepare 392 | 246: ST 2,0(4) protect bx 393 | * -> op 394 | * -> variable 395 | 247: LDA 2,-1(5) get local address 396 | 248: LD 1,0(2) get variable value 397 | * <- variable 398 | 249: LDA 4,-1(4) push prepare 399 | 250: ST 1,0(4) op: protect left 400 | * -> number 401 | 251: LDC 1,1(0) store number 402 | * <- number 403 | 252: LDA 4,1(4) pop prepare 404 | 253: LD 2,-1(4) op: recover left 405 | 254: ADD 1,2,1 op + 406 | * <- op 407 | 255: LDA 4,1(4) pop prepare 408 | 256: LD 2,-1(4) recover bx 409 | 257: ST 1,0(2) assign: store 410 | * <- assign 411 | * <- compound 412 | 258: LDA 7,149(0) jump to test 413 | 168: JEQ 1,259(0) jump to end 414 | * <- while 415 | * <- compound 416 | 259: LDA 4,0(5) let sp == bp 417 | 260: LDA 4,2(4) pop prepare 418 | 261: LD 5,-2(4) pop old bp 419 | 262: LD 7,-1(4) pop return addr 420 | * <- function 421 | * -> function: 422 | 263: LDA 4,-1(4) push prepare 423 | 264: ST 5,0(4) push old bp 424 | 265: LDA 5,0(4) let bp == sp 425 | 266: LDA 4,-1(4) allocate for local variables 426 | * -> compound 427 | * -> assign 428 | * -> variable 429 | 267: LDA 2,-1(5) get local address 430 | * <- variable 431 | 268: LDA 4,-1(4) push prepare 432 | 269: ST 2,0(4) protect bx 433 | * -> number 434 | 270: LDC 1,0(0) store number 435 | * <- number 436 | 271: LDA 4,1(4) pop prepare 437 | 272: LD 2,-1(4) recover bx 438 | 273: ST 1,0(2) assign: store 439 | * <- assign 440 | * -> while 441 | * jump here after body 442 | * -> op 443 | * -> variable 444 | 274: LDA 2,-1(5) get local address 445 | 275: LD 1,0(2) get variable value 446 | * <- variable 447 | 276: LDA 4,-1(4) push prepare 448 | 277: ST 1,0(4) op: protect left 449 | * -> number 450 | 278: LDC 1,10(0) store number 451 | * <- number 452 | 279: LDA 4,1(4) pop prepare 453 | 280: LD 2,-1(4) op: recover left 454 | 281: SUB 1,2,1 op < 455 | 282: JLT 1,2(7) br if true 456 | 283: LDC 1,0(0) false case 457 | 284: LDA 7,1(7) unconditional jmp 458 | 285: LDC 1,1(0) true case 459 | * <- op 460 | * jump to end if test fails 461 | * -> compound 462 | * -> assign 463 | * -> array element 464 | 287: LDA 2,0(6) get global array address 465 | 288: LDA 4,-1(4) push prepare 466 | 289: ST 2,0(4) protect array address 467 | * -> variable 468 | 290: LDA 2,-1(5) get local address 469 | 291: LD 1,0(2) get variable value 470 | * <- variable 471 | 292: LDA 4,1(4) pop prepare 472 | 293: LD 2,-1(4) recover array address 473 | 294: SUB 2,2,1 get address of array element 474 | * <- array element 475 | 295: LDA 4,-1(4) push prepare 476 | 296: ST 2,0(4) protect bx 477 | * -> call 478 | 297: LDA 1,3(7) store returned PC 479 | 298: LDA 4,-1(4) push prepare 480 | 299: ST 1,0(4) push returned PC 481 | 300: LDC 7,9(0) jump to function 482 | 301: LDA 4,0(4) release parameters 483 | * <- call 484 | 302: LDA 4,1(4) pop prepare 485 | 303: LD 2,-1(4) recover bx 486 | 304: ST 1,0(2) assign: store 487 | * <- assign 488 | * -> assign 489 | * -> variable 490 | 305: LDA 2,-1(5) get local address 491 | * <- variable 492 | 306: LDA 4,-1(4) push prepare 493 | 307: ST 2,0(4) protect bx 494 | * -> op 495 | * -> variable 496 | 308: LDA 2,-1(5) get local address 497 | 309: LD 1,0(2) get variable value 498 | * <- variable 499 | 310: LDA 4,-1(4) push prepare 500 | 311: ST 1,0(4) op: protect left 501 | * -> number 502 | 312: LDC 1,1(0) store number 503 | * <- number 504 | 313: LDA 4,1(4) pop prepare 505 | 314: LD 2,-1(4) op: recover left 506 | 315: ADD 1,2,1 op + 507 | * <- op 508 | 316: LDA 4,1(4) pop prepare 509 | 317: LD 2,-1(4) recover bx 510 | 318: ST 1,0(2) assign: store 511 | * <- assign 512 | * <- compound 513 | 319: LDA 7,274(0) jump to test 514 | 286: JEQ 1,320(0) jump to end 515 | * <- while 516 | * -> call 517 | * -> number 518 | 320: LDC 1,10(0) store number 519 | * <- number 520 | 321: LDA 4,-1(4) push prepare 521 | 322: ST 1,0(4) push parameters 522 | * -> number 523 | 323: LDC 1,0(0) store number 524 | * <- number 525 | 324: LDA 4,-1(4) push prepare 526 | 325: ST 1,0(4) push parameters 527 | * -> variable 528 | 326: LDA 2,0(6) get global array address 529 | 327: LDA 1,0(2) get array variable value( == address) 530 | * <- variable 531 | 328: LDA 4,-1(4) push prepare 532 | 329: ST 1,0(4) push parameters 533 | 330: LDA 1,3(7) store returned PC 534 | 331: LDA 4,-1(4) push prepare 535 | 332: ST 1,0(4) push returned PC 536 | 333: LDC 7,137(0) jump to function 537 | 334: LDA 4,3(4) release parameters 538 | * <- call 539 | * -> assign 540 | * -> variable 541 | 335: LDA 2,-1(5) get local address 542 | * <- variable 543 | 336: LDA 4,-1(4) push prepare 544 | 337: ST 2,0(4) protect bx 545 | * -> number 546 | 338: LDC 1,0(0) store number 547 | * <- number 548 | 339: LDA 4,1(4) pop prepare 549 | 340: LD 2,-1(4) recover bx 550 | 341: ST 1,0(2) assign: store 551 | * <- assign 552 | * -> while 553 | * jump here after body 554 | * -> op 555 | * -> variable 556 | 342: LDA 2,-1(5) get local address 557 | 343: LD 1,0(2) get variable value 558 | * <- variable 559 | 344: LDA 4,-1(4) push prepare 560 | 345: ST 1,0(4) op: protect left 561 | * -> number 562 | 346: LDC 1,10(0) store number 563 | * <- number 564 | 347: LDA 4,1(4) pop prepare 565 | 348: LD 2,-1(4) op: recover left 566 | 349: SUB 1,2,1 op < 567 | 350: JLT 1,2(7) br if true 568 | 351: LDC 1,0(0) false case 569 | 352: LDA 7,1(7) unconditional jmp 570 | 353: LDC 1,1(0) true case 571 | * <- op 572 | * jump to end if test fails 573 | * -> compound 574 | * -> call 575 | * -> array element 576 | 355: LDA 2,0(6) get global array address 577 | 356: LDA 4,-1(4) push prepare 578 | 357: ST 2,0(4) protect array address 579 | * -> variable 580 | 358: LDA 2,-1(5) get local address 581 | 359: LD 1,0(2) get variable value 582 | * <- variable 583 | 360: LDA 4,1(4) pop prepare 584 | 361: LD 2,-1(4) recover array address 585 | 362: SUB 2,2,1 get address of array element 586 | 363: LD 1,0(2) get value of array element 587 | * <- array element 588 | 364: LDA 4,-1(4) push prepare 589 | 365: ST 1,0(4) push parameters 590 | 366: LDA 1,3(7) store returned PC 591 | 367: LDA 4,-1(4) push prepare 592 | 368: ST 1,0(4) push returned PC 593 | 369: LDC 7,12(0) jump to function 594 | 370: LDA 4,1(4) release parameters 595 | * <- call 596 | * -> assign 597 | * -> variable 598 | 371: LDA 2,-1(5) get local address 599 | * <- variable 600 | 372: LDA 4,-1(4) push prepare 601 | 373: ST 2,0(4) protect bx 602 | * -> op 603 | * -> variable 604 | 374: LDA 2,-1(5) get local address 605 | 375: LD 1,0(2) get variable value 606 | * <- variable 607 | 376: LDA 4,-1(4) push prepare 608 | 377: ST 1,0(4) op: protect left 609 | * -> number 610 | 378: LDC 1,1(0) store number 611 | * <- number 612 | 379: LDA 4,1(4) pop prepare 613 | 380: LD 2,-1(4) op: recover left 614 | 381: ADD 1,2,1 op + 615 | * <- op 616 | 382: LDA 4,1(4) pop prepare 617 | 383: LD 2,-1(4) recover bx 618 | 384: ST 1,0(2) assign: store 619 | * <- assign 620 | * <- compound 621 | 385: LDA 7,342(0) jump to test 622 | 354: JEQ 1,386(0) jump to end 623 | * <- while 624 | * <- compound 625 | 386: LDA 4,0(5) let sp == bp 626 | 387: LDA 4,2(4) pop prepare 627 | 388: LD 5,-2(4) pop old bp 628 | 389: LD 7,-1(4) pop return addr 629 | * <- function 630 | 3: LDA 1,3(7) store returned PC 631 | 4: LDA 4,-1(4) push prepare 632 | 5: ST 1,0(4) push returned PC 633 | 6: LDC 7,263(0) jump to function 634 | 7: LDA 4,0(4) release parameters 635 | 8: HALT 0,0,0 END OF PROGRAM 636 | -------------------------------------------------------------------------------- /tm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/koyabr/C-Compiler/4ba98e20b3f6ac02eb0ec1faf90d1f637828010c/tm -------------------------------------------------------------------------------- /tm.c: -------------------------------------------------------------------------------- 1 | /****************************************************/ 2 | /* File: tm.c */ 3 | /* The TM ("Tiny Machine") computer */ 4 | /* Compiler Construction: Principles and Practice */ 5 | /* Kenneth C. Louden */ 6 | /****************************************************/ 7 | 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #ifndef TRUE 14 | #define TRUE 1 15 | #endif 16 | #ifndef FALSE 17 | #define FALSE 0 18 | #endif 19 | 20 | /******* const *******/ 21 | #define IADDR_SIZE 1024 /* increase for large programs */ 22 | #define DADDR_SIZE 1024 /* increase for large programs */ 23 | #define NO_REGS 8 24 | #define PC_REG 7 25 | 26 | #define LINESIZE 121 27 | #define WORDSIZE 20 28 | 29 | /******* type *******/ 30 | 31 | typedef enum { 32 | opclRR, /* reg operands r,s,t */ 33 | opclRM, /* reg r, mem d+s */ 34 | opclRA /* reg r, int d+s */ 35 | } OPCLASS; 36 | 37 | typedef enum { 38 | /* RR instructions */ 39 | opHALT, /* RR halt, operands are ignored */ 40 | opIN, /* RR read into reg(r); s and t are ignored */ 41 | opOUT, /* RR write from reg(r), s and t are ignored */ 42 | opADD, /* RR reg(r) = reg(s)+reg(t) */ 43 | opSUB, /* RR reg(r) = reg(s)-reg(t) */ 44 | opMUL, /* RR reg(r) = reg(s)*reg(t) */ 45 | opDIV, /* RR reg(r) = reg(s)/reg(t) */ 46 | opRRLim, /* limit of RR opcodes */ 47 | 48 | /* RM instructions */ 49 | opLD, /* RM reg(r) = mem(d+reg(s)) */ 50 | opST, /* RM mem(d+reg(s)) = reg(r) */ 51 | opRMLim, /* Limit of RM opcodes */ 52 | 53 | /* RA instructions */ 54 | opLDA, /* RA reg(r) = d+reg(s) */ 55 | opLDC, /* RA reg(r) = d ; reg(s) is ignored */ 56 | opJLT, /* RA if reg(r)<0 then reg(7) = d+reg(s) */ 57 | opJLE, /* RA if reg(r)<=0 then reg(7) = d+reg(s) */ 58 | opJGT, /* RA if reg(r)>0 then reg(7) = d+reg(s) */ 59 | opJGE, /* RA if reg(r)>=0 then reg(7) = d+reg(s) */ 60 | opJEQ, /* RA if reg(r)==0 then reg(7) = d+reg(s) */ 61 | opJNE, /* RA if reg(r)!=0 then reg(7) = d+reg(s) */ 62 | opRALim /* Limit of RA opcodes */ 63 | } OPCODE; 64 | 65 | typedef enum { 66 | srOKAY, 67 | srHALT, 68 | srIMEM_ERR, 69 | srDMEM_ERR, 70 | srZERODIVIDE 71 | } STEPRESULT; 72 | 73 | typedef struct { 74 | int iop ; 75 | int iarg1 ; 76 | int iarg2 ; 77 | int iarg3 ; 78 | } INSTRUCTION; 79 | 80 | /******** vars ********/ 81 | int iloc = 0 ; 82 | int dloc = 0 ; 83 | int traceflag = FALSE; 84 | int icountflag = FALSE; 85 | 86 | INSTRUCTION iMem [IADDR_SIZE]; 87 | int dMem [DADDR_SIZE]; 88 | int reg [NO_REGS]; 89 | 90 | char * opCodeTab[] 91 | = {"HALT","IN","OUT","ADD","SUB","MUL","DIV","????", 92 | /* RR opcodes */ 93 | "LD","ST","????", /* RM opcodes */ 94 | "LDA","LDC","JLT","JLE","JGT","JGE","JEQ","JNE","????" 95 | /* RA opcodes */ 96 | }; 97 | 98 | char * stepResultTab[] 99 | = {"OK","Halted","Instruction Memory Fault", 100 | "Data Memory Fault","Division by 0" 101 | }; 102 | 103 | char pgmName[20]; 104 | FILE *pgm ; 105 | 106 | char in_Line[LINESIZE] ; 107 | int lineLen ; 108 | int inCol ; 109 | int num ; 110 | char word[WORDSIZE] ; 111 | char ch ; 112 | int done ; 113 | 114 | /********************************************/ 115 | int opClass( int c ) 116 | { if ( c <= opRRLim) return ( opclRR ); 117 | else if ( c <= opRMLim) return ( opclRM ); 118 | else return ( opclRA ); 119 | } /* opClass */ 120 | 121 | /********************************************/ 122 | void writeInstruction ( int loc ) 123 | { printf( "%5d: ", loc) ; 124 | if ( (loc >= 0) && (loc < IADDR_SIZE) ) 125 | { printf("%6s%3d,", opCodeTab[iMem[loc].iop], iMem[loc].iarg1); 126 | switch ( opClass(iMem[loc].iop) ) 127 | { case opclRR: printf("%1d,%1d", iMem[loc].iarg2, iMem[loc].iarg3); 128 | break; 129 | case opclRM: 130 | case opclRA: printf("%3d(%1d)", iMem[loc].iarg2, iMem[loc].iarg3); 131 | break; 132 | } 133 | printf ("\n") ; 134 | } 135 | } /* writeInstruction */ 136 | 137 | /********************************************/ 138 | void getCh (void) 139 | { if (++inCol < lineLen) 140 | ch = in_Line[inCol] ; 141 | else ch = ' ' ; 142 | } /* getCh */ 143 | 144 | /********************************************/ 145 | int nonBlank (void) 146 | { while ((inCol < lineLen) 147 | && (in_Line[inCol] == ' ') ) 148 | inCol++ ; 149 | if (inCol < lineLen) 150 | { ch = in_Line[inCol] ; 151 | return TRUE ; } 152 | else 153 | { ch = ' ' ; 154 | return FALSE ; } 155 | } /* nonBlank */ 156 | 157 | /********************************************/ 158 | int getNum (void) 159 | { int sign; 160 | int term; 161 | int temp = FALSE; 162 | num = 0 ; 163 | do 164 | { sign = 1; 165 | while ( nonBlank() && ((ch == '+') || (ch == '-')) ) 166 | { temp = FALSE ; 167 | if (ch == '-') sign = - sign ; 168 | getCh(); 169 | } 170 | term = 0 ; 171 | nonBlank(); 172 | while (isdigit(ch)) 173 | { temp = TRUE ; 174 | term = term * 10 + ( ch - '0' ) ; 175 | getCh(); 176 | } 177 | num = num + (term * sign) ; 178 | } while ( (nonBlank()) && ((ch == '+') || (ch == '-')) ) ; 179 | return temp; 180 | } /* getNum */ 181 | 182 | /********************************************/ 183 | int getWord (void) 184 | { int temp = FALSE; 185 | int length = 0; 186 | if (nonBlank ()) 187 | { while (isalnum(ch)) 188 | { if (length < WORDSIZE-1) word [length++] = ch ; 189 | getCh() ; 190 | } 191 | word[length] = '\0'; 192 | temp = (length != 0); 193 | } 194 | return temp; 195 | } /* getWord */ 196 | 197 | /********************************************/ 198 | int skipCh ( char c ) 199 | { int temp = FALSE; 200 | if ( nonBlank() && (ch == c) ) 201 | { getCh(); 202 | temp = TRUE; 203 | } 204 | return temp; 205 | } /* skipCh */ 206 | 207 | /********************************************/ 208 | int atEOL(void) 209 | { return ( ! nonBlank ()); 210 | } /* atEOL */ 211 | 212 | /********************************************/ 213 | int error( char * msg, int lineNo, int instNo) 214 | { printf("Line %d",lineNo); 215 | if (instNo >= 0) printf(" (Instruction %d)",instNo); 216 | printf(" %s\n",msg); 217 | return FALSE; 218 | } /* error */ 219 | 220 | /********************************************/ 221 | int readInstructions (void) 222 | { OPCODE op; 223 | int arg1, arg2, arg3; 224 | int loc, regNo, lineNo; 225 | for (regNo = 0 ; regNo < NO_REGS ; regNo++) 226 | reg[regNo] = 0 ; 227 | dMem[0] = DADDR_SIZE - 1 ; 228 | for (loc = 1 ; loc < DADDR_SIZE ; loc++) 229 | dMem[loc] = 0 ; 230 | for (loc = 0 ; loc < IADDR_SIZE ; loc++) 231 | { iMem[loc].iop = opHALT ; 232 | iMem[loc].iarg1 = 0 ; 233 | iMem[loc].iarg2 = 0 ; 234 | iMem[loc].iarg3 = 0 ; 235 | } 236 | lineNo = 0 ; 237 | while (! feof(pgm)) 238 | { fgets( in_Line, LINESIZE-2, pgm ) ; 239 | inCol = 0 ; 240 | lineNo++; 241 | lineLen = strlen(in_Line)-1 ; 242 | if (in_Line[lineLen]=='\n') in_Line[lineLen] = '\0' ; 243 | else in_Line[++lineLen] = '\0'; 244 | if ( (nonBlank()) && (in_Line[inCol] != '*') ) 245 | { if (! getNum()) 246 | return error("Bad location", lineNo,-1); 247 | loc = num; 248 | if (loc > IADDR_SIZE) 249 | return error("Location too large",lineNo,loc); 250 | if (! skipCh(':')) 251 | return error("Missing colon", lineNo,loc); 252 | if (! getWord ()) 253 | return error("Missing opcode", lineNo,loc); 254 | op = opHALT ; 255 | while ((op < opRALim) 256 | && (strncmp(opCodeTab[op], word, 4) != 0) ) 257 | op++ ; 258 | if (strncmp(opCodeTab[op], word, 4) != 0) 259 | return error("Illegal opcode", lineNo,loc); 260 | switch ( opClass(op) ) 261 | { case opclRR : 262 | /***********************************/ 263 | if ( (! getNum ()) || (num < 0) || (num >= NO_REGS) ) 264 | return error("Bad first register", lineNo,loc); 265 | arg1 = num; 266 | if ( ! skipCh(',')) 267 | return error("Missing comma", lineNo, loc); 268 | if ( (! getNum ()) || (num < 0) || (num >= NO_REGS) ) 269 | return error("Bad second register", lineNo, loc); 270 | arg2 = num; 271 | if ( ! skipCh(',')) 272 | return error("Missing comma", lineNo,loc); 273 | if ( (! getNum ()) || (num < 0) || (num >= NO_REGS) ) 274 | return error("Bad third register", lineNo,loc); 275 | arg3 = num; 276 | break; 277 | 278 | case opclRM : 279 | case opclRA : 280 | /***********************************/ 281 | if ( (! getNum ()) || (num < 0) || (num >= NO_REGS) ) 282 | return error("Bad first register", lineNo,loc); 283 | arg1 = num; 284 | if ( ! skipCh(',')) 285 | return error("Missing comma", lineNo,loc); 286 | if (! getNum ()) 287 | return error("Bad displacement", lineNo,loc); 288 | arg2 = num; 289 | if ( ! skipCh('(') && ! skipCh(',') ) 290 | return error("Missing LParen", lineNo,loc); 291 | if ( (! getNum ()) || (num < 0) || (num >= NO_REGS)) 292 | return error("Bad second register", lineNo,loc); 293 | arg3 = num; 294 | break; 295 | } 296 | iMem[loc].iop = op; 297 | iMem[loc].iarg1 = arg1; 298 | iMem[loc].iarg2 = arg2; 299 | iMem[loc].iarg3 = arg3; 300 | } 301 | } 302 | return TRUE; 303 | } /* readInstructions */ 304 | 305 | 306 | /********************************************/ 307 | STEPRESULT stepTM (void) 308 | { INSTRUCTION currentinstruction ; 309 | int pc ; 310 | int r,s,t,m ; 311 | int ok ; 312 | 313 | pc = reg[PC_REG] ; 314 | if ( (pc < 0) || (pc > IADDR_SIZE) ) 315 | return srIMEM_ERR ; 316 | reg[PC_REG] = pc + 1 ; 317 | currentinstruction = iMem[ pc ] ; 318 | switch (opClass(currentinstruction.iop) ) 319 | { case opclRR : 320 | /***********************************/ 321 | r = currentinstruction.iarg1 ; 322 | s = currentinstruction.iarg2 ; 323 | t = currentinstruction.iarg3 ; 324 | break; 325 | 326 | case opclRM : 327 | /***********************************/ 328 | r = currentinstruction.iarg1 ; 329 | s = currentinstruction.iarg3 ; 330 | m = currentinstruction.iarg2 + reg[s] ; 331 | if ( (m < 0) || (m > DADDR_SIZE)) 332 | return srDMEM_ERR ; 333 | break; 334 | 335 | case opclRA : 336 | /***********************************/ 337 | r = currentinstruction.iarg1 ; 338 | s = currentinstruction.iarg3 ; 339 | m = currentinstruction.iarg2 + reg[s] ; 340 | break; 341 | } /* case */ 342 | 343 | switch ( currentinstruction.iop) 344 | { /* RR instructions */ 345 | case opHALT : 346 | /***********************************/ 347 | printf("HALT: %1d,%1d,%1d\n",r,s,t); 348 | return srHALT ; 349 | /* break; */ 350 | 351 | case opIN : 352 | /***********************************/ 353 | do 354 | { printf("Enter value for IN instruction: ") ; 355 | fflush (stdin); 356 | fflush (stdout); 357 | gets(in_Line); 358 | lineLen = strlen(in_Line) ; 359 | inCol = 0; 360 | ok = getNum(); 361 | if ( ! ok ) printf ("Illegal value\n"); 362 | else reg[r] = num; 363 | } 364 | while (! ok); 365 | break; 366 | 367 | case opOUT : 368 | printf ("OUT instruction prints: %d\n", reg[r] ) ; 369 | break; 370 | case opADD : reg[r] = reg[s] + reg[t] ; break; 371 | case opSUB : reg[r] = reg[s] - reg[t] ; break; 372 | case opMUL : reg[r] = reg[s] * reg[t] ; break; 373 | 374 | case opDIV : 375 | /***********************************/ 376 | if ( reg[t] != 0 ) reg[r] = reg[s] / reg[t]; 377 | else return srZERODIVIDE ; 378 | break; 379 | 380 | /*************** RM instructions ********************/ 381 | case opLD : reg[r] = dMem[m] ; break; 382 | case opST : dMem[m] = reg[r] ; break; 383 | 384 | /*************** RA instructions ********************/ 385 | case opLDA : reg[r] = m ; break; 386 | case opLDC : reg[r] = currentinstruction.iarg2 ; break; 387 | case opJLT : if ( reg[r] < 0 ) reg[PC_REG] = m ; break; 388 | case opJLE : if ( reg[r] <= 0 ) reg[PC_REG] = m ; break; 389 | case opJGT : if ( reg[r] > 0 ) reg[PC_REG] = m ; break; 390 | case opJGE : if ( reg[r] >= 0 ) reg[PC_REG] = m ; break; 391 | case opJEQ : if ( reg[r] == 0 ) reg[PC_REG] = m ; break; 392 | case opJNE : if ( reg[r] != 0 ) reg[PC_REG] = m ; break; 393 | 394 | /* end of legal instructions */ 395 | } /* case */ 396 | return srOKAY ; 397 | } /* stepTM */ 398 | 399 | /********************************************/ 400 | int doCommand (void) 401 | { char cmd; 402 | int stepcnt=0, i; 403 | int printcnt; 404 | int stepResult; 405 | int regNo, loc; 406 | do 407 | { printf ("Enter command: "); 408 | fflush (stdin); 409 | fflush (stdout); 410 | gets(in_Line); 411 | lineLen = strlen(in_Line); 412 | inCol = 0; 413 | } 414 | while (! getWord ()); 415 | 416 | cmd = word[0] ; 417 | switch ( cmd ) 418 | { case 't' : 419 | /***********************************/ 420 | traceflag = ! traceflag ; 421 | printf("Tracing now "); 422 | if ( traceflag ) printf("on.\n"); else printf("off.\n"); 423 | break; 424 | 425 | case 'h' : 426 | /***********************************/ 427 | printf("Commands are:\n"); 428 | printf(" s(tep "\ 429 | "Execute n (default 1) TM instructions\n"); 430 | printf(" g(o "\ 431 | "Execute TM instructions until HALT\n"); 432 | printf(" r(egs "\ 433 | "Print the contents of the registers\n"); 434 | printf(" i(Mem > "\ 435 | "Print n iMem locations starting at b\n"); 436 | printf(" d(Mem > "\ 437 | "Print n dMem locations starting at b\n"); 438 | printf(" t(race "\ 439 | "Toggle instruction trace\n"); 440 | printf(" p(rint "\ 441 | "Toggle print of total instructions executed"\ 442 | " ('go' only)\n"); 443 | printf(" c(lear "\ 444 | "Reset simulator for new execution of program\n"); 445 | printf(" h(elp "\ 446 | "Cause this list of commands to be printed\n"); 447 | printf(" q(uit "\ 448 | "Terminate the simulation\n"); 449 | break; 450 | 451 | case 'p' : 452 | /***********************************/ 453 | icountflag = ! icountflag ; 454 | printf("Printing instruction count now "); 455 | if ( icountflag ) printf("on.\n"); else printf("off.\n"); 456 | break; 457 | 458 | case 's' : 459 | /***********************************/ 460 | if ( atEOL ()) stepcnt = 1; 461 | else if ( getNum ()) stepcnt = abs(num); 462 | else printf("Step count?\n"); 463 | break; 464 | 465 | case 'g' : stepcnt = 1 ; break; 466 | 467 | case 'r' : 468 | /***********************************/ 469 | for (i = 0; i < NO_REGS; i++) 470 | { printf("%1d: %4d ", i,reg[i]); 471 | if ( (i % 4) == 3 ) printf ("\n"); 472 | } 473 | break; 474 | 475 | case 'i' : 476 | /***********************************/ 477 | printcnt = 1 ; 478 | if ( getNum ()) 479 | { iloc = num ; 480 | if ( getNum ()) printcnt = num ; 481 | } 482 | if ( ! atEOL ()) 483 | printf ("Instruction locations?\n"); 484 | else 485 | { while ((iloc >= 0) && (iloc < IADDR_SIZE) 486 | && (printcnt > 0) ) 487 | { writeInstruction(iloc); 488 | iloc++ ; 489 | printcnt-- ; 490 | } 491 | } 492 | break; 493 | 494 | case 'd' : 495 | /***********************************/ 496 | printcnt = 1 ; 497 | if ( getNum ()) 498 | { dloc = num ; 499 | if ( getNum ()) printcnt = num ; 500 | } 501 | if ( ! atEOL ()) 502 | printf("Data locations?\n"); 503 | else 504 | { while ((dloc >= 0) && (dloc < DADDR_SIZE) 505 | && (printcnt > 0)) 506 | { printf("%5d: %5d\n",dloc,dMem[dloc]); 507 | dloc++; 508 | printcnt--; 509 | } 510 | } 511 | break; 512 | 513 | case 'c' : 514 | /***********************************/ 515 | iloc = 0; 516 | dloc = 0; 517 | stepcnt = 0; 518 | for (regNo = 0; regNo < NO_REGS ; regNo++) 519 | reg[regNo] = 0 ; 520 | dMem[0] = DADDR_SIZE - 1 ; 521 | for (loc = 1 ; loc < DADDR_SIZE ; loc++) 522 | dMem[loc] = 0 ; 523 | break; 524 | 525 | case 'q' : return FALSE; /* break; */ 526 | 527 | default : printf("Command %c unknown.\n", cmd); break; 528 | } /* case */ 529 | stepResult = srOKAY; 530 | if ( stepcnt > 0 ) 531 | { if ( cmd == 'g' ) 532 | { stepcnt = 0; 533 | while (stepResult == srOKAY) 534 | { iloc = reg[PC_REG] ; 535 | if ( traceflag ) writeInstruction( iloc ) ; 536 | stepResult = stepTM (); 537 | stepcnt++; 538 | } 539 | if ( icountflag ) 540 | printf("Number of instructions executed = %d\n",stepcnt); 541 | } 542 | else 543 | { while ((stepcnt > 0) && (stepResult == srOKAY)) 544 | { iloc = reg[PC_REG] ; 545 | if ( traceflag ) writeInstruction( iloc ) ; 546 | stepResult = stepTM (); 547 | stepcnt-- ; 548 | } 549 | } 550 | printf( "%s\n",stepResultTab[stepResult] ); 551 | } 552 | return TRUE; 553 | } /* doCommand */ 554 | 555 | 556 | /********************************************/ 557 | /* E X E C U T I O N B E G I N S H E R E */ 558 | /********************************************/ 559 | 560 | main( int argc, char * argv[] ) 561 | { if (argc != 2) 562 | { printf("usage: %s \n",argv[0]); 563 | exit(1); 564 | } 565 | strcpy(pgmName,argv[1]) ; 566 | if (strchr (pgmName, '.') == NULL) 567 | strcat(pgmName,".tm"); 568 | pgm = fopen(pgmName,"r"); 569 | if (pgm == NULL) 570 | { printf("file '%s' not found\n",pgmName); 571 | exit(1); 572 | } 573 | 574 | /* read the program */ 575 | if ( ! readInstructions ()) 576 | exit(1) ; 577 | /* switch input file to terminal */ 578 | /* reset( input ); */ 579 | /* read-eval-print */ 580 | printf("TM simulation (enter h for help)...\n"); 581 | do 582 | done = ! doCommand (); 583 | while (! done ); 584 | printf("Simulation done.\n"); 585 | return 0; 586 | } --------------------------------------------------------------------------------