├── README ├── ast.c ├── ast.h ├── base.c ├── base.h ├── compiler.h ├── graphprinter_visitor.c ├── graphprinter_visitor.h ├── makefile ├── parser.y ├── scanner.l ├── symbol_table.c ├── symbol_table.h ├── test.prog ├── typecheck_visitor.c └── typecheck_visitor.h /README: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soshimozi/Compiler/62a4a76e883394b6cdc2a2dbdc86d181b465c7ad/README -------------------------------------------------------------------------------- /ast.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "ast.h" 5 | //#include "typecheck_visitor.h" 6 | 7 | struct AstNode * 8 | ast_node_new(const char* name, int kind, int type, 9 | int linenum, Symbol *symbol) 10 | { 11 | int i; 12 | struct AstNode *node; 13 | 14 | node = (struct AstNode *) malloc (sizeof(struct AstNode)); 15 | 16 | if (name != NULL){ 17 | node->name = strdup(name); 18 | } else 19 | node->name = NULL; 20 | 21 | node->kind = kind; 22 | node->type = type; 23 | node->linenum = linenum; 24 | node->child_counter = 0; 25 | node->symbol = symbol; 26 | node->parent = NULL; 27 | node->children = NULL; 28 | node->sibling = NULL; 29 | 30 | return node; 31 | } 32 | 33 | void 34 | ast_node_destroy(struct AstNode *self) 35 | { 36 | if (self != NULL) { 37 | ast_node_destroy(self->children); 38 | ast_node_destroy(self->sibling); 39 | free(self); 40 | } 41 | } 42 | 43 | Value 44 | ast_node_get_value(struct AstNode *self) 45 | { 46 | if (self->kind == IDENTIFIER) 47 | return self->symbol->value; 48 | 49 | return self->value; 50 | } 51 | 52 | int 53 | ast_node_get_value_as_int(struct AstNode *self) 54 | { 55 | if (self->kind == IDENTIFIER) 56 | return self->symbol->value.integer; 57 | 58 | return self->value.integer; 59 | } 60 | 61 | int 62 | ast_node_get_child_counter(struct AstNode *self) 63 | { 64 | return self->child_counter++; 65 | } 66 | 67 | bool 68 | ast_node_check_errors(struct AstNode *self) 69 | { 70 | struct AstNode *child; 71 | 72 | if (self == NULL || self->type == ERROR) 73 | return TRUE; 74 | 75 | for (child = self->children; child != NULL; child = child->sibling) { 76 | if (ast_node_check_errors(child) == TRUE) 77 | return TRUE; 78 | } 79 | 80 | return FALSE; 81 | } 82 | 83 | void 84 | ast_node_add_child(struct AstNode *self, struct AstNode *child) 85 | { 86 | struct AstNode *temp; 87 | 88 | if (child == NULL) 89 | return; 90 | 91 | if (self->children == NULL) { 92 | child->parent = self; 93 | self->children = child; 94 | } else { 95 | ast_node_add_sibling(self->children, child); 96 | } 97 | for (temp = child; temp != NULL; temp = temp->sibling) 98 | temp->parent = self; 99 | } 100 | 101 | void 102 | ast_node_add_sibling(struct AstNode *self, struct AstNode *sibling) 103 | { 104 | struct AstNode *temp; 105 | 106 | if (sibling == NULL) 107 | return; 108 | 109 | if (self->sibling == NULL) { 110 | self->sibling = sibling; 111 | } else { 112 | for (temp = self->sibling; temp->sibling != NULL; temp = temp->sibling) 113 | ; 114 | temp->sibling = sibling; 115 | } 116 | } 117 | 118 | 119 | void 120 | ast_node_accept(struct AstNode *self, Visitor *visitor) 121 | { 122 | VisitFunc visit; 123 | 124 | if (self == NULL) 125 | return; 126 | 127 | self->child_counter = 1; 128 | 129 | switch (self->kind) { 130 | case PROGRAM: 131 | visit = visitor->visit_program; 132 | break; 133 | case PROGRAM_DECL: 134 | visit = visitor->visit_programdecl; 135 | break; 136 | case VARDECL_LIST: 137 | visit = visitor->visit_vardecl_list; 138 | break; 139 | case VARDECL: 140 | visit = visitor->visit_vardecl; 141 | break; 142 | case IDENT_LIST: 143 | visit = visitor->visit_identifier_list; 144 | break; 145 | case PROCFUNC_LIST: 146 | visit = visitor->visit_procfunc_list; 147 | break; 148 | case PROCEDURE: 149 | visit = visitor->visit_procedure; 150 | break; 151 | case FUNCTION: 152 | visit = visitor->visit_function; 153 | break; 154 | case PARAM_LIST: 155 | visit = visitor->visit_param_list; 156 | break; 157 | case PARAMETER: 158 | visit = visitor->visit_parameter; 159 | break; 160 | case STATEMENT_LIST: 161 | visit = visitor->visit_statement_list; 162 | break; 163 | case PRINTINT_STMT: 164 | visit = visitor->visit_printint_stmt; 165 | break; 166 | case PRINTCHAR_STMT: 167 | visit = visitor->visit_printchar_stmt; 168 | break; 169 | case PRINTBOOL_STMT: 170 | visit = visitor->visit_printbool_stmt; 171 | break; 172 | case PRINTLINE_STMT: 173 | visit = visitor->visit_printline_stmt; 174 | break; 175 | case ASSIGNMENT_STMT: 176 | visit = visitor->visit_assignment_stmt; 177 | break; 178 | case IF_STMT: 179 | visit = visitor->visit_if_stmt; 180 | break; 181 | case WHILE_STMT: 182 | visit = visitor->visit_while_stmt; 183 | break; 184 | case FOR_STMT: 185 | visit = visitor->visit_for_stmt; 186 | break; 187 | case REL_EXPR: 188 | visit = visitor->visit_rel_expr; 189 | break; 190 | case ADD_EXPR: 191 | visit = visitor->visit_add_expr; 192 | break; 193 | case MUL_EXPR: 194 | visit = visitor->visit_mul_expr; 195 | break; 196 | case NOTFACTOR: 197 | visit = visitor->visit_notfactor; 198 | break; 199 | case CALL: 200 | visit = visitor->visit_call; 201 | break; 202 | case CALLPARAM_LIST: 203 | visit = visitor->visit_callparam_list; 204 | break; 205 | case CALLPARAM: 206 | visit = visitor->visit_callparam; 207 | break; 208 | case IDENTIFIER: 209 | visit = visitor->visit_identifier; 210 | break; 211 | case INT_LITERAL: 212 | case BOOL_LITERAL: 213 | case CHAR_LITERAL: 214 | visit = visitor->visit_literal; 215 | break; 216 | case T_PLUS: 217 | case T_MINUS: 218 | case T_LOGICOR: 219 | case T_BITOR: 220 | visit = visitor->visit_add_op; 221 | break; 222 | case T_STAR: 223 | case T_SLASH: 224 | case T_LOGICAND: 225 | case T_BITAND: 226 | visit = visitor->visit_mul_op; 227 | break; 228 | case T_EQ: 229 | case T_NE: 230 | case T_LT: 231 | case T_GT: 232 | case T_LE: 233 | case T_GE: 234 | visit = visitor->visit_rel_op; 235 | break; 236 | default: 237 | visit = NULL; 238 | } 239 | 240 | if (visit != NULL) 241 | visit(visitor, self); 242 | } 243 | 244 | void 245 | ast_node_accept_children(struct AstNode *self, Visitor *visitor) 246 | { 247 | struct AstNode *temp; 248 | for (temp = self; temp != NULL; temp = temp->sibling) 249 | ast_node_accept(temp, visitor); 250 | } 251 | 252 | -------------------------------------------------------------------------------- /ast.h: -------------------------------------------------------------------------------- 1 | #ifndef AST_H 2 | #define AST_H 3 | 4 | #include "compiler.h" 5 | #include "base.h" 6 | #include "parser.h" 7 | #include "symbol_table.h" 8 | 9 | struct AstNode { 10 | char *name; 11 | int kind; 12 | Type type; 13 | Value value; 14 | Symbol *symbol; 15 | int linenum; 16 | int child_counter; 17 | struct AstNode* parent; 18 | struct AstNode* children; 19 | struct AstNode* sibling; 20 | }; 21 | 22 | typedef struct _Visitor { 23 | void (*visit_program) (struct _Visitor *, struct AstNode *); 24 | void (*visit_programdecl) (struct _Visitor *, struct AstNode *); 25 | void (*visit_vardecl_list) (struct _Visitor *, struct AstNode *); 26 | void (*visit_vardecl) (struct _Visitor *, struct AstNode *); 27 | void (*visit_identifier_list) (struct _Visitor *, struct AstNode *); 28 | void (*visit_identifier) (struct _Visitor *, struct AstNode *); 29 | void (*visit_procfunc_list) (struct _Visitor *, struct AstNode *); 30 | void (*visit_procedure) (struct _Visitor *, struct AstNode *); 31 | void (*visit_function) (struct _Visitor *, struct AstNode *); 32 | void (*visit_param_list) (struct _Visitor *, struct AstNode *); 33 | void (*visit_parameter) (struct _Visitor *, struct AstNode *); 34 | void (*visit_statement_list) (struct _Visitor *, struct AstNode *); 35 | void (*visit_printint_stmt) (struct _Visitor *, struct AstNode *); 36 | void (*visit_printchar_stmt) (struct _Visitor *, struct AstNode *); 37 | void (*visit_printbool_stmt) (struct _Visitor *, struct AstNode *); 38 | void (*visit_printline_stmt) (struct _Visitor *, struct AstNode *); 39 | void (*visit_assignment_stmt) (struct _Visitor *, struct AstNode *); 40 | void (*visit_if_stmt) (struct _Visitor *, struct AstNode *); 41 | void (*visit_while_stmt) (struct _Visitor *, struct AstNode *); 42 | void (*visit_for_stmt) (struct _Visitor *, struct AstNode *); 43 | void (*visit_rel_expr) (struct _Visitor *, struct AstNode *); 44 | void (*visit_add_expr) (struct _Visitor *, struct AstNode *); 45 | void (*visit_mul_expr) (struct _Visitor *, struct AstNode *); 46 | void (*visit_notfactor) (struct _Visitor *, struct AstNode *); 47 | void (*visit_call) (struct _Visitor *, struct AstNode *); 48 | void (*visit_callparam_list) (struct _Visitor *, struct AstNode *); 49 | void (*visit_callparam) (struct _Visitor *, struct AstNode *); 50 | void (*visit_literal) (struct _Visitor *, struct AstNode *); 51 | void (*visit_add_op) (struct _Visitor *, struct AstNode *); 52 | void (*visit_mul_op) (struct _Visitor *, struct AstNode *); 53 | void (*visit_rel_op) (struct _Visitor *, struct AstNode *); 54 | void (*visit_not_op) (struct _Visitor *, struct AstNode *); 55 | } Visitor; 56 | 57 | typedef void (*VisitFunc)(struct _Visitor *, struct AstNode *); 58 | 59 | struct AstNode *ast_node_new(const char *name, int kind, int type, 60 | int linenum, Symbol *symbol); 61 | void ast_node_destroy(struct AstNode *); 62 | 63 | Value ast_node_get_value(struct AstNode *); 64 | int ast_node_get_value_as_int(struct AstNode *); 65 | int ast_node_get_child_counter(struct AstNode *); 66 | bool ast_node_check_errors(struct AstNode *); 67 | void ast_node_add_child(struct AstNode *, struct AstNode *); 68 | void ast_node_add_sibling(struct AstNode *, struct AstNode *); 69 | void ast_node_accept(struct AstNode *, Visitor *); 70 | void ast_node_accept_children(struct AstNode *, Visitor *); 71 | 72 | #endif // AST_H 73 | -------------------------------------------------------------------------------- /base.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "base.h" 5 | 6 | Type 7 | type_get_from_lexeme(const char *lexeme) 8 | { 9 | if (!strcasecmp (lexeme, "Int")) 10 | return INTEGER; 11 | else if (!strcasecmp (lexeme, "Bool")) 12 | return BOOLEAN; 13 | else if (!strcasecmp (lexeme, "Char")) 14 | return CHAR; 15 | else 16 | return VOID; 17 | } 18 | 19 | char * 20 | type_get_lexeme(Type type) 21 | { 22 | switch (type) { 23 | case VOID: 24 | return "void"; 25 | case INTEGER: 26 | return "int"; 27 | case BOOLEAN: 28 | return "bool"; 29 | case CHAR: 30 | return "char"; 31 | case ERROR: 32 | return "error"; 33 | default: 34 | return ""; 35 | } 36 | } 37 | 38 | void 39 | value_print(FILE *file, Value *value, Type type) 40 | { 41 | if (type == INTEGER) { 42 | fprintf(file, "%d", value->integer); 43 | } else if (type == BOOLEAN) { 44 | fprintf(file, "%s", value->boolean ? "true" : "false"); 45 | } else if (type == CHAR) { 46 | fprintf(file, "'%c'", value->character); 47 | } 48 | } 49 | 50 | void 51 | value_get(Value *value, Type type, void *val) 52 | { 53 | if (value == NULL) { 54 | fprintf(stderr, "base.c: value_get: value == NULL\n"); 55 | exit(1); 56 | } 57 | 58 | if (type == INTEGER) { 59 | *((int *) val) = value->integer; 60 | } else if (type == BOOLEAN) { 61 | *((bool *) val) = value->boolean; 62 | } else if (type == CHAR) { 63 | *((char *) val) = value->character; 64 | } else { 65 | fprintf(stderr, "base.c: value_get: unknow type\n"); 66 | exit(1); 67 | } 68 | } 69 | 70 | void 71 | value_set(Value *value, Type type, void *val) 72 | { 73 | if (value == NULL) { 74 | fprintf(stderr, "base.c: value_set: value == NULL\n"); 75 | exit(1); 76 | } 77 | 78 | if (type == VOID || val == NULL) { 79 | value->integer = 0; 80 | } else if (type == INTEGER) { 81 | value->integer = *((int *) val); 82 | } else if (type == BOOLEAN) { 83 | value->boolean = *((bool *) val); 84 | } else if (type == CHAR) { 85 | value->character = *((char *) val); 86 | } else { 87 | fprintf(stderr, "base.c: value_set: unknow type\n"); 88 | exit(1); 89 | } 90 | } 91 | 92 | void 93 | value_set_from_int(Value *value, int val) 94 | { 95 | value_set(value, INTEGER, VOID(val)); 96 | } 97 | 98 | void 99 | value_set_from_bool(Value *value, bool val) 100 | { 101 | value_set(value, BOOLEAN, VOID(val)); 102 | } 103 | 104 | void 105 | value_set_from_char(Value *value, char val) 106 | { 107 | value_set(value, CHAR, VOID(val)); 108 | } 109 | 110 | -------------------------------------------------------------------------------- /base.h: -------------------------------------------------------------------------------- 1 | #ifndef BASE_H 2 | #define BASE_H 3 | 4 | #define VOID(var) ((void *) &var) 5 | #define IS_LITERAL(k) (k == BOOL_LITERAL || \ 6 | k == CHAR_LITERAL || \ 7 | k == INT_LITERAL) 8 | 9 | typedef enum { 10 | FALSE = 0, 11 | TRUE 12 | } bool; 13 | 14 | typedef enum TypeEnum { 15 | ERROR = -1, 16 | VOID, 17 | INTEGER, 18 | BOOLEAN, 19 | CHAR 20 | } Type; 21 | 22 | typedef enum KindEnum { 23 | NONE_KIND = -1, 24 | PROGRAM, 25 | PROGRAM_DECL, 26 | VARDECL_LIST, 27 | VARDECL, 28 | IDENT_LIST, 29 | PROCFUNC_LIST, 30 | PROCEDURE, 31 | FUNCTION, 32 | PARAM_LIST, 33 | PARAMETER, 34 | STATEMENT_LIST, 35 | PRINTINT_STMT, 36 | PRINTCHAR_STMT, 37 | PRINTBOOL_STMT, 38 | PRINTLINE_STMT, 39 | ASSIGNMENT_STMT, 40 | IF_STMT, 41 | WHILE_STMT, 42 | FOR_STMT, 43 | REL_EXPR, 44 | ADD_EXPR, 45 | MUL_EXPR, 46 | NOTFACTOR, 47 | CALL, 48 | CALLPARAM_LIST, 49 | CALLPARAM, 50 | //IDENTIFIER defined as token 51 | //INT_LITERAL, BOOL_LITERAL, CHAR_LITERAL defined as tokens 52 | } Kind; 53 | 54 | typedef union { 55 | int integer; 56 | bool boolean; 57 | char character; 58 | } Value; 59 | 60 | char *type_get_lexeme(Type type); 61 | Type type_get_from_lexeme(const char *lexeme); 62 | 63 | void value_get(Value *value, Type type, void *val); 64 | void value_set(Value *value, Type type, void *val); 65 | 66 | void value_set_from_int(Value *value, int val); 67 | void value_set_from_bool(Value *value, bool val); 68 | void value_set_from_char(Value *value, char val); 69 | 70 | void value_print(FILE *file, Value *value, Type type); 71 | 72 | #endif // BASE_H 73 | 74 | -------------------------------------------------------------------------------- /compiler.h: -------------------------------------------------------------------------------- 1 | typedef enum { typeCon, typeId, typeOpr } nodeEnum; 2 | 3 | /* constants */ 4 | typedef struct { 5 | int value; /* value of constant */ 6 | } conNodeType; 7 | 8 | /* identifiers */ 9 | typedef struct { 10 | int i; /* subscript to sym array */ 11 | } idNodeType; 12 | 13 | /* operators */ 14 | typedef struct { 15 | int oper; /* operator */ 16 | int nops; /* number of operands */ 17 | struct nodeTypeTag *op[1]; /* operands (exandable) */ 18 | } oprNodeType; 19 | 20 | typedef struct nodeTypeTag { 21 | nodeEnum type; /* type of node */ 22 | 23 | /* union must be last entry in nodeType */ 24 | /* because operNodeType may dynamicaly increase */ 25 | union { 26 | conNodeType con; /* constants */ 27 | idNodeType id; /* identifiers */ 28 | oprNodeType opr; /* operators */ 29 | }; 30 | } nodeType; 31 | 32 | extern int sym[26]; 33 | 34 | 35 | -------------------------------------------------------------------------------- /graphprinter_visitor.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "graphprinter_visitor.h" 5 | 6 | static void _print_arrow(struct AstNode *node); 7 | static void _print_symbol_table(struct AstNode *node); 8 | static void _print_symbols(Symbol *symbol); 9 | 10 | Visitor * 11 | graphprinter_new() 12 | { 13 | Visitor *visitor = (Visitor *) malloc (sizeof(Visitor)); 14 | 15 | visitor->visit_program = &graphprinter_visit_program; 16 | visitor->visit_programdecl = &graphprinter_visit_programdecl; 17 | visitor->visit_vardecl_list = &graphprinter_visit_vardecl_list; 18 | visitor->visit_vardecl = &graphprinter_visit_simplenode; 19 | visitor->visit_identifier_list = &graphprinter_visit_identifier_list; 20 | visitor->visit_procfunc_list = &graphprinter_visit_procfunc_list; 21 | visitor->visit_procedure = &graphprinter_visit_procfunc; 22 | visitor->visit_function = &graphprinter_visit_procfunc; 23 | visitor->visit_param_list = &graphprinter_visit_param_list; 24 | visitor->visit_parameter = &graphprinter_visit_parameter; 25 | visitor->visit_statement_list = &graphprinter_visit_statement_list; 26 | visitor->visit_printint_stmt = &graphprinter_visit_simplenode; 27 | visitor->visit_printchar_stmt = &graphprinter_visit_simplenode; 28 | visitor->visit_printbool_stmt = &graphprinter_visit_simplenode; 29 | visitor->visit_printline_stmt = &graphprinter_visit_simplenode; 30 | visitor->visit_assignment_stmt = &graphprinter_visit_simplenode; 31 | visitor->visit_if_stmt = &graphprinter_visit_simplenode; 32 | visitor->visit_while_stmt = &graphprinter_visit_simplenode; 33 | visitor->visit_for_stmt = &graphprinter_visit_simplenode; 34 | visitor->visit_rel_expr = &graphprinter_visit_binary_expr; 35 | visitor->visit_add_expr = &graphprinter_visit_binary_expr; 36 | visitor->visit_mul_expr = &graphprinter_visit_binary_expr; 37 | visitor->visit_notfactor = &graphprinter_visit_simplenode; 38 | visitor->visit_call = &graphprinter_visit_call; 39 | visitor->visit_callparam_list = &graphprinter_visit_callparam_list; 40 | visitor->visit_callparam = &graphprinter_visit_callparam; 41 | visitor->visit_identifier = &graphprinter_visit_identifier; 42 | visitor->visit_literal = &graphprinter_visit_literal; 43 | visitor->visit_add_op = NULL; 44 | visitor->visit_mul_op = NULL; 45 | visitor->visit_rel_op = NULL; 46 | visitor->visit_not_op = NULL; 47 | 48 | return visitor; 49 | } 50 | 51 | void 52 | graphprinter_visit_program(struct _Visitor *visitor, struct AstNode *node) 53 | { 54 | printf("/* toypasc AST graph. */\n"); 55 | printf("digraph {\n"); 56 | 57 | printf("\tremincross=true;\n"); 58 | printf("\tordering=out;\n"); 59 | printf("\tcompound=true;\n"); 60 | printf("\tranksep=1.0;\n"); 61 | printf("\tnode [fontsize=11,fontname=Courier];\n"); 62 | printf("\tedge [color="COLOR_EDGE_GROUP"];\n\n"); 63 | 64 | printf("\tnode_%x [label=\"%s\",fontsize=16,fontname=Courier,", 65 | (unsigned)node, node->name); 66 | printf("style=filled,color=black,fillcolor="COLOR_FILL_GLOBAL"];\n"); 67 | 68 | _print_symbol_table(node); 69 | 70 | ast_node_accept_children(node->children, visitor); 71 | 72 | printf("}\n"); 73 | } 74 | 75 | void 76 | graphprinter_visit_simplenode (struct _Visitor *visitor, struct AstNode *node) 77 | { 78 | _print_arrow(node); 79 | printf("\tnode_%x [label=\"%s\\n[line: %d]\",style=filled,", 80 | (unsigned)node, node->name, node->linenum); 81 | printf("fillcolor="COLOR_FILL_COMMON",color=%s];\n", 82 | (node->type == ERROR) ? COLOR_EDGE_ERROR : COLOR_FILL_COMMON); 83 | ast_node_accept_children(node->children, visitor); 84 | } 85 | 86 | void 87 | graphprinter_visit_programdecl(struct _Visitor *visitor, struct AstNode *node) 88 | { 89 | _print_arrow(node); 90 | printf("\tnode_%x [label=\"%s\\n[line: %d]\",style=filled,", 91 | (unsigned)node, node->name, node->linenum); 92 | printf("color="COLOR_EDGE_GROUP",fillcolor="COLOR_FILL_COMMON"];\n"); 93 | ast_node_accept(node->children, visitor); 94 | printf("\tnode_%x -> symbol_%x [color=lightgray];\n", (unsigned)node->children, (unsigned)node->children->symbol); 95 | } 96 | 97 | void 98 | graphprinter_visit_vardecl_list (struct _Visitor *visitor, struct AstNode *node) 99 | { 100 | _print_arrow(node); 101 | printf("\tnode_%x [label=\"%s\",style=filled,", (unsigned)node, node->name); 102 | printf("color="COLOR_EDGE_GROUP",fillcolor="COLOR_FILL_COMMON"];\n"); 103 | printf("\nsubgraph cluster_%x {\n\tstyle=dotted;\n", (unsigned)node); 104 | ast_node_accept_children(node->children, visitor); 105 | printf("}\n\n"); 106 | } 107 | 108 | void 109 | graphprinter_visit_identifier_list (struct _Visitor *visitor, struct AstNode *node) 110 | { 111 | _print_arrow(node); 112 | printf("\tnode_%x [label=\"%s\",style=filled,", (unsigned)node, node->name); 113 | printf("color="COLOR_EDGE_GROUP",fillcolor="COLOR_FILL_COMMON"];\n"); 114 | printf("\nsubgraph cluster_%x {\n\tstyle=dotted;\n", (unsigned)node); 115 | ast_node_accept_children(node->children, visitor); 116 | printf("}\n\n"); 117 | } 118 | 119 | void 120 | graphprinter_visit_procfunc_list (struct _Visitor *visitor, struct AstNode *node) 121 | { 122 | _print_arrow(node); 123 | printf("\tnode_%x [label=\"%s\",style=filled,", (unsigned)node, node->name); 124 | printf("color="COLOR_EDGE_GROUP",fillcolor="COLOR_FILL_COMMON"];\n"); 125 | ast_node_accept_children(node->children, visitor); 126 | } 127 | 128 | void 129 | graphprinter_visit_procfunc (struct _Visitor *visitor, struct AstNode *node) 130 | { 131 | _print_arrow(node); 132 | printf("\tnode_%x [label=\"%s\\n<%s>\\n[line: %d]\",style=filled,", 133 | (unsigned)node, node->name, type_get_lexeme(node->type), node->linenum); 134 | printf("color=blue,fillcolor="COLOR_EDGE_FUNCT"];\n"); 135 | printf("\nsubgraph cluster_%x {\n\tstyle=dotted;\n", (unsigned)node); 136 | 137 | _print_symbol_table(node); 138 | ast_node_accept_children(node->children, visitor); 139 | printf("}\n\n"); 140 | } 141 | 142 | void 143 | graphprinter_visit_param_list (struct _Visitor *visitor, struct AstNode *node) 144 | { 145 | _print_arrow(node); 146 | printf("\tnode_%x [label=\"%s\",style=filled,", (unsigned)node, node->name); 147 | printf("color="COLOR_EDGE_GROUP",fillcolor="COLOR_FILL_COMMON"];\n"); 148 | printf("\nsubgraph cluster_%x {\n\tstyle=dotted;\n", (unsigned)node); 149 | ast_node_accept_children(node->children, visitor); 150 | printf("}\n\n"); 151 | } 152 | 153 | void 154 | graphprinter_visit_parameter (struct _Visitor *visitor, struct AstNode *node) 155 | { 156 | _print_arrow(node); 157 | printf("\tnode_%x [label=\"%s\",style=filled,", (unsigned)node, node->name); 158 | printf("fillcolor="COLOR_FILL_COMMON",color=%s];\n", 159 | (node->type == ERROR) ? COLOR_EDGE_ERROR : COLOR_FILL_COMMON); 160 | ast_node_accept_children(node->children, visitor); 161 | } 162 | 163 | void 164 | graphprinter_visit_statement_list (struct _Visitor *visitor, struct AstNode *node) 165 | { 166 | _print_arrow(node); 167 | printf("\tnode_%x [label=\"%s\",style=filled,", (unsigned)node, node->name); 168 | printf("color="COLOR_EDGE_GROUP",fillcolor="COLOR_FILL_COMMON"];\n"); 169 | printf("\nsubgraph cluster_%x {\n\tstyle=dotted;\n", (unsigned)node); 170 | ast_node_accept_children(node->children, visitor); 171 | printf("}\n\n"); 172 | } 173 | 174 | void 175 | graphprinter_visit_binary_expr (struct _Visitor *visitor, struct AstNode *node) 176 | { 177 | _print_arrow(node); 178 | printf("\tnode_%x [label=\"%s\\n'%s'\",style=filled,", 179 | (unsigned)node, node->name, node->children->sibling->name); 180 | printf("fillcolor="COLOR_FILL_COMMON",color=%s];\n", 181 | (node->type == ERROR) ? COLOR_EDGE_ERROR : COLOR_FILL_COMMON); 182 | ast_node_accept_children(node->children, visitor); 183 | } 184 | 185 | void 186 | graphprinter_visit_call (struct _Visitor *visitor, struct AstNode *node) 187 | { 188 | struct AstNode *ident = node->children; 189 | struct AstNode *plist = ident->sibling; 190 | 191 | _print_arrow(node); 192 | printf("\tnode_%x [label=\"%s\\n[line: %d]\",style=filled,", 193 | (unsigned)node, node->name, node->linenum); 194 | printf("fillcolor="COLOR_FILL_COMMON",color=%s];\n", 195 | (node->type == ERROR) ? COLOR_EDGE_ERROR : COLOR_FILL_COMMON); 196 | printf("\nsubgraph cluster_%x {\n\tstyle=dotted;\n", (unsigned)node); 197 | ast_node_accept(ident, visitor); 198 | ast_node_accept(plist, visitor); 199 | printf("}\n\n"); 200 | } 201 | 202 | void 203 | graphprinter_visit_callparam_list (struct _Visitor *visitor, struct AstNode *node) 204 | { 205 | int i; 206 | 207 | _print_arrow(node); 208 | printf("\tnode_%x [label=\"%s\\n<", (unsigned)node, node->name); 209 | 210 | for (i = 0; i < node->symbol->params; i++) { 211 | printf("%s", type_get_lexeme(node->symbol->param_types[i])); 212 | if (i + 1 < node->symbol->params) 213 | printf(", "); 214 | } 215 | 216 | 217 | printf(">\",style=filled,fillcolor="COLOR_FILL_COMMON",color=%s];\n", 218 | (node->type == ERROR) ? COLOR_EDGE_ERROR : COLOR_EDGE_GROUP); 219 | 220 | ast_node_accept_children(node->children, visitor); 221 | } 222 | 223 | void 224 | graphprinter_visit_callparam (struct _Visitor *visitor, struct AstNode *node) 225 | { 226 | _print_arrow(node); 227 | printf("\tnode_%x [label=\"%s\\n<%s>\",style=filled,", 228 | (unsigned)node, node->name, type_get_lexeme(node->type)); 229 | printf("fillcolor="COLOR_FILL_COMMON",color=%s];\n", 230 | (node->type == ERROR) ? COLOR_EDGE_ERROR : COLOR_FILL_COMMON); 231 | ast_node_accept_children(node->children, visitor); 232 | } 233 | 234 | void 235 | graphprinter_visit_identifier (struct _Visitor *visitor, struct AstNode *node) 236 | { 237 | _print_arrow(node); 238 | 239 | printf("\tnode_%x [label=\"", (unsigned)node); 240 | 241 | if (node->symbol->decl_linenum == 0) 242 | printf("UNDECLARED\\n"); 243 | 244 | printf("%s\\n'%s'\\n<%s>\",style=filled,color=", 245 | node->name, node->symbol->name, type_get_lexeme(node->type)); 246 | 247 | if (node->symbol->decl_linenum == 0) 248 | printf(COLOR_EDGE_ERROR); 249 | else if (node->symbol->is_global) 250 | printf(COLOR_FILL_GLOBAL); 251 | else 252 | printf(COLOR_FILL_LOCAL); 253 | 254 | printf(",fillcolor="); 255 | 256 | if (node->symbol->is_global) 257 | printf(COLOR_FILL_GLOBAL); 258 | else 259 | printf(COLOR_FILL_LOCAL); 260 | 261 | printf("];\n"); 262 | } 263 | 264 | void 265 | graphprinter_visit_literal (struct _Visitor *visitor, struct AstNode *node) 266 | { 267 | printf("\tnode_%x -> literal_%x;\n", (unsigned)node->parent, (unsigned)node); 268 | printf("\tliteral_%x [label=\"", (unsigned)node); 269 | value_print(stdout, &node->value, node->type); 270 | printf("\\n<%s>\",style=filled,color="COLOR_FILL_LITERAL"];\n", 271 | node->name, type_get_lexeme(node->type)); 272 | ast_node_accept_children(node->children, visitor); 273 | } 274 | 275 | // Helper functions ---------------------------------------------------------- 276 | 277 | static void 278 | _print_arrow(struct AstNode *node) 279 | { 280 | printf("\tnode_%x -> node_%x [label=\"%d\",", 281 | (unsigned)node->parent, (unsigned)node, ast_node_get_child_counter(node->parent)); 282 | printf("fontsize=11,fontname=Courier];\n"); 283 | } 284 | 285 | static void 286 | _print_symbol_table(struct AstNode *node) 287 | { 288 | if (node->symbol->next == NULL) 289 | return; 290 | 291 | printf("\tnode_%x -> symbol_%x [lhead=cluster_symtab_%x,color=", 292 | (unsigned)node, (unsigned)node->symbol->next, (unsigned)node); 293 | if (node->parent == NULL) 294 | printf("black];\n"); 295 | else 296 | printf("blue];\n"); 297 | 298 | printf("\n\tsubgraph cluster_symtab_%x {\n", (unsigned)node); 299 | 300 | if (node->parent == NULL) 301 | printf("\t\tcolor=black;\n"); 302 | else 303 | printf("\t\tcolor=blue;\n"); 304 | 305 | printf("\t\tstyle=filled;\n\t\tfillcolor="COLOR_FILL_GLOBAL";\n\t\tfontname=Courier;\n"); 306 | printf("\t\tnode [style=filled,color=white,fillcolor="COLOR_FILL_SYMBOL"];\n"); 307 | 308 | _print_symbols(node->symbol->next); 309 | 310 | printf("\t}\n\n"); 311 | } 312 | 313 | static void 314 | _print_symbols(Symbol *symbol) 315 | { 316 | if (symbol == NULL) 317 | return; 318 | 319 | if (symbol->name != NULL) { 320 | printf("\t\tsymbol_%x [shape=record,label=\"{", (unsigned)symbol); 321 | printf("Symbol|Address: 0x%x\\l|lexeme: %s\\l|", (unsigned)symbol, symbol->name); 322 | printf("type: %s\\l}\"", type_get_lexeme(symbol->type)); 323 | printf(",style=filled,color=white,fillcolor="COLOR_FILL_SYMBOL"];\n"); 324 | 325 | if (symbol->next != NULL) 326 | printf("\tsymbol_%x -> symbol_%x;\n", (unsigned)symbol, (unsigned)symbol->next); 327 | 328 | } 329 | 330 | _print_symbols(symbol->next); 331 | } 332 | 333 | -------------------------------------------------------------------------------- /graphprinter_visitor.h: -------------------------------------------------------------------------------- 1 | #ifndef GRAPHPRINTER_VISITOR_H 2 | #define GRAPHPRINTER_VISITOR_H 3 | 4 | #include "ast.h" 5 | 6 | #define COLOR_FILL_GLOBAL "\"#EEEEEE\"" 7 | #define COLOR_FILL_LOCAL "\"#CAE7FF\"" 8 | #define COLOR_FILL_COMMON "\"#EEFFEE\"" 9 | #define COLOR_FILL_LITERAL "\"#FFFFCC\"" 10 | #define COLOR_FILL_SYMBOL "\"#CCFF99\"" 11 | #define COLOR_FILL_ERROR "\"#FFEEEE\"" 12 | 13 | #define COLOR_EDGE_GROUP "\"#22DDAA\"" 14 | #define COLOR_EDGE_FUNCT "\"#EEEEFF\"" 15 | #define COLOR_EDGE_ERROR "\"#FF0000\"" 16 | 17 | Visitor *graphprinter_new(); 18 | 19 | void graphprinter_visit_program (struct _Visitor *, struct AstNode *); 20 | void graphprinter_visit_programdecl (struct _Visitor *, struct AstNode *); 21 | void graphprinter_visit_vardecl_list (struct _Visitor *, struct AstNode *); 22 | void graphprinter_visit_identifier_list (struct _Visitor *, struct AstNode *); 23 | void graphprinter_visit_procfunc_list (struct _Visitor *, struct AstNode *); 24 | void graphprinter_visit_procfunc (struct _Visitor *, struct AstNode *); 25 | void graphprinter_visit_param_list (struct _Visitor *, struct AstNode *); 26 | void graphprinter_visit_parameter (struct _Visitor *, struct AstNode *); 27 | void graphprinter_visit_statement_list (struct _Visitor *, struct AstNode *); 28 | void graphprinter_visit_binary_expr (struct _Visitor *, struct AstNode *); 29 | void graphprinter_visit_call (struct _Visitor *, struct AstNode *); 30 | void graphprinter_visit_callparam_list (struct _Visitor *, struct AstNode *); 31 | void graphprinter_visit_callparam (struct _Visitor *, struct AstNode *); 32 | void graphprinter_visit_identifier (struct _Visitor *, struct AstNode *); 33 | void graphprinter_visit_literal (struct _Visitor *, struct AstNode *); 34 | 35 | void graphprinter_visit_simplenode (struct _Visitor *, struct AstNode *); 36 | 37 | #endif // GRAPHPRINTER_VISITOR_H 38 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | LEX=flex 2 | LEXFLAGS= 3 | YACC=bison 4 | YACCFLAGS=-v -t -d 5 | CC=gcc 6 | CFLAGS=-ggdb 7 | LIBS= 8 | PARSER=parser 9 | SCANNER=scanner 10 | OBJS=$(SCANNER).o $(PARSER).o ast.o base.o symbol_table.o typecheck_visitor.o graphprinter_visitor.o 11 | PROGRAM=compiler 12 | 13 | all: $(OBJS) 14 | $(CC) $(LIBS) $(OBJS) -o $(PROGRAM) 15 | 16 | graphprinter_visitor.o: graphprinter_visitor.c graphprinter_visitor.h 17 | $(CC) $(CFLAGS) graphprinter_visitor.c -c 18 | 19 | typecheck_visitor.o: typecheck_visitor.c typecheck_visitor.h 20 | $(CC) $(CFLAGS) typecheck_visitor.c -c 21 | 22 | symbol_table.o: symbol_table.c symbol_table.h 23 | $(CC) $(CFLAGS) symbol_table.c -c 24 | 25 | ast.o: ast.c ast.h 26 | $(CC) $(CFLAGS) ast.c -c 27 | 28 | base.o: base.c base.h 29 | $(CC) $(CFLAGS) base.c -c 30 | 31 | $(PARSER).o: $(PARSER).c $(PARSER).h 32 | $(CC) $(CFLAGS) $(PARSER).c -c 33 | 34 | $(SCANNER).o: $(SCANNER).c $(PARSER).h 35 | $(CC) $(CFLAGS) $(SCANNER).c -c 36 | 37 | $(SCANNER).c: $(SCANNER).l 38 | $(LEX) $(LEXFLAGS) -o$(SCANNER).c $(SCANNER).l 39 | 40 | $(PARSER).h: $(PARSER).y 41 | $(YACC) $(YACCFLAGS) $(PARSER).y -o $(PARSER).c 42 | 43 | clean: 44 | rm -rf $(SCANNER).c $(PARSER).c $(PARSER).h *.o $(PROGRAM) 45 | 46 | -------------------------------------------------------------------------------- /parser.y: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include "base.h" 7 | #include "parser.h" 8 | #include "ast.h" 9 | #include "symbol_table.h" 10 | 11 | #include "typecheck_visitor.h" 12 | #include "graphprinter_visitor.h" 13 | 14 | 15 | 16 | extern FILE *yyin; 17 | 18 | static void yyerror( const char *msg ); 19 | 20 | static struct AstNode *ast; 21 | 22 | %} 23 | 24 | %defines 25 | %locations 26 | %pure-parser 27 | %error-verbose 28 | 29 | %union { 30 | char* lexeme; 31 | int integer; 32 | int boolean; 33 | char character; 34 | int type; 35 | struct AstNode *astnode; 36 | }; 37 | 38 | %token IDENTIFIER 39 | %token TYPE_IDENTIFIER 40 | %token INT_LITERAL 41 | %token BOOL_LITERAL 42 | %token CHAR_LITERAL 43 | 44 | %token T_WHILE T_IF T_PROGRAM T_FUNCTION T_COLON T_PROC 45 | %token T_COMMA T_SEMICOLON T_LBRACE T_RBRACE T_LPAR T_RPAR 46 | %token T_DO T_DOT T_ASSIGN 47 | %nonassoc IFX 48 | %nonassoc T_ELSE 49 | 50 | %left T_BITOR 51 | %left T_LOGICOR 52 | %left T_BITAND 53 | %left T_LOGICAND 54 | %left T_EQ T_NE 55 | %left T_LT T_GT T_LE T_GE 56 | %left T_PLUS T_MINUS 57 | %left T_STAR T_SLASH 58 | %nonassoc UMINUS 59 | 60 | %type program 61 | %type ident 62 | %type program_decl 63 | %type var_decl_list 64 | %type multi_var_decl 65 | %type var_decl 66 | %type identlist 67 | %type single_identifier 68 | %type multi_identifier 69 | 70 | %type proc_func_list 71 | %type multi_proc_func_decl 72 | %type proc_func_decl 73 | %type func_decl 74 | %type proc_decl 75 | 76 | %type param_list 77 | %type single_param 78 | %type multi_param 79 | 80 | %type type 81 | 82 | %start program 83 | 84 | %% 85 | 86 | program: 87 | program_decl var_decl_list proc_func_list statement_block 88 | { 89 | struct AstNode *ast_node; 90 | ast_node = ast_node_new("Program", PROGRAM, VOID, 91 | yylloc.last_line, NULL); 92 | ast_node_add_child(ast_node, $1); // program_decl 93 | ast_node_add_child(ast_node, $2); // var_decl_list 94 | ast_node_add_child(ast_node, $3); // proc_func_list 95 | $$ = ast_node; 96 | 97 | ast = ast_node; 98 | //ast_node_add_child(ast_node, $3); // statement_block 99 | } 100 | ; 101 | 102 | var_decl_list: 103 | /* empty */ { $$ = NULL; } 104 | | multi_var_decl 105 | { 106 | struct AstNode *ast_node; 107 | ast_node = ast_node_new("VarDeclList", VARDECL_LIST, VOID, 108 | yylloc.last_line, NULL); 109 | ast_node_add_child(ast_node, $1); 110 | $$ = ast_node; 111 | } 112 | ; 113 | 114 | multi_var_decl: 115 | var_decl { $$ = $1; } 116 | | var_decl multi_var_decl 117 | { 118 | ast_node_add_sibling($1, $2); 119 | $$ = $1; 120 | } 121 | ; 122 | 123 | var_decl: 124 | type identlist T_SEMICOLON 125 | { 126 | struct AstNode *ast_node; 127 | ast_node = ast_node_new("VarDecl", VARDECL, $1, 128 | yylloc.last_line, NULL); 129 | ast_node_add_child(ast_node, $2); 130 | $$ = ast_node; 131 | } 132 | ; 133 | 134 | proc_func_list: 135 | /* empty */ { $$ = NULL; } 136 | | proc_func_decl multi_proc_func_decl 137 | { 138 | struct AstNode *ast_node; 139 | ast_node = ast_node_new("ProcFuncList", PROCFUNC_LIST, VOID, 140 | yylloc.last_line, NULL); 141 | ast_node_add_sibling($1, $2); 142 | ast_node_add_child(ast_node, $1); 143 | 144 | $$ = ast_node; 145 | } 146 | ; 147 | 148 | multi_proc_func_decl: 149 | /* empty */ { $$ = NULL; } 150 | | proc_func_decl multi_proc_func_decl 151 | { 152 | ast_node_add_sibling($1, $2); 153 | } 154 | ; 155 | 156 | proc_func_decl: 157 | proc_decl { $$ = $1; } 158 | | func_decl { $$ = $1; } 159 | ; 160 | 161 | func_decl: 162 | T_FUNCTION ident T_LPAR param_list T_RPAR T_COLON type T_LBRACE var_decl_list statement_block T_RBRACE 163 | { 164 | Symbol *symtab; 165 | struct AstNode *ast_node; 166 | 167 | ast_node = ast_node_new("FuncDecl", FUNCTION, VOID, 168 | yylloc.last_line, NULL); 169 | 170 | ast_node_add_child(ast_node, $2); // Identifier 171 | ast_node_add_child(ast_node, $4); // ParamList 172 | ast_node_add_child(ast_node, $9); // VarDeclList 173 | //ast_node_add_child(ast_node, $9); // Statements 174 | 175 | $2->symbol->type = $7; 176 | 177 | ast_node->symbol = symbol_new(NULL); 178 | 179 | $$ = ast_node; 180 | } 181 | ; 182 | 183 | proc_decl: 184 | T_PROC ident T_LPAR param_list T_RPAR T_LBRACE var_decl_list statement_block T_RBRACE 185 | { 186 | Symbol *symtab; 187 | struct AstNode *ast_node; 188 | 189 | ast_node = ast_node_new("ProcDecl", PROCEDURE, VOID, 190 | yylloc.last_line, NULL); 191 | 192 | ast_node_add_child(ast_node, $2); // Identifier 193 | //ast_node_add_child(ast_node, $4); // ParamList 194 | ast_node_add_child(ast_node, $7); // VarDeclList 195 | //ast_node_add_child(ast_node, $9); // Statements 196 | 197 | ast_node->symbol = symbol_new(NULL); 198 | 199 | $$ = ast_node; 200 | } 201 | ; 202 | 203 | program_decl: 204 | T_PROGRAM ident T_SEMICOLON 205 | { 206 | struct AstNode *ast_node; 207 | 208 | ast_node = ast_node_new("ProgramDecl", PROGRAM_DECL, VOID, 209 | yylloc.last_line, NULL); 210 | ast_node_add_child(ast_node, $2); /* identifier */ 211 | $$ = ast_node; 212 | } 213 | ; 214 | 215 | param_list: 216 | /* empty */ { $$ = NULL; } 217 | | single_param multi_param 218 | { 219 | struct AstNode *ast_node; 220 | ast_node = ast_node_new("ParamList", PARAM_LIST, VOID, 221 | yylloc.last_line, NULL); 222 | ast_node_add_sibling($1, $2); 223 | ast_node_add_child(ast_node, $1); 224 | $$ = ast_node; 225 | } 226 | ; 227 | 228 | multi_param: 229 | /* empty */ { $$ = NULL; } 230 | | T_COMMA single_param multi_param 231 | { 232 | ast_node_add_sibling($2, $3); 233 | $$ = $2; 234 | } 235 | ; 236 | 237 | 238 | single_param: 239 | type ident 240 | { 241 | struct AstNode *ast_node; 242 | ast_node = ast_node_new("Parameter", PARAMETER, $1, 243 | yylloc.last_line, NULL); 244 | ast_node_add_child(ast_node, $2); // Identifier 245 | $$ = ast_node; 246 | } 247 | ; 248 | 249 | identlist: 250 | single_identifier multi_identifier 251 | { 252 | struct AstNode *ast_node; 253 | 254 | ast_node = ast_node_new("IdentifierList", IDENT_LIST, VOID, 255 | yylloc.last_line, NULL); 256 | ast_node_add_sibling($1, $2); 257 | ast_node_add_child(ast_node, $1); 258 | $$ = ast_node; 259 | } 260 | ; 261 | 262 | multi_identifier: 263 | /* empty */ { $$ = NULL; } 264 | | T_COMMA single_identifier multi_identifier 265 | { 266 | ast_node_add_sibling($2, $3); 267 | $$ = $2; 268 | } 269 | ; 270 | 271 | single_identifier: 272 | ident { $$ = $1; } 273 | ; 274 | 275 | ident: 276 | IDENTIFIER 277 | { 278 | struct AstNode *ast_node; 279 | 280 | ast_node = ast_node_new("Identifier", IDENTIFIER, VOID, 281 | yylloc.last_line, NULL); 282 | ast_node->symbol = symbol_new($1); 283 | // ast-node->symbol->decl_linenum = yylloc.last_line; 284 | $$ = ast_node; 285 | } 286 | ; 287 | 288 | 289 | statement_block: 290 | statement_block stmt 291 | | 292 | /* empty */ 293 | ; 294 | 295 | type: TYPE_IDENTIFIER 296 | ; 297 | 298 | stmt: 299 | T_SEMICOLON { } 300 | | expr T_SEMICOLON { } 301 | | IDENTIFIER T_ASSIGN expr T_SEMICOLON { } 302 | | T_WHILE T_LPAR expr T_RPAR stmt 303 | { } 304 | | T_DO stmt T_WHILE T_LPAR expr T_RPAR T_SEMICOLON { } 305 | | T_IF T_LPAR expr T_RPAR stmt %prec IFX 306 | { } 307 | | T_IF T_LPAR expr T_RPAR stmt T_ELSE stmt 308 | { } 309 | | T_LBRACE stmt_list T_RBRACE { } 310 | ; 311 | 312 | stmt_list: 313 | stmt { } 314 | | stmt_list stmt { } 315 | ; 316 | 317 | expr: 318 | INT_LITERAL { } 319 | | CHAR_LITERAL { } 320 | | BOOL_LITERAL { } 321 | | IDENTIFIER { } 322 | | T_MINUS expr %prec UMINUS { } 323 | | expr T_PLUS expr { } 324 | | expr T_MINUS expr { } 325 | | expr T_STAR expr { } 326 | | expr T_SLASH expr { } 327 | | expr T_LT expr { } 328 | | expr T_GT expr { } 329 | | expr T_GE expr { } 330 | | expr T_LE expr { } 331 | | expr T_NE expr { } 332 | | expr T_EQ expr { } 333 | | T_LPAR expr T_RPAR { } 334 | ; 335 | %% 336 | 337 | static void yyerror(const char *msg) 338 | { 339 | fprintf(stderr, "Error(%d): %s\n", yyget_lineno(), msg); 340 | } 341 | 342 | int main(int argc, char **argv) 343 | { 344 | if (argc > 1) 345 | yyin = fopen(argv[1], "r"); 346 | else 347 | yyin = stdin; 348 | 349 | /*yylloc.first_line = yylloc.last_line = 1; 350 | yylloc.first_column = yylloc.last_column = 0;*/ 351 | 352 | yyparse(); 353 | 354 | Visitor *visitor; 355 | 356 | visitor = typecheck_new(); 357 | ast_node_accept(ast, visitor); 358 | 359 | if(ast_node_check_errors(ast)) { 360 | fprintf(stderr, "Too many errors to compile.\n"); 361 | } 362 | 363 | visitor = graphprinter_new(); 364 | 365 | ast_node_accept(ast, visitor); 366 | 367 | return 0; 368 | } 369 | -------------------------------------------------------------------------------- /scanner.l: -------------------------------------------------------------------------------- 1 | %{ 2 | #include 3 | #include "base.h" 4 | #include "parser.h" 5 | 6 | #define uploc { yylloc->first_column = yylloc->last_column + 1; yylloc->last_column += yyleng; } 7 | 8 | #define CAST_BOOLEAN(strb) strcasecmp(strb, "False") ? 1 : 0 9 | 10 | %} 11 | 12 | %option yylineno 13 | %option bison-bridge 14 | %option bison-locations 15 | %option noyywrap 16 | %option nounput 17 | %x COMMENT 18 | 19 | %% 20 | 21 | "/*" { uploc; BEGIN(COMMENT); } 22 | 23 | [^*\n]* { uploc; }/* eat anything that's not a '*' */ 24 | "*"+[^*/\n]* { uploc; }/* eat up '*'s not followed by '/'s */ 25 | \n { uploc; } 26 | "*"+"/" BEGIN(INITIAL); 27 | 28 | "program" { uploc; return T_PROGRAM; } 29 | "function" { uploc; return T_FUNCTION; } 30 | "proc" { uploc; return T_PROC; } 31 | "int"|"bool"|"char" { 32 | uploc; 33 | yylval->type = type_get_from_lexeme(yytext); 34 | return TYPE_IDENTIFIER; 35 | } 36 | ">=" { uploc; return T_GE; } 37 | "<=" { uploc; return T_LE; } 38 | "==" { uploc; return T_EQ; } 39 | "!=" { uploc; return T_NE; } 40 | "while" { uploc; return T_WHILE; } 41 | "if" { uploc; return T_IF; } 42 | "else" { uploc; return T_ELSE; } 43 | "do" { uploc; return T_DO; } 44 | "," { uploc; return T_COMMA; } 45 | "=" { uploc; return T_ASSIGN; } 46 | "(" { uploc; return T_LPAR; } 47 | ")" { uploc; return T_RPAR; } 48 | "+" { uploc; return T_PLUS; } 49 | "-" { uploc; return T_MINUS; } 50 | "*" { uploc; return T_STAR; } 51 | "/" { uploc; return T_SLASH; } 52 | "&&" { uploc; return T_LOGICAND; } 53 | "&" { uploc; return T_BITAND; } 54 | "||" { uploc; return T_LOGICOR; } 55 | "|" { uploc; return T_BITOR; } 56 | ">" { uploc; return T_GT; } 57 | "<" { uploc; return T_LT; } 58 | ";" { uploc; return T_SEMICOLON; } 59 | "." { uploc; return T_DOT; } 60 | "{" { uploc; return T_LBRACE; } 61 | "}" { uploc; return T_RBRACE; } 62 | ":" { uploc; return T_COLON; } 63 | "true"|"false" { 64 | uploc; 65 | yylval->boolean=CAST_BOOLEAN(yytext); 66 | return BOOL_LITERAL; 67 | } 68 | "'"."'" { 69 | uploc; 70 | yylval->character=yytext[1]; 71 | return CHAR_LITERAL; 72 | } 73 | [0-9]+ { 74 | uploc; 75 | return INT_LITERAL; 76 | } 77 | [A-Za-z][A-Za-z0-9_]* { 78 | uploc; 79 | yylval->lexeme=strdup(yytext); 80 | return IDENTIFIER; 81 | } 82 | [ \t]+ ; /* ignore whitespace */ 83 | [\n] { 84 | yylloc->first_line = yylloc->last_line = yylineno; 85 | yylloc->first_column = 1; 86 | yylloc->last_column = 0; 87 | } 88 | . { 89 | uploc; 90 | fprintf (stderr, "Syntax Error: unexpected character '%s' at line %d\n", yytext, yylloc->first_line); 91 | } 92 | %% 93 | 94 | -------------------------------------------------------------------------------- /symbol_table.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include "symbol_table.h" 5 | 6 | Symbol * 7 | symbol_new(char const * name) 8 | { 9 | Symbol * symbol = (Symbol *) malloc (sizeof(Symbol)); 10 | symbol->type = VOID; 11 | value_set(&symbol->value, symbol->type, NULL); 12 | symbol->params = -1; 13 | symbol->param_types = NULL; 14 | symbol->decl_linenum = 0; 15 | symbol->is_global = FALSE; 16 | symbol->stack_index = -1; 17 | 18 | symbol->next = NULL; 19 | 20 | if (name != NULL) 21 | symbol->name = strdup(name); 22 | else 23 | symbol->name = NULL; 24 | 25 | return symbol; 26 | } 27 | 28 | /* Insere um simbolo na tabela indicada. 29 | * Caso o simbolo ja exista, a memoria do 30 | * simbolo do parametro sera liberada. 31 | * Returns: O simbolo passado como parametro, 32 | * caso este ainda nao esteja na tabela, 33 | * ou um ponteiro para o simbolo encontrado. 34 | */ 35 | Symbol * 36 | symbol_insert(Symbol *symtab, Symbol *symbol) 37 | { 38 | Symbol *sym; 39 | 40 | if (symbol == NULL) 41 | return NULL; 42 | 43 | sym = symbol_lookup(symtab, symbol->name); 44 | 45 | if (sym != NULL) { 46 | free(symbol->name); 47 | free(symbol); 48 | return sym; 49 | } 50 | 51 | symbol->next = symtab->next; 52 | symtab->next = symbol; 53 | 54 | return symbol; 55 | } 56 | 57 | Symbol * 58 | symbol_lookup(Symbol *symtab, char const *name) 59 | { 60 | Symbol *temp; 61 | 62 | if (symtab == NULL) 63 | return NULL; 64 | 65 | for (temp = symtab->next; temp != NULL; temp = temp->next) { 66 | if (!strcmp (temp->name, name)) 67 | return temp; 68 | } 69 | 70 | return temp; 71 | } 72 | 73 | void 74 | symbol_table_destroy(Symbol *symtab) 75 | { 76 | Symbol *first; 77 | Symbol *to_kill; 78 | first = symtab->next; 79 | symtab->next = NULL; 80 | 81 | while (first != NULL) { 82 | to_kill = first; 83 | first = first->next; 84 | if (to_kill->name != NULL) 85 | free(to_kill->name); 86 | free(to_kill); 87 | } 88 | } 89 | 90 | void 91 | symbol_create_params(Symbol *symbol, int quantity) 92 | { 93 | symbol->params = quantity; 94 | if (quantity > 0) 95 | symbol->param_types = (int *) malloc (sizeof(int) * quantity); 96 | } 97 | 98 | bool 99 | symbol_is_procfunc(Symbol *symbol) 100 | { 101 | return (symbol->params > -1); 102 | } 103 | 104 | void 105 | symbol_print(Symbol *symbol) 106 | { 107 | if (symbol == NULL) { 108 | printf("NULL\n\n"); 109 | return; 110 | } 111 | 112 | printf("Symbol: %x\n", (unsigned)symbol); 113 | printf("name: %s\n", symbol->name); 114 | printf("type: %d\n", symbol->type); 115 | printf("value:"); 116 | value_print(stdout, &symbol->value, symbol->type); 117 | printf("\ndeclaration line: %d\n", symbol->decl_linenum); 118 | printf("next: %x\n\n", (unsigned)symbol->next); 119 | } 120 | 121 | void 122 | symbol_table_dump(Symbol *symtab) 123 | { 124 | Symbol *temp = symtab; 125 | 126 | for (temp = symtab->next; temp != NULL; temp = temp->next) 127 | symbol_print(temp); 128 | } 129 | -------------------------------------------------------------------------------- /symbol_table.h: -------------------------------------------------------------------------------- 1 | #ifndef SYMBOL_TABLE_H 2 | #define SYMBOL_TABLE_H 3 | 4 | #include "base.h" 5 | 6 | typedef struct _symbol { 7 | char *name; 8 | Type type; 9 | Value value; 10 | int decl_linenum; 11 | 12 | // For procedures and functions 13 | int params; 14 | Type *param_types; 15 | 16 | bool is_global; 17 | int stack_index; 18 | struct _symbol *next; 19 | } Symbol; 20 | 21 | static Symbol *global_symbol_table; 22 | 23 | Symbol *symbol_new(char const * name); 24 | Symbol *symbol_lookup(Symbol *symtab, char const *name); 25 | Symbol *symbol_insert(Symbol *symtab, Symbol *symbol); 26 | 27 | void symbol_create_params(Symbol *symbol, int quantity); 28 | bool symbol_is_procfunc(Symbol *symbol); 29 | void symbol_print(Symbol *symbol); 30 | 31 | void symbol_table_destroy(Symbol *table); 32 | void symbol_table_dump(Symbol *table); 33 | 34 | #endif // SYMBOL_TABLE_H 35 | -------------------------------------------------------------------------------- /test.prog: -------------------------------------------------------------------------------- 1 | program testme; 2 | 3 | int motor_speed, last_command_time, current_time; 4 | bool motor_running; 5 | 6 | proc start_motor(int motor_index) 7 | { 8 | int signal_port, motor_index_port; 9 | 10 | signal_port = 23; 11 | motor_index_port = motor_index; 12 | } 13 | 14 | 15 | if( motor_index < 0 ) 16 | { 17 | motor_index = 0; 18 | } 19 | 20 | motor_running = true; 21 | 22 | -------------------------------------------------------------------------------- /typecheck_visitor.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "typecheck_visitor.h" 4 | 5 | static struct AstNode *_inside_procfunc = NULL; 6 | static void _typecheck_print_stmt(struct AstNode *node, Type type, const char *ptype_str); 7 | static Symbol *_complete_symbol_lookup(Symbol *sym); 8 | 9 | Visitor * 10 | typecheck_new() 11 | { 12 | Visitor *visitor = (Visitor *) malloc (sizeof(Visitor)); 13 | 14 | visitor->visit_program = &typecheck_visit_program; 15 | visitor->visit_programdecl = &typecheck_visit_programdecl; 16 | visitor->visit_vardecl_list = &typecheck_visit_vardecl_list; 17 | visitor->visit_vardecl = &typecheck_visit_vardecl; 18 | visitor->visit_procfunc_list = &typecheck_visit_procfunc_list; 19 | visitor->visit_procedure = &typecheck_visit_procfunc; 20 | visitor->visit_function = &typecheck_visit_procfunc; 21 | visitor->visit_param_list = &typecheck_visit_param_list; 22 | visitor->visit_parameter = &typecheck_visit_parameter; 23 | visitor->visit_statement_list = &typecheck_visit_statement_list; 24 | visitor->visit_printint_stmt = &typecheck_visit_printint_stmt; 25 | visitor->visit_printchar_stmt = &typecheck_visit_printchar_stmt; 26 | visitor->visit_printbool_stmt = &typecheck_visit_printbool_stmt; 27 | visitor->visit_printline_stmt = NULL; 28 | visitor->visit_assignment_stmt = &typecheck_visit_assignment_stmt; 29 | visitor->visit_if_stmt = &typecheck_visit_if_stmt; 30 | visitor->visit_while_stmt = &typecheck_visit_while_stmt; 31 | visitor->visit_for_stmt = &typecheck_visit_for_stmt; 32 | visitor->visit_rel_expr = &typecheck_visit_binary_expr; 33 | visitor->visit_add_expr = &typecheck_visit_binary_expr; 34 | visitor->visit_mul_expr = &typecheck_visit_binary_expr; 35 | visitor->visit_notfactor = &typecheck_visit_notfactor; 36 | visitor->visit_call = &typecheck_visit_call; 37 | visitor->visit_callparam_list = &typecheck_visit_callparam_list; 38 | visitor->visit_callparam = &typecheck_visit_callparam; 39 | visitor->visit_identifier_list = &typecheck_visit_identifier_list; 40 | visitor->visit_identifier = &typecheck_visit_identifier; 41 | visitor->visit_literal = NULL; 42 | visitor->visit_add_op = NULL; 43 | visitor->visit_mul_op = NULL; 44 | visitor->visit_rel_op = NULL; 45 | visitor->visit_not_op = NULL; 46 | 47 | return visitor; 48 | } 49 | 50 | void 51 | typecheck_visit_program(struct _Visitor *visitor, struct AstNode *node) 52 | { 53 | node->symbol = symbol_new(NULL); 54 | global_symtab = node->symbol; 55 | symtab = global_symtab; 56 | _inside_procfunc = NULL; 57 | ast_node_accept_children(node->children, visitor); 58 | } 59 | 60 | void 61 | typecheck_visit_programdecl (struct _Visitor *visitor, struct AstNode *node) 62 | { 63 | node->children->symbol->decl_linenum = node->linenum; 64 | 65 | //struct AstNode *child; 66 | //for (child = node->children; child != NULL; child = child->sibling) { 67 | // ast_node_accept(child, visitor); 68 | 69 | ast_node_accept(node->children, visitor); 70 | } 71 | 72 | void 73 | typecheck_visit_procfunc_list (struct _Visitor *visitor, struct AstNode *node) 74 | { 75 | symtab = global_symtab; 76 | 77 | ast_node_accept_children(node->children, visitor); 78 | 79 | symtab = global_symtab; 80 | _inside_procfunc = NULL; 81 | } 82 | 83 | void 84 | typecheck_visit_vardecl_list (struct _Visitor *visitor, struct AstNode *node) 85 | { 86 | struct AstNode *child; 87 | 88 | for (child = node->children; child != NULL; child = child->sibling) 89 | ast_node_accept(child, visitor); 90 | } 91 | 92 | void 93 | typecheck_visit_vardecl (struct _Visitor *visitor, struct AstNode *node) 94 | { 95 | node->children->type = node->type; 96 | ast_node_accept(node->children, visitor); 97 | } 98 | 99 | void 100 | typecheck_visit_procfunc (struct _Visitor *visitor, struct AstNode *node) 101 | { 102 | struct AstNode *ident; 103 | struct AstNode *child; 104 | 105 | _inside_procfunc = node; 106 | 107 | // Identifier 108 | symtab = global_symtab; 109 | ident = node->children; 110 | ident->type = node->type; 111 | 112 | // params > -1 == identificador eh funcao 113 | ident->symbol->params = 0; 114 | 115 | ident->symbol->decl_linenum = node->linenum; 116 | 117 | ast_node_accept(ident, visitor); 118 | 119 | // ParamList, VarDeclList, Statements 120 | symtab = node->symbol; 121 | for (child = ident->sibling; child != NULL; child = child->sibling) { 122 | if (child->kind == PARAM_LIST) 123 | child->symbol = ident->symbol; 124 | ast_node_accept(child, visitor); 125 | } 126 | } 127 | 128 | void 129 | typecheck_visit_param_list(struct _Visitor *visitor, struct AstNode *node) 130 | { 131 | fprintf(stderr, "About to visit param_list\n"); 132 | fprintf(stderr, "node: %x, node->symbol: %x\n", (unsigned)node, (unsigned)node->symbol); 133 | 134 | int i; 135 | struct AstNode *child; 136 | 137 | node->child_counter = 0; 138 | for (child = node->children; child != NULL; child = child->sibling) { 139 | ast_node_accept(child, visitor); 140 | node->child_counter++; 141 | } 142 | 143 | symbol_create_params(node->symbol, node->child_counter); 144 | 145 | i = 0; 146 | for (child = node->children; child != NULL; child = child->sibling) { 147 | node->symbol->param_types[i] = child->type; 148 | i++; 149 | } 150 | } 151 | 152 | void 153 | typecheck_visit_parameter (struct _Visitor *visitor, struct AstNode *node) 154 | { 155 | node->children->type = node->type; 156 | node->children->symbol->decl_linenum = node->linenum; 157 | ast_node_accept(node->children, visitor); 158 | } 159 | 160 | void 161 | typecheck_visit_statement_list(struct _Visitor *visitor, struct AstNode *node) 162 | { 163 | ast_node_accept_children(node->children, visitor); 164 | } 165 | 166 | void 167 | typecheck_visit_printint_stmt (struct _Visitor *visitor, struct AstNode *node) 168 | { 169 | ast_node_accept(node->children, visitor); 170 | _typecheck_print_stmt(node, INTEGER, "Int"); 171 | } 172 | 173 | void 174 | typecheck_visit_printchar_stmt (struct _Visitor *visitor, struct AstNode *node) 175 | { 176 | ast_node_accept(node->children, visitor); 177 | _typecheck_print_stmt(node, CHAR, "Char"); 178 | } 179 | 180 | void 181 | typecheck_visit_printbool_stmt (struct _Visitor *visitor, struct AstNode *node) 182 | { 183 | ast_node_accept(node->children, visitor); 184 | _typecheck_print_stmt(node, BOOLEAN, "Bool"); 185 | } 186 | 187 | void 188 | typecheck_visit_assignment_stmt (struct _Visitor *visitor, struct AstNode *node) 189 | { 190 | struct AstNode *lnode = node->children; 191 | struct AstNode *rnode = lnode->sibling; 192 | 193 | ast_node_accept(lnode, visitor); 194 | ast_node_accept(rnode, visitor); 195 | 196 | if (symbol_is_procfunc(lnode->symbol) && (_inside_procfunc == NULL || 197 | strcmp(_inside_procfunc->children->symbol->name, 198 | lnode->symbol->name))) { 199 | node->type = ERROR; 200 | fprintf(stderr, 201 | "Error: Symbol '%s' is a function identifier, you cannot " 202 | "assign a value to it from outside the said function. " 203 | "Check line %d.\n", lnode->symbol->name, node->linenum); 204 | 205 | } else if (lnode->type != ERROR && rnode->type != ERROR && 206 | lnode->type != rnode->type) { 207 | node->type = ERROR; 208 | fprintf(stderr, 209 | "Error: Incompatible types on assignment " 210 | "operation in line %d.\n", node->linenum); 211 | } 212 | } 213 | 214 | void 215 | typecheck_visit_if_stmt (struct _Visitor *visitor, struct AstNode *node) 216 | { 217 | struct AstNode *expr = node->children; 218 | struct AstNode *stmt = expr->sibling; 219 | 220 | ast_node_accept(expr, visitor); 221 | ast_node_accept(stmt, visitor); 222 | 223 | if (expr->type != BOOLEAN) { 224 | node->type = ERROR; 225 | fprintf(stderr, 226 | "Error: Condition for if statement must be of Boolean type. " 227 | "Check line %d.\n", node->linenum); 228 | } 229 | } 230 | 231 | void 232 | typecheck_visit_while_stmt (struct _Visitor *visitor, struct AstNode *node) 233 | { 234 | struct AstNode *expr = node->children; 235 | struct AstNode *stmt = expr->sibling; 236 | 237 | ast_node_accept(expr, visitor); 238 | ast_node_accept(stmt, visitor); 239 | 240 | if (expr->type != BOOLEAN) { 241 | node->type = ERROR; 242 | fprintf(stderr, 243 | "Error: Expression in While statement must be of " 244 | "Boolean type. Check line %d.\n", expr->linenum); 245 | } 246 | } 247 | 248 | void 249 | typecheck_visit_for_stmt (struct _Visitor *visitor, struct AstNode *node) 250 | { 251 | struct AstNode *asgn = node->children; 252 | struct AstNode *expr = asgn->sibling; 253 | struct AstNode *stmt = expr->sibling; 254 | struct AstNode *id_node = asgn->children; 255 | 256 | ast_node_accept(asgn, visitor); 257 | ast_node_accept(expr, visitor); 258 | 259 | if (id_node->type != INTEGER) { 260 | node->type = ERROR; 261 | fprintf(stderr, 262 | "Error: Identifier '%s' is of %s type; it must be Integer. " 263 | "Check line %d.\n", id_node->symbol->name, 264 | type_get_lexeme(id_node->type), id_node->linenum); 265 | } 266 | 267 | if (expr->type != INTEGER) { 268 | node->type = ERROR; 269 | fprintf(stderr, 270 | "Error: Value of stop condition is not of Integer type. " 271 | "Check line %d.\n", expr->linenum); 272 | } 273 | 274 | ast_node_accept(stmt, visitor); 275 | 276 | } 277 | 278 | void 279 | typecheck_visit_binary_expr (struct _Visitor *visitor, struct AstNode *node) 280 | { 281 | struct AstNode *lnode = node->children; 282 | struct AstNode *op = lnode->sibling; 283 | struct AstNode *rnode = op->sibling; 284 | 285 | ast_node_accept(lnode, visitor); 286 | ast_node_accept(rnode, visitor); 287 | 288 | if (lnode->type != ERROR && rnode->type != ERROR && 289 | lnode->type != rnode->type) { 290 | node->type = ERROR; 291 | fprintf(stderr, 292 | "Error: Operation '%s' over incompatible types on line %d.\n", 293 | op->name, op->linenum); 294 | } 295 | } 296 | 297 | void 298 | typecheck_visit_notfactor (struct _Visitor *visitor, struct AstNode *node) 299 | { 300 | ast_node_accept(node->children, visitor); 301 | 302 | if (node->children->type != BOOLEAN) { 303 | node->type = ERROR; 304 | fprintf(stderr, 305 | "Error: Operation 'not' over non-boolean " 306 | "operand on line %d.\n", node->linenum); 307 | } 308 | } 309 | 310 | void 311 | typecheck_visit_call (struct _Visitor *visitor, struct AstNode *node) 312 | { 313 | int params; 314 | struct AstNode *ident = node->children; 315 | struct AstNode *plist = ident->sibling; 316 | 317 | ast_node_accept(ident, visitor); 318 | 319 | if (ident->type == ERROR) 320 | return; 321 | 322 | node->type = ident->symbol->type; 323 | 324 | if (plist != NULL) { 325 | // CallParamLists apontam para o simbolo da funcao chamada 326 | // para obter a quantidade e os tipos esperados dos parametros. 327 | plist->symbol = ident->symbol; 328 | 329 | ast_node_accept(plist, visitor); 330 | params = plist->child_counter; 331 | 332 | } else 333 | params = 0; 334 | 335 | if (params != ident->symbol->params) { 336 | node->type = ERROR; 337 | fprintf(stderr, "Error: Expecting %d parameters, received %d. " 338 | "Check line %d\n", 339 | ident->symbol->params, params, node->linenum); 340 | } 341 | } 342 | 343 | void 344 | typecheck_visit_callparam_list (struct _Visitor *visitor, struct AstNode *node) 345 | { 346 | int i; 347 | struct AstNode *child; 348 | 349 | node->child_counter = 0; 350 | for (child = node->children; child != NULL; child = child->sibling) 351 | node->child_counter++; 352 | 353 | if (node->symbol->params != node->child_counter) { 354 | node->type = ERROR; 355 | return; 356 | } 357 | 358 | i = 0; 359 | for (child = node->children; child != NULL; child = child->sibling) { 360 | ast_node_accept(child, visitor); 361 | 362 | if (child->type != ERROR && 363 | child->type != node->symbol->param_types[i]) { 364 | node->type = ERROR; 365 | child->type = node->symbol->param_types[i]; 366 | 367 | fprintf(stderr, "Error: Call '%s' on line %d, expecting %s " 368 | "on parameter %d (", 369 | node->symbol->name, node->linenum, 370 | type_get_lexeme(node->symbol->param_types[i]), 371 | i + 1); 372 | 373 | if (child->children->kind == IDENTIFIER) 374 | fprintf(stderr, "'%s'", child->children->symbol->name); 375 | else 376 | value_print(stderr, &child->value, child->type); 377 | 378 | fprintf(stderr, "), received %s.\n", type_get_lexeme(child->type)); 379 | } 380 | i++; 381 | } 382 | } 383 | 384 | void 385 | typecheck_visit_callparam (struct _Visitor *visitor, struct AstNode *node) 386 | { 387 | ast_node_accept(node->children, visitor); 388 | node->type = node->children->type; 389 | } 390 | 391 | void 392 | typecheck_visit_identifier_list (struct _Visitor *visitor, struct AstNode *node) 393 | { 394 | struct AstNode *child; 395 | 396 | for (child = node->children; child != NULL; child = child->sibling) { 397 | child->type = node->type; 398 | child->symbol->decl_linenum = node->linenum; 399 | ast_node_accept(child, visitor); 400 | } 401 | } 402 | 403 | void 404 | typecheck_visit_identifier (struct _Visitor *visitor, struct AstNode *node) 405 | { 406 | Symbol *sym = symbol_lookup(symtab, node->symbol->name); 407 | Symbol *_sym = sym; 408 | 409 | // O atributo 'decl_linenum' > 0 indica que o identificador referencia 410 | // a declaracao de uma variavel/procedimento/funcao. 411 | 412 | void __fetch_symbol(struct AstNode *node, Symbol *sym) { 413 | symbol_table_destroy(node->symbol); 414 | node->symbol = sym; 415 | node->type = sym->type; 416 | } 417 | 418 | if (sym == NULL) { 419 | 420 | // Simbolo possui linha de declaracao: Insira na tabela de simbolos. 421 | if (node->symbol->decl_linenum > 0) { 422 | node->symbol->type = node->type; 423 | node->symbol->is_global = (symtab == global_symtab); 424 | 425 | node->symbol = symbol_insert(symtab, node->symbol); 426 | 427 | } else if ((sym = symbol_lookup(global_symtab, node->symbol->name)) 428 | != NULL) { 429 | __fetch_symbol(node, sym); 430 | 431 | // Sem linha de declaracao == eh fetch de variavel nao declarada. 432 | } else { 433 | node->symbol->type = node->type = ERROR; 434 | fprintf(stderr, "Error: Undeclared symbol '%s' in line %d\n", 435 | node->symbol->name, node->linenum); 436 | } 437 | 438 | // Simbolo encontrado na tabela e eh fetch: OK. Ou pode ser global. 439 | } else if (node->symbol->decl_linenum == 0) { 440 | __fetch_symbol(node, sym); 441 | 442 | // Simbolo possui linha de declaracao mas foi encontrado na tabela: 443 | // tentativa de redefinicao. 444 | } else { 445 | node->symbol->type = node->type = ERROR; 446 | fprintf(stderr, "Error: Symbol '%s' already defined in line %d. " 447 | "Check line %d.\n", 448 | _sym->name, _sym->decl_linenum, node->linenum); 449 | } 450 | 451 | } 452 | 453 | // Helper functions ---------------------------------------------------------- 454 | 455 | static void 456 | _typecheck_print_stmt(struct AstNode *node, Type type, const char *ptype_str) 457 | { 458 | if (node->children->type != type) { 459 | node->type = ERROR; 460 | fprintf(stderr, 461 | "Error: Expression Print%s statement must be of " 462 | "%s type. Check line %d.\n", 463 | ptype_str, type_get_lexeme(type), node->linenum); 464 | } 465 | } 466 | -------------------------------------------------------------------------------- /typecheck_visitor.h: -------------------------------------------------------------------------------- 1 | #ifndef TYPECHECK_VISITOR_H 2 | #define TYPECHECK_VISITOR_H 3 | 4 | #include "ast.h" 5 | #include "base.h" 6 | #include "symbol_table.h" 7 | 8 | //static bool is_vardecl = FALSE; 9 | static Type declared_type = VOID; 10 | static Symbol *symtab; 11 | static Symbol *global_symtab; 12 | 13 | Visitor *typecheck_new(); 14 | 15 | void typecheck_visit_program (struct _Visitor *, struct AstNode *); 16 | void typecheck_visit_programdecl (struct _Visitor *, struct AstNode *); 17 | void typecheck_visit_procfunc_list (struct _Visitor *, struct AstNode *); 18 | void typecheck_visit_procfunc(struct _Visitor *, struct AstNode *); 19 | void typecheck_visit_vardecl_list (struct _Visitor *, struct AstNode *); 20 | void typecheck_visit_vardecl (struct _Visitor *, struct AstNode *); 21 | void typecheck_visit_param_list(struct _Visitor *, struct AstNode *); 22 | void typecheck_visit_parameter (struct _Visitor *, struct AstNode *); 23 | void typecheck_visit_statement_list(struct _Visitor *, struct AstNode *); 24 | void typecheck_visit_printint_stmt (struct _Visitor *, struct AstNode *); 25 | void typecheck_visit_printchar_stmt (struct _Visitor *, struct AstNode *); 26 | void typecheck_visit_printbool_stmt (struct _Visitor *, struct AstNode *); 27 | void typecheck_visit_printline_stmt (struct _Visitor *, struct AstNode *); 28 | void typecheck_visit_assignment_stmt (struct _Visitor *, struct AstNode *); 29 | void typecheck_visit_if_stmt (struct _Visitor *, struct AstNode *); 30 | void typecheck_visit_while_stmt (struct _Visitor *, struct AstNode *); 31 | void typecheck_visit_for_stmt (struct _Visitor *, struct AstNode *); 32 | void typecheck_visit_binary_expr (struct _Visitor *, struct AstNode *); 33 | void typecheck_visit_notfactor (struct _Visitor *, struct AstNode *); 34 | void typecheck_visit_call (struct _Visitor *, struct AstNode *); 35 | void typecheck_visit_callparam_list (struct _Visitor *, struct AstNode *); 36 | void typecheck_visit_callparam (struct _Visitor *, struct AstNode *); 37 | void typecheck_visit_identifier_list(struct _Visitor *, struct AstNode *); 38 | void typecheck_visit_identifier (struct _Visitor *, struct AstNode *); 39 | 40 | #endif // TYPECHECK_VISITOR_H 41 | --------------------------------------------------------------------------------