/****************************************************/ /* File: analyze.c */ /* Semantic analyzer implementation */ /* for the CMinus compiler */ /* Yenru0 */ /****************************************************/ #include "analyze.h" #include "globals.h" #include "symtab.h" static void symbolError(TreeNode *t, char *message) { fprintf(listing, "Symbol error at line %d: %s\n", t->lineno, message); Error = TRUE; exit(-1); } static BucketList func_entry = NULL; static Scope func_scope; static TreeNode *func_params[256]; static int func_param_count = 0; /* Procedure traverse is a generic recursive * syntax tree traversal routine: * it applies preProc in preorder and postProc * in postorder to tree pointed to by t */ static void traverse(TreeNode *t, void (*preProc)(TreeNode *), void (*postProc)(TreeNode *)) { if (t != NULL) { preProc(t); { int i; for (i = 0; i < MAXCHILDREN; i++) traverse(t->child[i], preProc, postProc); } postProc(t); traverse(t->sibling, preProc, postProc); } } /* nullProc is a do-nothing procedure to * generate preorder-only or postorder-only * traversals from traverse */ static void nullProc(TreeNode *t) { if (t == NULL) return; else return; } /* Procedure insertNode inserts * identifiers stored in t into * the symbol table */ static void insertNode(TreeNode *t) { //printf("Insert Node: line %d\n", t->lineno); switch (t->nodekind) { case ExpK: switch (t->kind.exp) { case IdK: case ArrIdK: case CallK: { BucketList entry = st_lookup(t->attr.name); if (entry == NULL) { symbolError(t, "Undeclared Symbol"); } else { // t->type = entry->type;// TODO: Ambiguity t->scope = curr_scope(); st_entry_insert_line(entry, t->lineno); t->type = entry->type; } } default: break; } break; case StmtK: switch (t->kind.stmt) { case CompK: if (func_scope != NULL) { push_scope(func_scope); func_scope = NULL; for (int i = 0; i < func_param_count; i++) { TreeNode *param = func_params[i]; func_entry->param_types[func_entry->param_count++] = param->type; if (st_lookup_current(param->attr.name) != NULL) { symbolError(param, "Redefinition of a Parameter"); } else { st_try_insert(param->attr.name, SymbolParam, param->type, param->lineno); } } func_entry = NULL; func_scope = NULL; func_param_count = 0; } else { push_scope(scope_new("compound")); } break; default: break; } break; case DeclK: switch (t->kind.decl) { case FuncK: if (st_lookup(t->attr.name) != NULL) { symbolError(t, "Redefinition of a Function"); } else { func_entry = st_try_insert(t->attr.name, SymbolFunc, t->type, t->lineno); t->scope = curr_scope(); } func_scope = scope_new(t->attr.name); //push_scope(scope_new(t->attr.name)); break; case ArrParamK: case NonArrParamK: { if (t->type != Void) { func_params[func_param_count++] = t; } } break; case VarK: case ArrVarK: if (st_lookup_current(t->attr.name) != NULL) { symbolError(t, "Redefinition of a Variable"); } else { if (t->type == Void) { symbolError(t, "Variable cannot be of type void"); break; } t->scope = curr_scope(); st_try_insert(t->attr.name, SymbolVar, t->type, t->lineno); } break; default: break; } break; default: break; } } static void afterNode(TreeNode *t) { if (t->nodekind == StmtK && t->kind.stmt == CompK) { pop_scope(); } } /* Function buildSymtab constructs the symbol * table by preorder traversal of the syntax tree */ void buildSymtab(TreeNode *syntaxTree) { st_init(); BucketList entry; entry = st_try_insert("input", SymbolFunc, Integer, 0); entry->param_count = 0; entry = st_try_insert("output", SymbolFunc, Void, 0); entry->param_types[0] = Integer; entry->param_count = 1; traverse(syntaxTree, insertNode, afterNode); if (TraceAnalyze) { fprintf(listing, "\nSymbol table:\n\n"); printSymTab(listing); } } static void typeError(TreeNode *t, char *message) { fprintf(listing, "Type error at line %d: %s\n", t->lineno, message); Error = TRUE; } static void beforeCheckNode(TreeNode *t) { if (t->nodekind == DeclK && t->kind.decl == FuncK) { func_entry = st_lookup(t->attr.name); } } static void checkNode(TreeNode *t) { switch (t->nodekind) { case ExpK: switch (t->kind.exp) { case OpK: { TreeNode *left = t->child[0]; TreeNode *right = t->child[1]; if (left->type != Integer || right->type != Integer) { typeError(t, "Operator applied to non-integer"); } t->type = Integer; } break; case ConstK: t->type = Integer; break; case IdK: { BucketList entry = st_lookup_from(t->attr.name, t->scope); t->type = entry->type; } break; case ArrIdK: { if (t->child[0]->type != Integer) { typeError(t, "Array subscript is not an integer"); } t->type = IntegerArray; } break; case AssignK: { TreeNode *left = t->child[0]; TreeNode *right = t->child[1]; if (left->type != right->type) { typeError(t, "Assignment of different types"); } t->type = left->type; } break; case CallK: { BucketList entry = st_lookup_from(t->attr.name, t->scope);// not null if (entry->symbolKind != SymbolFunc) { typeError(t, "Call to a non-function"); } TreeNode *arg = t->child[0]; int i = 0;// 파라미터 인덱스 while (arg != NULL && i < entry->param_count) { if (arg->type != entry->param_types[i]) { typeError(t, "Type mismatch in argument: Expected different type"); } arg = arg->sibling; i++; } if (arg != NULL) { typeError(t, "Too many arguments in function call"); } else if (i < entry->param_count) { typeError(t, "Too few arguments in function call"); } t->type = entry->returnType; } break; default: break; } break; case StmtK: switch (t->kind.stmt) { case ReturnK: { if (func_entry == NULL) { typeError(t, "Return statement is not in a function"); break; } TreeNode *retval = t->child[0]; /* nullalbe */ if (func_entry->returnType == Void) { if (retval != NULL) { typeError(t, "Return with a value in a void function"); } } else { if (retval == NULL) { typeError(t, "Return without a value in a non-void function"); } else if (retval->type != func_entry->returnType) { typeError(t, "Return type mismatch"); } } } break; case IterK: { TreeNode *condition = t->child[0]; if (condition->type != Integer) { typeError(t, "While condition is not of type integer"); } } break; case IfK: { TreeNode *condition = t->child[0]; if (condition->type != Integer) { typeError(t, "If condition is not of type integer"); } } break; default: break; } break; case DeclK: switch (t->kind.decl) { case FuncK: func_entry = NULL; break; default: break; } default: break; } } /* Procedure typeCheck performs type checking * by a postorder syntax tree traversal */ void typeCheck(TreeNode *syntaxTree) { traverse(syntaxTree, beforeCheckNode, checkNode); }