diff --git a/Makefile b/Makefile index 8649a5c..4b92e65 100644 --- a/Makefile +++ b/Makefile @@ -7,6 +7,8 @@ YACC := bison TESTS-S1 := $(wildcard tests/sprint1/test/*.alpha) TESTS-S2 := $(wildcard tests/sprint2/test/*.alpha) +TESTS-S3 := $(wildcard tests/sprint3/test/*.alpha) +TESTS-S4 := $(wildcard tests/sprint4/test/*.alpha) compiler: clean runner @@ -32,17 +34,38 @@ runner: tmp/lex.yy.c tmp/runner.o tmp/symbol_table.o debug: CFLAGS += -DDEBUG=1 debug: clean compiler -test: test-s1 test-s2 +test: + chmod +x ./check.sh + chmod +x ./test.sh + $(foreach test, $(TESTS-S1), (./$(EXE) -tok $(test) -debug || true);) + ./test.sh sp2 + ./test.sh sp3 + ./test.sh sp4 + ./check.sh test-s1: chmod +x ./check.sh - $(foreach test, $(TESTS-S1), ./$(EXE) -tok $(test);) - ./check.sh + chmod +x ./test.sh + $(foreach test, $(TESTS-S1), (./$(EXE) -tok $(test) -debug || true);) + ./check.sh sp1 test-s2: chmod +x ./check.sh - $(foreach test, $(TESTS-S2), ./$(EXE) -st $(test);) - ./check.sh + chmod +x ./test.sh + ./test.sh sp2 + ./check.sh sp2 + +test-s3: + chmod +x ./check.sh + chmod +x ./test.sh + ./test.sh sp3 + ./check.sh sp3 + +test-s4: + chmod +x ./check.sh + chmod +x ./test.sh + ./test.sh sp4 + ./check.sh sp4 clean: rm -f *.o @@ -55,4 +78,4 @@ clean: rm -f *.st rm -rf out rm -rf tmp - rm -f parser \ No newline at end of file + rm -f parser diff --git a/check.sh b/check.sh index f325421..bac18ec 100755 --- a/check.sh +++ b/check.sh @@ -5,34 +5,61 @@ # The Translators - Spring 2025 # TOK_DIR="out" +NOCOLOR='\033[0m' RED='\033[0;31m' GREEN='\033[0;32m' -WHITE='\033[0m' -PURPLE='\033[0;35m' ORANGE='\033[0;33m' +BLUE='\033[0;34m' +PURPLE='\033[0;35m' +CYAN='\033[0;36m' +LIGHTGRAY='\033[0;37m' +DARKGRAY='\033[1;30m' +LIGHTRED='\033[1;31m' +LIGHTGREEN='\033[1;32m' +YELLOW='\033[1;33m' +LIGHTBLUE='\033[1;34m' +LIGHTPURPLE='\033[1;35m' +LIGHTCYAN='\033[1;36m' +WHITE='\033[1;37m' + +compare_files() { + local file="$1" + local filename=$(basename -- "$file") + filename="${filename%.*}" + local num=${filename:2:1} + local exp="./tests/sprint$num/expected/$filename.expected" + + if [[ -f "$exp" ]]; then + diff -q "$file" "$exp" > /dev/null + if [[ $? -eq 0 ]]; then + echo -e "${GREEN}[✔] ${PURPLE}$filename ${WHITE}passed.${NOCOLOR}" + else + echo -e "\n${RED}[✘] ${PURPLE}$file ${WHITE}failed with an unexpected value...${NOCOLOR}" + diff --color=always "$file" "$exp" + echo -e "" + fi + else + echo -e "${ORANGE}[-] ${PURPLE}$filename ${WHITE}does not have an expected value.${NOCOLOR}" + fi +} if [[ ! -d "$TOK_DIR" ]]; then - echo "Directory $TOK_DIR does not exist." + echo -e "${RED}[ERROR] ${YELLOW}Directory $TOK_DIR does not exist.${NOCOLOR}" exit 1 fi -echo -e "\n" -for file in "$TOK_DIR"/*; do - filename=$(basename -- "$file") - filename="${filename%.*}" - num=${filename:2:1} - exp="./tests/sprint$num/expected/$filename.expected" - - if [[ -f "$exp" ]]; then - diff -q "$file" "$exp" > /dev/null - if [[ $? -eq 0 ]]; then - echo -e "${GREEN}[✔] ${PURPLE}$filename ${WHITE}passed." - else - echo -e "\n${RED}[✘] ${PURPLE}$file ${WHITE}failed with an unexpected value..." - diff --color=always "$file" "$exp" - echo -e "" - fi - else - echo -e "${ORANGE}[-] ${PURPLE}$filename ${WHITE}does not have an expected value." - fi -done \ No newline at end of file +if [[ $# -eq 0 ]]; then + for file in "$TOK_DIR"/*; do + compare_files "$file" + done +elif [[ $# -eq 1 ]]; then + prefix="$1" + for file in "$TOK_DIR"/"$prefix"*; do + if [[ -f "$file" ]]; then + compare_files "$file" + fi + done +else + echo -e "${LIGHTBLUE}Usage: $0 [sp#]${NOCOLOR}" + exit 1 +fi \ No newline at end of file diff --git a/src/grammar.y b/src/grammar.y index 758b35d..7b925f6 100644 --- a/src/grammar.y +++ b/src/grammar.y @@ -1,40 +1,37 @@ + /* Syntax Analyzer with Bison (3.8.2) */ /* The Translators - Spring 2025 */ +// ----- THIS FILE MUST BE FORMATTED CORRECTLY FOR READABILITY ----- // + +// ✏️ FORMATTING RULES: +// 1️⃣ Use 4 spaces for indentation. +// 2️⃣ Grammar rules (terminals and nonterminals) should always be on their own line. +// 3️⃣ Grammar rules and C-blocks should always begin 8 spaces in. +// 4️⃣ Rule end-markers (;, |) should always be 4 spaces in. +// 5️⃣ C-blocks should always be clearly defined and follow clang formatting rules. +// 6️⃣ 1-line if/for/while statements must be wrapped in curly braces. +// 7️⃣ Comments should always be above rules +// 8️⃣ DO NOT USE TABS. EVER. + +// Please ask Scarlett if you are unsure of how to format something. Thanks! 😀 + %{ - #include - #include "../src/symbol_table.c" - #include - extern int yylex(void); - void yyerror(const char *err); - extern char* yytext; - extern int yyleng; - extern int yychar; - extern SymbolTable * cur; - //char* cur_value; - //char* cur_type; - int token_tracker; - extern int line_number; - extern int column_number; - extern FILE * yyin; - extern TableNode* funprime; - extern TableNode* arrayprim; - extern TableNode* recprime; - extern TableNode* funtypeprime; - extern TableNode* integ; - extern TableNode* addr; - extern TableNode* chara; - extern TableNode* stri; - extern TableNode* boo; + #include "../src/symbol_table.c" + + void yyerror(const char *err); + int token_tracker; + TableNode * tn; %} -//%define api.location.type {location_t} + %locations + %union { - int integ; - char * words; + int integ; + char * words; } - +%type idlist %type assignable %type expression %type constant @@ -46,7 +43,7 @@ %token T_BOOLEAN 203 %token T_CHARACTER 204 %token T_STRING 205 -%token C_INTEGER 301 +%token C_INTEGER 301 %token C_NULL 302 %token C_CHARACTER 303 %token C_STRING 304 @@ -100,164 +97,633 @@ %precedence DOT %precedence RESERVE RELEASE - - %% program: - prototype_or_definition_list - ; + prototype_or_definition_list + ; + + prototype_or_definition_list: - prototype prototype_or_definition_list - | definition prototype_or_definition_list - | prototype - | definition - ; + prototype prototype_or_definition_list + | definition prototype_or_definition_list + | prototype + | definition + ; + + prototype: - L_PAREN EXTERNAL R_PAREN FUNCTION ID COLON ID; + L_PAREN EXTERNAL R_PAREN FUNCTION ID COLON ID; + + definition: - TYPE ID COLON dblock - | TYPE ID COLON constant ARROW ID - | function_declaration - | TYPE ID COLON id_or_types ARROW id_or_types { - CreateEntry(cur,funtypeprime,$2,CreateFunctionTypeInfo(table_lookup(cur,$4),table_lookup(cur,$6))); + TYPE ID COLON + { + printdebug("Currently see a record definition for %s", $2); + tn = CreateEntry(getAncestor(cur), recprime, $2, CreateRecordInfo(0, cur = CreateScope(cur, 0, 0))); + if (table_lookup(getAncestor(cur), $2) == undefined) { + printdebug("rec not found"); + } } - | ID parameter ASSIGN sblock - ; + dblock + { + setRecSize(table_lookup(getParent(cur), $2), getRecSize(cur)); + cur = getParent(cur); + } + + | TYPE ID COLON C_INTEGER ARROW id_or_types + { + printdebug("Currently see a array definition of name %s,storing type %s, of dimensions %d", $2, $6, $4); + CreateEntry(cur, arrayprim, $2, CreateArrayInfo($4, look_up(cur, $6))); + printdebug("%sID: %s, dimensions: %d, typeOfArray: %s", COLOR_GREEN, $2, $4, $6); + } + + | function_declaration + + | TYPE ID COLON id_or_types ARROW id_or_types + { + printdebug("Currently see a function type definition of name %s,parameter type %s, of return type %s", $2, $4, $6); + CreateEntry(cur,funtypeprime,$2,CreateFunctionTypeInfo(table_lookup(cur,$4),table_lookup(cur,$6))); + } + + | ID + { + TableNode *node = table_lookup(getAncestor(cur), $1); + if (node == undefined) { + printdebug("function not declared at line %d, column %d", @1.first_line, @1.first_column); + } else if(getAdInfoType(node) != TYPE_FUNCTION_DECLARATION) { + printdebug("function not declared at line %d, column %d", @1.first_line, @1.first_column); + } else { + setStartLine(node, @1.first_line); + setAsKeyword(node, false); + } + cur = CreateScope(cur, 0, 0); + } + L_PAREN ID + { + printdebug("Currently see a function definition taking only one parameter (no as) of name %s and argument name %s", $1,$4); + CreateEntry(cur, getParameter(table_lookup(getAncestor(cur), getType(table_lookup(getAncestor(cur), $1)))), $4, NULL); + } + R_PAREN ASSIGN sblock + + | ID + { + TableNode *node = table_lookup(getAncestor(cur), $1); + if (node == undefined) { + printdebug("null check"); + } + if (node == undefined) { + printdebug("function not declared at line %d, column %d", @1.first_line, @1.first_column); + } else if (getAdInfoType(node) != TYPE_FUNCTION_DECLARATION) { + printdebug("function not declared at line %d, column %d", @1.first_line, @1.first_column); + } else { + setStartLine(node, @1.first_line); + setAsKeyword(node, true); + } + cur = CreateScope(cur, 0, 0); + } + AS L_PAREN + { + TableNode *parameter = getParameter(table_lookup(getAncestor(cur), getType(table_lookup(getAncestor(cur), $1)))); + printdebug("%s", getType(parameter)); + if (parameter == undefined) { + printdebug("function defined with as, but parameter is undefined at line %d, column %d", @1.first_line, @1.first_column); + } else if(getAdInfoType(parameter) != TYPE_RECORD) { + printdebug("record: %s., primitive: %s.", getType(parameter), getName(recprime)); + printdebug("function defined with as, but parameter is type %s at line %d, column %d", getType(parameter),@1.first_line, @1.first_column); + } else { + for (TableNode* entry = getFirstEntry(getRecList(parameter)); entry!= NULL; entry = getNextEntry(entry)) { + CreateEntry(cur, entry->theType, NULL, NULL); + } + } + } + idlist + { + printdebug("Currently see a function definition taking one paramter (with as) of name %s and number of arguments %d", $1,$6); + } + R_PAREN ASSIGN sblock + ; + + function_declaration: - FUNCTION ID COLON ID - | EXTERNAL FUNCTION ID COLON ID - ; + FUNCTION ID COLON ID + { + CreateEntry(cur, look_up(cur, $4), $2, CreateFunctionDeclarationInfo(-1, false)); + } + + | EXTERNAL FUNCTION ID COLON ID + { + CreateEntry(cur, look_up(cur, $5), $3, NULL); + } + ; + -parameter: - L_PAREN ID R_PAREN - | AS L_PAREN idlist R_PAREN - ; idlist: - ID COMMA idlist - | ID - ; + ID + { + TableNode *entry = getFirstEntry(cur); + while (strcmp(getName(entry),"undefined") != 0) { + entry = getNextEntry(entry); + } + if (getNextEntry(entry) == NULL) { + printdebug("too many parameters at line %d column %d", @1.first_line, @1.first_column); + } + addName(entry, $1); + } + COMMA idlist + { + $$ = $4 + 1; + } + + | ID + { + TableNode *entry = getFirstEntry(cur); + while (strcmp(getName(entry),"undefined") != 0) { + entry = getNextEntry(entry); + } + if (getNextEntry(entry) != NULL) { + printdebug("too many parameters at line %d column %d", @1.first_line, @1.first_column); + } + addName(entry, $1); + $$ = 1; + } + ; + sblock: - L_BRACE {cur = CreateScope(cur,@1.first_line,@1.first_column);} statement_list {cur = getParent(cur);} R_BRACE - | L_BRACE {cur = CreateScope(cur,@1.first_line,@1.first_column);} dblock {printf("seen sblock with dblock\n");} statement_list {cur = getParent(cur);} R_BRACE - ; + L_BRACE + { + if (getLine(cur) != 0) { + cur = CreateScope(cur,@1.first_line,@1.first_column); + } else { + setLineNumber(cur, @1.first_line); + setColumnNumber(cur,@1.first_line); + } + } + statement_list + { + cur = getParent(cur); + } + R_BRACE + + | L_BRACE + { + if (getLine(cur) != 0 && getColumn(cur)) { + cur = CreateScope(cur,@1.first_line,@1.first_column); + } + } + dblock + { + printdebug("seen sblock with dblock"); + } + statement_list + { + cur = getParent(cur); + } + R_BRACE + ; + + dblock: - L_BRACKET declaration_list R_BRACKET; + L_BRACKET + { + if(getLine(cur)==0) { + setLineNumber(cur, @1.first_line); + setColumnNumber(cur,@1.first_line); + } else { + cur = CreateScope(cur,@1.first_line,@1.first_column); + } + } + declaration_list R_BRACKET; + + declaration_list: - declaration SEMI_COLON declaration_list - | declaration - ; + declaration SEMI_COLON declaration_list + | declaration + ; + + declaration: - id_or_types COLON ID {CreateEntry(cur,table_lookup(getAncestor(cur),$1),$3,NULL); } - ; + id_or_types COLON ID + { + printdebug("ID/TYPE: %s, ID: %s", $1, $3) ; + CreateEntry(cur,table_lookup(getAncestor(cur),$1),$3,NULL); + } + ; + + id_or_types: - ID {printf("string of id in id_or_type is %s\n",$1);} {$$ = $1;} - | types {printf("string of type in id_or_type is %s\n",$1);} {$$ = $1;} - ; + ID + { + printdebug("string of id is %s in ID pattern of id_or_type rule.", $1); $$ = $1; + } + + | types + { + printdebug("string of type is %s in types pattern of id_or_type rule.",$1); + $$ = $1; + } + ; + + statement_list: - compound_statement statement_list - | compound_statement - | simple_statement SEMI_COLON statement_list - | simple_statement SEMI_COLON - ; + compound_statement statement_list + | compound_statement + | simple_statement SEMI_COLON statement_list + | simple_statement SEMI_COLON + ; + + compound_statement: - WHILE L_PAREN expression R_PAREN sblock - | IF L_PAREN expression R_PAREN THEN sblock ELSE sblock - | sblock //{printf("seen a compound statement rule\n");} - ; + WHILE L_PAREN expression R_PAREN sblock + | IF L_PAREN expression R_PAREN THEN sblock ELSE sblock + | sblock + ; + + simple_statement: - assignable ASSIGN expression - | RETURN expression - ; + assignable ASSIGN expression + { + if(strcmp($1, $3) == 0) { + printdebug("Passed standard type check; assignable = expression"); + } else if((strcmp(getType(look_up(cur, $1)), "array") == 0) && (strcmp($3, "address") == 0)) { + printdebug("%s[☺] Passed array type check; %s = %s", COLOR_GREEN, $1, $3); + } else if((strcmp(getType(look_up(cur, $1)), "record") == 0) && (strcmp($3, "address") == 0)) { + printdebug("%s[☺] Passed address type check; %s = %s", COLOR_GREEN, $1, $3); + } else if((strcmp(getType(look_up(cur, $1)), "function type primitive") == 0) && (strcmp($3, "address") == 0)) { + printdebug("%s[☺] Passed function type primitive type check; %s = %s", COLOR_GREEN, $1, $3); + // } else if () { -assignable: - ID - | assignable ablock - | assignable rec_op ID - ; + // } else if(strcmp(getType(table_lookup(cur, $1)), getType(table_lookup(cur, $3))) == 0) { + // printdebug("%s[] Passed double lookup type check; %s = %s", COLOR_GREEN, $1, $3); + } else { + printdebug("%s[TYPE ERROR] %sMismatch at %sline %d and column %d%s", COLOR_ORANGE, COLOR_WHITE, COLOR_YELLOW, @2.first_line, @2.first_column, COLOR_WHITE); + printdebug(" - Invalid types %s$1: %s and $3: %s%s", COLOR_YELLOW, $1, $3, COLOR_WHITE); + printdebug(" - %sgetType for address: %s", COLOR_YELLOW, getType(look_up(cur, $1))); + } + } -rec_op : - DOT + | RETURN expression + ; -expression: - constant {printf("constant expression\n");} {$$ = $1;} - | SUB_OR_NEG expression %prec UMINUS {printf("negative expression\n");if(strcmp($2,"integer") != 0) - {printf("cant negate something not an integer at line %d and column %d\n",@2.first_line,@2.first_column); - $$=strdup("undefined");}else{$$=$2;}} - | NOT expression {printf("not expression\n"); if(strcmp($2,"Boolean")==0){$$=$2;}else{$$=strdup("undefined"); - printf("mismatch at line %d and column %d\n",@1.first_line,@1.first_column);}} - | expression ADD expression {printf("add expression\n");} - | expression SUB_OR_NEG expression {printf("subtract expression\n");} - | expression MUL expression {printf("multiply expression\n");} - | expression DIV expression {printf("division expression\n");} - | expression REM expression {printf("remainder expression\n");} - | expression AND expression {printf("and expression\n");} - | expression OR expression {printf("or expression\n");} +rec_op: + DOT - | expression LESS_THAN expression {printf("less than expression\n");if(strcmp($1,$3)==0 && - strcmp($1,"integer")==0){$$=strdup("Boolean");}else{printf("mismatch at line %d and column %d\n",@2.first_line,@2.first_column); - $$=strdup("Boolean");$$=strdup("undefined");}} - | expression EQUAL_TO expression {printf("equals check expression\n"); - if(strcmp($1,$3)==0){$$=strdup("Boolean");}else if((strcmp($1,"array")==0||strcmp($1,"record")==0|| - strcmp($1,"function type primitive")==0) && (strcmp($3,"address")==0)){$$=strdup("Boolean");} - else{printf("mismatch at line %d and column %d\n",@2.first_line,@2.first_column);$$=strdup("undefined");}} - | assignable {printf("assignable expression\n");$$=$1;} - | L_PAREN expression R_PAREN {printf("paren expression\n");$$=$2;} - | memOp assignable {$$ = strdup("address");} - ; ablock: - L_PAREN argument_list R_PAREN - ; + L_PAREN argument_list R_PAREN + { + $$ = $2; + printdebug("ablock is %d", $$); + } + ; + + argument_list: - expression COMMA argument_list - | expression - ; + expression COMMA argument_list + { + CreateEntry(cur, look_up(cur, $1), "", NULL); + $$ = $3 + 1; + printdebug("[ARGUMENT_LIST] argument list is %d", $$); + } + + | expression + { + CreateEntry(cur, look_up(cur, $1), "", NULL); + $$ = 1; printdebug("[ARGUMENT_LIST] argument list is %d", $$); + } + ; + + + +// will ALWAYS be a TYPE +expression: + constant + { + printdebug("constant expression"); + $$ = $1; + } + + | SUB_OR_NEG expression %prec UMINUS + { + printdebug("negative expression"); + if(strcmp($2,"integer") != 0) { + printdebug("cant negate something not an integer at line %d and column %d",@2.first_line,@2.first_column); + $$=strdup("undefined"); + } else { + $$=$2; + } + } + + | NOT expression + { + printdebug("not expression"); + if(strcmp($2,"Boolean")==0) { + $$=$2; + } else { + $$=strdup("undefined"); + printdebug("mismatch at line %d and column %d. Invalid type being negated is %s", @1.first_line,@1.first_column,$2); + } + } + + | expression ADD expression + { + printdebug("add expression"); + if(strcmp($1,$3)==0 && strcmp($1,"integer")==0) { + $$=strdup("integer"); + } else { + printdebug("mismatch at line %d and column %d. Invalid types %s and %s.", @2.first_line,@2.first_column,$1,$3); + $$=strdup("undefined"); + } + } + + | expression SUB_OR_NEG expression + { + printdebug("sub or neg expression"); + if(strcmp($1,$3)==0 &&strcmp($1,"integer")==0) { + $$=strdup("integer"); + } else { + printdebug("mismatch at line %d and column %d. Invalid types %s and %s.", @2.first_line,@2.first_column,$1,$3); + $$=strdup("undefined"); + } + } + + | expression MUL expression + { + printdebug("multiply expression"); + if(strcmp($1,$3)==0 &&strcmp($1,"integer")==0) { + $$=strdup("integer"); + } else{ + printdebug("mismatch at line %d and column %d. Invalid types %s and %s.", @2.first_line,@2.first_column,$1,$3); + $$=strdup("undefined"); + } + } + + | expression DIV expression + { + printdebug("divide expression"); + if(strcmp($1,$3)==0 && strcmp($1,"integer")==0) { + $$=strdup("integer"); + } else { + printdebug("mismatch at line %d and column %d. Invalid types %s and %s.", @2.first_line,@2.first_column,$1,$3); + $$=strdup("undefined"); + } + } + + | expression REM expression + { + printdebug("remainder expression"); + if(strcmp($1,$3)==0 && strcmp($1,"integer")==0) { + $$=strdup("integer"); + } else { + printdebug("mismatch at line %d and column %d. Invalid types %s and %s.", @2.first_line,@2.first_column,$1,$3); + $$=strdup("undefined"); + } + } + + | expression AND expression + { + printdebug("AND expression"); + if(strcmp($1,$3)==0 && strcmp($1,"Boolean")==0) { + $$=strdup("Boolean"); + } else{ + printdebug("mismatch at line %d and column %d. Invalid types %s and %s.", @2.first_line,@2.first_column,$1,$3); + $$=strdup("undefined"); + } + } + + | expression OR expression + { + printdebug("OR"); + if(strcmp($1,$3)==0 && strcmp($1,"Boolean")==0) { + $$=strdup("Boolean"); + } else { + printdebug("mismatch at line %d and column %d. Invalid types %s and %s.", @2.first_line,@2.first_column,$1,$3); + $$=strdup("undefined"); + } + } + + | expression LESS_THAN expression + { + printdebug("less than expression"); + if(strcmp($1,$3)==0 && strcmp($1,"integer")==0) { + $$=strdup("Boolean"); + } else { + printdebug("mismatch at line %d and column %d. Invalid types %s and %s.", @2.first_line,@2.first_column,$1,$3); + $$=strdup("undefined"); + } + } + + | expression EQUAL_TO expression + { + printdebug("equals check expression"); + if(strcmp($1,$3)==0) { + $$=strdup("Boolean"); + } else { + printdebug("mismatch at line %d and column %d. Invalid types %s and %s", @2.first_line,@2.first_column,$1,$3); + $$=strdup("undefined"); + } + } + + | assignable + { + printdebug("assignable expression. current type is %s",$1); + $$=$1; + } + + | L_PAREN expression R_PAREN + { + printdebug("paren expression. current type is %s",$2); + $$=$2; + } + + | memOp assignable + { + $$ = strdup("address"); + } + + ; + + + +// prolly right, check back with me later +// add array case +// include type check for ablock in arrays - ablock is always the int of the elements in array/rec +assignable: + ID + { + $$ = getType(look_up(cur,$1)); + printdebug("[ASSIGNABLE - RULE 1] assignable = type: %s | ID = %s", $$, $1); + } + + | assignable + { + printdebug("%sBeginning rule 2 of assignable.", COLOR_CYAN); + cur = CreateScope(cur, -1,-1); + } + ablock + { + int type = getAdInfoType(look_up(getParent(cur), $1)); + printdebug("%stype is %d", COLOR_PURPLE, type); + + if (type == TYPE_FUNCTION_DECLARATION) { + printdebug("%sEntering function call", COLOR_LIGHTGREEN); + if (getAsKeyword(look_up(getParent(cur), $1))) { + TableNode *param = getParameter(look_up(getParent(cur), $1)); + SymbolTable *recList = getRecList(param); + TableNode *lastCheckedRef = getFirstEntry(recList); + TableNode *lastCheckedAct = getFirstEntry(cur); + while (getNextEntry(lastCheckedRef) != NULL) { + lastCheckedRef = getNextEntry(lastCheckedRef); + } + //this isn't very efficient, but will hopefully work + while (lastCheckedAct != NULL && lastCheckedRef != NULL) { + if (strcmp(getName(lastCheckedAct), getName(lastCheckedRef)) != 0) { + printdebug("expected %s expression in function call but got %s at line %d and column %d",getType(lastCheckedRef), getName(lastCheckedAct), @3.first_line, @3.first_column); + } + lastCheckedAct = getNextEntry(lastCheckedAct); + TableNode *tn = getFirstEntry(recList); + while (getNextEntry(tn) != lastCheckedRef) { + tn = getNextEntry(tn); + } + lastCheckedRef = tn; + } + } else { + char *expected = getName(getParameter(look_up(getParent(cur), $1))); + char *actual = getType(getFirstEntry(cur)); + if (strcmp(expected, actual) != 0) { + printdebug("expected %s expression in function call but got %s at line %d and column %d",expected, actual, @3.first_line, @3.first_column); + } + } + + $$ = getName(getReturn(table_lookup(getAncestor(cur), $1))); + printdebug("[ASSIGNABLE - RULE 2] assignable = type: %s | name_func = %s", $$, $1); + + } else if (type == TYPE_ARRAY_TYPE) { + printdebug("%sEntering array call", COLOR_LIGHTGREEN); + if (getNumArrDim(look_up(getParent(cur), $1)) != $2) { + printdebug("expected %d arguments but had %d at line %d and column %d\n", getNumArrDim(look_up(cur, $1)), $2, @2.first_line, @2.first_column); + } + $$ = getName(getArrType(look_up(getParent(cur), $1))); + printdebug("[ASSIGNABLE - RULE 2] assignable = type: %s | name_func = %s", $$, $1); + } + cur = getParent(cur); + } + + | assignable rec_op ID + { + if(undefined != table_lookup(getRecList(table_lookup(getAncestor(cur), $1)), $3)) { + $$ = getName(table_lookup(getRecList(table_lookup(getAncestor(cur), $1)), $3)); + } + printdebug("[ASSIGNABLE - RULE 3] assignable = type: %s | ID = %s", $$, $1); + } + + ; + memOp: - RESERVE {printf("reserve expression\n");} - | RELEASE {printf("release expression\n");} - ; + RESERVE + { + printdebug("reserve expression"); + } + + | RELEASE + { + printdebug("release expression"); + } + + ; constant: - C_STRING {$$ = $1;} - | C_INTEGER {$$ = $1;} - | C_NULL {$$ = $1;} - | C_CHARACTER {$$ = $1;} - | C_TRUE {$$ = $1;} - | C_FALSE {$$ = $1;} - ; + C_STRING + { + $$ = $1; + printdebug("string of C_STRING in constant is %s",$1); + } + + | C_INTEGER + { + $$ = "integer"; + printdebug("string of C_INTEGER in constant is integer"); + } + + | C_NULL + { + $$ = $1; + printdebug("string of C_NULL in constant is %s",$1); + } + + | C_CHARACTER + { + $$ = $1; + printdebug("string of C_CHARACTER in constant is %s",$1); + } + + | C_TRUE + { + $$ = $1; + printdebug("string of C_TRUE in constant is %s",$1); + } + + | C_FALSE + { + $$ = $1; + printdebug("string of C_FALSE in constant is %s",$1); + } + + ; + + types: - // Commented out T_String below - // T_STRING {printf("string of T_STRING in types is %s\n",$1);} {$$ = $1;} - T_INTEGER {printf("string of T_INTEGER in types is %s\n",$1);} {$$ = $1;} - | T_ADDRESS {printf("string of T_ADDRESS in types is %s\n",$1);} {$$ = $1;} - | T_CHARACTER {printf("string of T_CHARACTER in types is %s\n",$1);} {$$ = $1;} - | T_BOOLEAN {printf("string of T_BOOLEAN in types is %s\n",$1);} {$$ = $1;} - ; + T_INTEGER + { + $$ = $1; + printdebug("string of T_INTEGER in types is %s",$1); + } + + | T_ADDRESS + { + $$ = $1; + printdebug("string of T_ADDRESS in types is %s",$1); + } + + | T_CHARACTER + { + $$ = $1; + printdebug("string of T_CHARACTER in types is %s",$1); + } + + | T_BOOLEAN + { + $$ = $1; + printdebug("string of T_BOOLEAN in types is %s",$1); + } + + ; %% + + void yyerror(const char *err) { - fprintf(stderr, "ERROR: %s at token %s at line number %d,column number %d\n", err,yytext,yylloc.first_line,yylloc.first_column); + fprintf(stderr, "ERROR: %s at token %s at line number %d,column number %d", err,yytext,yylloc.first_line,yylloc.first_column); } diff --git a/src/lexicalStructure.lex b/src/lexicalStructure.lex index 24eaa78..00b5a4d 100644 --- a/src/lexicalStructure.lex +++ b/src/lexicalStructure.lex @@ -4,26 +4,26 @@ %option noyywrap %option header-file="flex.h" %option yylineno -%{ - #include - #include "../tmp/grammar.tab.h" - #include "../src/symbol_table.h" - #ifndef DEBUG - #define DEBUG 0 - #endif - extern SymbolTable * cur; - extern FILE* tok_flag; - extern void incr(int lnum,int cnum, int tok); - extern void print_tok(int tok); - int line_number = 1, column_number = 1; - int yycolumn = 1; - #define YY_USER_ACTION { \ - yylloc.first_line = yylineno; \ - yylloc.last_line = yylineno; \ - yylloc.first_column = yycolumn; \ - yylloc.last_column = yycolumn + yyleng - 1; \ - yycolumn += yyleng; } +%{ + #include "../tmp/grammar.tab.h" + #include "../src/symbol_table.h" + #ifndef DEBUG + #define DEBUG 0 + #endif + extern SymbolTable * cur; + extern FILE* tok_flag; + extern void incr(int lnum,int cnum, int tok); + extern void print_tok(int tok); + + int line_number = 1, column_number = 1; + int yycolumn = 1; + #define YY_USER_ACTION { \ + yylloc.first_line = yylineno; \ + yylloc.last_line = yylineno; \ + yylloc.first_column = yycolumn; \ + yylloc.last_column = yycolumn + yyleng - 1; \ + yycolumn += yyleng; } %} STARCOM [^\*]|\*+[^\)\*]+ @@ -72,7 +72,7 @@ SCHAR \\n|\\t|\\\"|[^\"\n\\] "," {if(DEBUG) {printf( "COMMA: %s (%d)\n", yytext, COMMA);} else {if(tok_flag != NULL){print_tok(COMMA);}incr(line_number,column_number,COMMA);return COMMA;}} "->" {if(DEBUG) {printf( "ARROW: %s (%d)\n", yytext, ARROW);} else {if(tok_flag != NULL){print_tok(ARROW);}incr(line_number,column_number,ARROW);return ARROW;}} -{DIGIT}+ {if(DEBUG) {printf( "C_INTEGER: %s (%d)\n", yytext, C_INTEGER);} else {if(tok_flag != NULL){print_tok(C_INTEGER);}incr(line_number,column_number,C_INTEGER);yylval.words = strdup("integer");return C_INTEGER;}} +{DIGIT}+ {if(DEBUG) {printf( "C_INTEGER: %s (%d)\n", yytext, C_INTEGER);} else {if(tok_flag != NULL){print_tok(C_INTEGER);}incr(line_number,column_number,C_INTEGER);yylval.integ = atoi(yytext)/*words = strdup("integer")*/;return C_INTEGER;}} '{CHAR}' {if(DEBUG) {printf( "C_CHARACTER: %s (%d)\n", yytext, C_CHARACTER);} else {if(tok_flag != NULL){print_tok(C_CHARACTER);}incr(line_number,column_number,C_CHARACTER);yylval.words = strdup("character");return C_CHARACTER;}} \"{SCHAR}*\" {if(DEBUG) {printf( "C_STRING: %s (%d)\n", yytext, C_STRING);} else {if(tok_flag != NULL){print_tok(C_STRING);}incr(line_number,column_number,C_STRING);yylval.words = strdup("string");return C_STRING;}} {COMMENT} {if(DEBUG) {printf( "COMMENT: %s (%d)\n", yytext, COMMENT);} else {if(tok_flag != NULL){print_tok(COMMENT);}incr(line_number,column_number,COMMENT);/*return COMMENT;*/}} diff --git a/src/runner.c b/src/runner.c index 68198f8..578fa22 100644 --- a/src/runner.c +++ b/src/runner.c @@ -2,15 +2,15 @@ /* The Translators - Spring 2025 */ #include "runner.h" -extern TableNode *funprime; -extern TableNode *arrayprim; -extern TableNode *integ; -extern TableNode *addr; -extern TableNode *chara; -extern TableNode *stri; -extern TableNode *boo; int main(int argc, char *argv[]) { + // if last argument is debug then set to true and ignore it for the rest + // of this file + if (argc > 1 && strcmp(argv[argc - 1], "-debug") == 0) { + DEBUG = true; + argc--; + } + if (argc == 1) { fprintf(stderr, INVALID); return -1; @@ -80,10 +80,12 @@ void incr(int lnum, int cnum, int tok) { // column_number += yyleng; // } } + void print_tok(int tok) { fprintf(tok_flag, "%d %d %3d \"%s\"\n", line_number, column_number, tok, yytext); } + int run(FILE *alpha) { int token; top = cur = init(CreateScope(NULL, 1, 1)); @@ -132,7 +134,16 @@ int run(FILE *alpha) { if (st_flag != NULL) { yyparse(); - print_symbol_table(getAncestor(cur), st_flag); + + if (cur == NULL) { + printdebug("%s[FATAL] cur is null", COLOR_LIGHTRED); + } + + if (top == NULL) { + printdebug("%s[FATAL] top is null", COLOR_LIGHTRED); + } + + print_symbol_table(top, st_flag); fclose(st_flag); if (yyin != NULL) { fclose(yyin); @@ -142,7 +153,8 @@ int run(FILE *alpha) { yyparse(); FILE *f = fdopen(1, "w"); - print_symbol_table(getAncestor(cur), f); + + print_symbol_table(top, f); fclose(f); if (yyin != NULL) { @@ -212,13 +224,4 @@ int is_alpha_file(char *alpha, int file_len) { return -1; // not alpha file } return 0; // is alpha file -} - -void enter_scope(int line, int column) { cur = CreateScope(cur, line, column); } -void exit_scope() { - if (cur->Parent_Scope == NULL) { - printf("Can't close top"); - return; - } - cur = cur->Parent_Scope; -} +} \ No newline at end of file diff --git a/src/runner.h b/src/runner.h index d378be5..cc573c5 100644 --- a/src/runner.h +++ b/src/runner.h @@ -25,32 +25,56 @@ #include #include "../tmp/flex.h" -#include "symbol_table.h" -// #include "typedefs.h" #include "../tmp/grammar.tab.h" +#include "symbol_table.h" extern int line_number, column_number; extern char *yytext; extern FILE *yyin; -int arg; +extern bool DEBUG; SymbolTable *top; SymbolTable *cur; -// int main(int argc, char* argv[]); -char *is_tok(int argc, char *argv[]); -// int is_alpha_file(char *file, int file_len); -void enter_scope(int, int); -void exit_scope(void); - FILE *alpha_file; FILE *tok_flag = NULL; FILE *st_flag = NULL; +bool DEBUG = false; int no_flag = 0; +int arg; + +TableNode *funprime; +TableNode *arrayprim; +TableNode *integ; +TableNode *addr; +TableNode *chara; +TableNode *stri; +TableNode *boo; +TableNode *recprime; +TableNode *funtypeprime; +TableNode *undefined; int main(int argc, char *argv[]); +int check_flag(char *arg, char *alpha); +void incr(int lnum, int cnum, int tok); +void print_tok(int tok); +int run(FILE *alpha); +bool is_help(char *input); int new_file(char *arg, char *alpha); int is_alpha_file(char *alpha, int file_len); -bool is_help(char *input); -int run(FILE *alpha); -int check_flag(char *arg, char *alpha); + +char *COLOR_RED = "\033[0;31m"; +char *COLOR_GREEN = "\033[0;32m"; +char *COLOR_ORANGE = "\033[0;33m"; +char *COLOR_BLUE = "\033[0;34m"; +char *COLOR_PURPLE = "\033[0;35m"; +char *COLOR_CYAN = "\033[0;36m"; +char *COLOR_LIGHTGRAY = "\033[0;37m"; +char *COLOR_DARKGRAY = "\033[1;30m"; +char *COLOR_LIGHTRED = "\033[1;31m"; +char *COLOR_LIGHTGREEN = "\033[1;32m"; +char *COLOR_YELLOW = "\033[1;33m"; +char *COLOR_LIGHTBLUE = "\033[1;34m"; +char *COLOR_LIGHTPURPLE = "\033[1;35m"; +char *COLOR_LIGHTCYAN = "\033[1;36m"; +char *COLOR_WHITE = "\033[1;37m"; \ No newline at end of file diff --git a/src/symbol_table.c b/src/symbol_table.c index 56c5577..f749b00 100644 --- a/src/symbol_table.c +++ b/src/symbol_table.c @@ -3,95 +3,18 @@ #include "symbol_table.h" -#include -#include -#include -char *typey = "type"; -char *funy = "function"; -TableNode *funprime; -TableNode *arrayprim; -extern SymbolTable *cur; -TableNode *integ; -TableNode *addr; -TableNode *chara; -TableNode *stri; -TableNode *boo; -TableNode *recprime; -TableNode *funtypeprime; - -typedef enum { - // First 4 below are primitive types that are all encapsulated in - // primitive type - // TYPE_INTEGER, - // TYPE_CHARACTER, - // TYPE_BOOLEAN, - // TYPE_ADDRESS, - // Type String is an array of char enclosed in double quotes per lexer - TYPE_STRING = 1, - // Array can be multidimensional. Information should be stored here - TYPE_ARRAY = 2, - // Record is user defined types - TYPE_RECORD = 3, - // Declaring what type a particular function is without as - TYPE_FUNCTION_DECLARATION = 4, - // Declaring what type a particular function is with as - // TYPE_AS_FUNCTION_DECLARATION, - // Declaring what type a function is (what the parameters and output - // are) - TYPE_FUNCTION_TYPE = 5, - // The Type being pointed to by the first 4 above that only stores the - // size - TYPE_PRIMITIVE = 6, - //likely NULL - TYPE_ALL_ELSE = 7 - -} types; - -/* put in symbol_table.h -typedef struct{ - int size; if(strcmp(getType(tn),getName(integ))==0){ - return +void printdebug_impl(char *file, int line, const char *format, ...) { + if (DEBUG) { + printf("%s<%s> [%d]%s ", COLOR_DARKGRAY, file, line, + COLOR_WHITE); + va_list args; + va_start(args, format); + vprintf(format, args); + va_end(args); + printf("\n"); } -}primitive_info; +} -typedef struct{ - int length; - char* location; -}string_info; - -typedef struct{ - int numofdimensions; - //the above value tells you how long the below array is. For example if num -of dimensions is 5, I can store 1,3,2,5,9 to define > int* sizesofdimensions; - TableNode* typeofarray; -}array_info; - -typedef struct{ - //similar to above we define a record to hold the number of elements and an -array of tablenodes (types) that it contains in the order specified by the user - int numofelements; - TableNode* listoftypes; -}record_info; - -typedef struct{ - int startlinenumber; - bool regularoras; -}function_declaration_info; - -typedef struct{ - TableNode* parameter; - TableNode* returntype; -}function_type_info; - -typedef union { - PrimAdInfo* primitive_info; - ArrayAdInfo* array_info; - RecAdInfo* record_info; - StringAdInfo* string_info; - FunDecAdInfo* func_dec_info; - FunTypeAdInfo* func_type_info; - }AdInfo; -*/ // primitive additional info only stores the size of that type AdInfo *CreatePrimitiveInfo(int size) { @@ -103,26 +26,47 @@ AdInfo *CreatePrimitiveInfo(int size) { // only gets the size of a primitive type int getPrimSize(TableNode *definition) { + if (definition == NULL) { + printdebug( + "passed an NULL entry to getPrimSize function. Invalid."); + return -1; + } + if (definition == undefined) { + printdebug("passed an undefined entry to getPrimSize function. " + "Invalid."); + return -1; + } + if (definition->additionalinfo == NULL) { + printdebug("node has NULL additionalinfo. Invalid."); + return -1; + } if (strcmp(getType(definition), "primitive") != 0) { - printf("not checking the size of a primitive -- invalid op\n"); + printdebug( + "not checking the size of a primitive -- invalid op"); return 0; } return definition->additionalinfo->PrimAdInfo->size; } -// probably don't need the below structure since can create from an array -/*string_info* CreateStringInfo(int length, char* loc){ - string_info* stringy = (string_info*)malloc(sizeof(string_info)); - stringy.length=length; - char* location = loc; - return stringy; -} -*/ - // Only information stored in array info is the number of dimensions and the // type stored in the array per professor, the actual size of the array is // calculated at runtime so bounds checking only needs to be done then -AdInfo *CreateArrayInfo(int dim, /*int* sizes,*/ TableNode *type) { +AdInfo *CreateArrayInfo(int dim, TableNode *type) { + if (type == NULL) { + printdebug("passed a NULL reference to " + "CreateArrayInfo. Invalid."); + return NULL; + } + if (type == undefined) { + printdebug("passed an undefined reference to " + "CreateArrayInfo. Invalid."); + return NULL; + } + if (type == undefined) { + printdebug("passed a undefined type reference to " + "CreateArrayInfo. Invalid."); + return NULL; + } AdInfo *info = (AdInfo *)malloc(sizeof(AdInfo)); info->ArrayAdInfo = (array_info *)malloc(sizeof(array_info)); info->ArrayAdInfo->numofdimensions = dim; @@ -133,8 +77,18 @@ AdInfo *CreateArrayInfo(int dim, /*int* sizes,*/ TableNode *type) { } // This gets the number of dimensions from array info int getNumArrDim(TableNode *definition) { + if (definition == NULL) { + printdebug("passed an NULL entry to getNumArrDim " + "function. Invalid."); + return -1; + } + if (definition == undefined) { + printdebug("passed an undefined entry to getNumArrDim " + "function. Invalid."); + return -1; + } if (strcmp(getType(definition), "array") != 0) { - printf("not checking the dim of an array -- invalid op\n"); + printdebug("not checking the dim of an array -- invalid op"); return 0; } return definition->additionalinfo->ArrayAdInfo->numofdimensions; @@ -142,10 +96,20 @@ int getNumArrDim(TableNode *definition) { // This gets the type stored in an array from arrtype. It returns a reference to // the entry of that type TableNode *getArrType(TableNode *definition) { - if (strcmp(getType(definition), "array") != 0) { - printf("not checking the type of an array -- invalid op\n"); + if (definition == NULL) { + printdebug("passed an NULL entry to getArrType " + "function. Invalid."); return NULL; } + if (definition == undefined) { + printdebug("passed an undefined entry to getArrType " + "function. Invalid."); + return NULL; + } + if (strcmp(getType(definition), "array") != 0) { + printdebug("not checking the type of an array -- invalid op"); + return undefined; + } return definition->additionalinfo->ArrayAdInfo->typeofarray; } @@ -165,24 +129,77 @@ AdInfo *CreateRecordInfo(int length, SymbolTable *recordScope) { // Perhaps this may not be needed since we need to iterate over all elements // anyways. int getRecLength(TableNode *definition) { + if (definition == NULL) { + printdebug("passed an NULL entry to getRecLength " + "function. Invalid."); + return -1; + } + if (definition == undefined) { + printdebug("passed an undefined entry to getRecLength " + "function. Invalid."); + return -1; + } if (strcmp(getType(definition), "record") != 0) { - printf("not checking the length of an record -- invalid op\n"); + printdebug( + "not checking the length of an record -- invalid op"); return 0; } return definition->additionalinfo->RecAdInfo->numofelements; } // This gets the array. Needs to up be updated to get the scope instead SymbolTable *getRecList(TableNode *definition) { + if (definition == NULL) { + printdebug("passed a NULL entry to getRecList " + "function. Invalid."); + return NULL; + } + if (definition == undefined) { + printdebug("passed an undefined entry to getRecList " + "function. Invalid."); + return NULL; + } if (strcmp(getType(definition), "record") != 0) { - printf("not checking the list of types of a record -- invalid " - "op\n"); + printdebug( + "not checking the list of types of a record -- invalid " + "op"); return NULL; } return definition->additionalinfo->RecAdInfo->recordScope; } +TableNode *setRecSize(TableNode *tn, int n) { + if (tn == NULL) { + printdebug("passed in NULL entry for setRecSize. Invalid"); + return undefined; + } + if (tn == undefined) { + printdebug("passed in undefined entry for setRecSize. Invalid"); + return undefined; + } + tn->additionalinfo->RecAdInfo->numofelements = n; + return tn; +} + +int getRecSize(SymbolTable *tn) { + if (tn == NULL) { + printdebug( + "passed in NULL SymbolTable for getRecSize. Invalid"); + return -1; + } + int s = 1; + TableNode *cur = getFirstEntry(tn); + if (cur != NULL) { + while (getNextEntry(cur) != NULL) { + s++; + cur = getNextEntry(cur); + } + return s; + } + return -1; +} + // below function takes a bool to see if parameter should be decomposed or not -// note that functions only take one input and have one output +; // note that functions only take one input and have one output // using "as" the input record can be decomposed to give the illusion of // multiple inputs Below function also has the line number where the function is // first defined @@ -197,25 +214,98 @@ AdInfo *CreateFunctionDeclarationInfo(int line, bool asorregular) { // gets the line at which the function was first defined. (Can be used to print // out in table if needed) int getStartLine(TableNode *definition) { - if (strcmp(getType(definition), "function primitive") != 0) { - printf("not checking the start line of a function -- invalid " - "op\n"); + if (definition == NULL) { + printdebug("passed a NULL entry to getStartLine " + "function. Invalid."); + return -1; + } + if (definition == undefined) { + printdebug("passed an undefined entry to getStartLine " + "function. Invalid."); + return -1; + } + if (strcmp(getType(definition), "primitive function") != 0) { + printdebug( + "not checking the start line of a function -- invalid " + "op"); return 0; } return definition->additionalinfo->FunDecAdInfo->startlinenumber; } + +TableNode *setStartLine(TableNode *tn, int start) { + if (tn == NULL) { + printdebug("passing in a NULL entry to setStartLine. " + "invalid"); + return undefined; + } + if (tn == undefined) { + printdebug("passing in an undefined entry to setStartLine. " + "invalid"); + return undefined; + } + tn->additionalinfo->FunDecAdInfo->startlinenumber = start; + return tn; +} // checks if "as" keyword was used for function definition. Either 0 or 1 for // not used or used. bool getAsKeyword(TableNode *definition) { - if (strcmp(getType(definition), "function primitive") != 0) { - printf("not checking if a function is called with as or not -- " - "invalid op\n"); - return NULL; + if (definition == NULL) { + printdebug("passed a NULL entry to getAsKeyword " + "function. Invalid."); + return false; + } + if (definition == undefined) { + printdebug("passed an undefined entry to getAsKeyword " + "function. Invalid."); + return false; + } + if (strcmp(getType(definition), "primitive function") != 0) { + printdebug( + "not checking if a function is called with as or not -- " + "invalid op"); + return 0; } return definition->additionalinfo->FunDecAdInfo->regularoras; } + +TableNode *setAsKeyword(TableNode *tn, bool as) { + if (tn == NULL) { + printdebug("passing in a NULL entry to setAsKeyword. " + "invalid"); + return undefined; + } + if (tn == undefined) { + printdebug("passing in an undefined entry to setAsKeyword. " + "invalid"); + return undefined; + } + tn->additionalinfo->FunDecAdInfo->regularoras = as; + return tn; +} + // stores the type of a function (parameter type and return type) AdInfo *CreateFunctionTypeInfo(TableNode *parameter, TableNode *returntype) { + if (parameter == NULL) { + printdebug("passed a NULL parameter to " + "CreateFunctionTypeInfo. Invalid."); + return NULL; + } + if (parameter == undefined) { + printdebug("passed an undefined parameter to " + "CreateFunctionTypeInfo. Invalid."); + return NULL; + } + if (returntype == NULL) { + printdebug("passed a NULL return type to " + "CreateFunctionTypeInfo. Invalid."); + return NULL; + } + if (returntype == undefined) { + printdebug("passed an undefined return type to " + "CreateFunctionTypeInfo. Invalid."); + return NULL; + } AdInfo *info = (AdInfo *)malloc(sizeof(AdInfo)); info->FunTypeAdInfo = (function_type_info *)malloc(sizeof(function_type_info)); @@ -225,19 +315,40 @@ AdInfo *CreateFunctionTypeInfo(TableNode *parameter, TableNode *returntype) { } // returns parameter type of a function TableNode *getParameter(TableNode *definition) { - if (strcmp(getType(definition), "function type primitive") != 0) { - printf( - "not checking the parameter of a function -- invalid op\n"); - return NULL; + if (definition == NULL) { + printdebug("passed a NULL entry to getParameter " + "function. Invalid."); + return undefined; + } + if (definition == undefined) { + printdebug("passed an undefined entry to getParameter " + "function. Invalid."); + return undefined; + } + if (strcmp(getType(definition), "primitive function type") != 0) { + printdebug( + "not checking the parameter of a function -- invalid op"); + return undefined; } return definition->additionalinfo->FunTypeAdInfo->parameter; } // returns return type of a function TableNode *getReturn(TableNode *definition) { - if (strcmp(getType(definition), "function type primitive") != 0) { - printf("not checking the return of a function -- invalid op\n"); + if (definition == NULL) { + printdebug("passed a NULL entry to getReturn " + "function. Invalid."); return NULL; } + if (definition == undefined) { + printdebug("passed an undefined entry to getReturn " + "function. Invalid."); + return NULL; + } + if (strcmp(getType(definition), "primitive function type") != 0) { + printdebug( + "not checking the return of a function -- invalid op"); + return undefined; + } return definition->additionalinfo->FunTypeAdInfo->returntype; } @@ -275,15 +386,16 @@ SymbolTable *CreateScope(SymbolTable *ParentScope, int Line, int Column) { // types SymbolTable *init(SymbolTable *start) { if (start->Parent_Scope != NULL) { - printf( - "Cannot initialize a scope that is not the parent scope\n"); + printdebug("%s[FATAL] Cannot initialize a scope that is not " + "the parent scope", + COLOR_RED); return NULL; } - integ = (TableNode *)malloc(sizeof(TableNode)); - addr = (TableNode *)malloc(sizeof(TableNode)); - chara = (TableNode *)malloc(sizeof(TableNode)); - stri = (TableNode *)malloc(sizeof(TableNode)); - boo = (TableNode *)malloc(sizeof(TableNode)); + integ = (TableNode *)calloc(1, sizeof(TableNode)); + addr = (TableNode *)calloc(1, sizeof(TableNode)); + chara = (TableNode *)calloc(1, sizeof(TableNode)); + stri = (TableNode *)calloc(1, sizeof(TableNode)); + boo = (TableNode *)calloc(1, sizeof(TableNode)); // TableNode* arr = (TableNode*)malloc(sizeof(SymbolTable)); start->entries = integ; integ->next = addr; @@ -344,6 +456,15 @@ SymbolTable *init(SymbolTable *start) { funtypeprime->additionalinfo = NULL; funtypeprime->next = NULL; + undefined = (TableNode *)malloc(sizeof(TableNode)); + undefined->theName = "undefined"; + undefined->theType = NULL; + undefined->additionalinfo = NULL; + undefined->next = NULL; + + // Undefined_function_type_info = CreateFunctionTypeInfo(undefined, + // undefined); + integ->theType = prime; addr->theType = prime; chara->theType = prime; @@ -379,59 +500,102 @@ TableNode* boo; TableNode* recprime; TableNode* funtypeprime; */ -TableNode* populateTypeAndInfo(TableNode* tn, TableNode* type, AdInfo* info){ - if(tn == NULL){ - printf("passed in an invalid table node to modify (NULL).\n"); - return NULL; - } - if(type == NULL){ - printf("passed in a NULL type reference to populate a table node. Invalid.\n"); - return NULL; - } - if(info == NULL){ - printf("passed in a NULL info reference to populate a table node. Invalid.\n"); - return NULL; - } - tn->theType = type; - tn->additionalinfo = info; - //returning reference to modified table node - return tn; - } +TableNode *populateTypeAndInfo(TableNode *tn, TableNode *type, AdInfo *info) { + if (tn == NULL) { + printdebug( + "passed in an NULL table node to populateTypeAndInfo."); + return undefined; + } + if (tn == undefined) { + printdebug( + "passed in an undefined table node to populateTypeAndInfo"); + return undefined; + } + if (type == NULL) { + printdebug("passed in a NULL type reference to " + "populate a table node. Invalid."); + return undefined; + } + if (type == undefined) { + printdebug("passed in an undefined type reference to " + "populate a table node. Invalid."); + return undefined; + } + if (info == NULL) { + printdebug( + "passed in a NULL info reference to populate a table " + "node. Invalid."); + return undefined; + } + tn->theType = type; + tn->additionalinfo = info; + // returning reference to modified table node + return tn; +} -int getAdInfoType(TableNode* tn){ - if(tn == NULL){ - printf("passing in NULL table entry. Invalid\n"); - return -1; - } - if(tn->theType == NULL){ - printf("Entry being passed in has a null reference for theType. Invalid.\n"); - return -1; - } - if(strcmp(getType(tn),getName(integ))==0){ - return TYPE_PRIMITIVE; - } - if(strcmp(getType(tn),getName(addr))==0){ +int getAdInfoType(TableNode *tn) { + if (tn == NULL) { + printdebug( + "passing in NULL table entry to getAdInfoType. Invalid"); + return -1; + } + if (tn == undefined) { + printdebug("passing in undefined table entry to getAdInfoType. " + "Invalid"); + return -1; + } + if (tn->theType == NULL) { + printdebug("Entry being passed in has a null" + "reference for theType to getAdInfoType. Invalid."); + return -1; + } + if (tn->theType == undefined) { + printdebug("Entry being passed in an undefined " + "reference for theType to getAdInfoType. Invalid."); + return -1; + } + if (strcmp(getName(tn), getName(integ)) == 0) { return TYPE_PRIMITIVE; } - if(strcmp(getType(tn),getName(chara))==0){ + if (strcmp(getName(tn), getName(addr)) == 0) { return TYPE_PRIMITIVE; } - if(strcmp(getType(tn),getName(stri))==0){ - return TYPE_ARRAY; - } - if(strcmp(getType(tn),getName(boo))==0){ + if (strcmp(getName(tn), getName(chara)) == 0) { return TYPE_PRIMITIVE; } - if(strcmp(getType(tn),getName(recprime))==0){ - return TYPE_RECORD; + if (strcmp(getName(tn), getName(stri)) == 0) { + return TYPE_ARRAY_TYPE; } - if(strcmp(getType(tn),getName(funtypeprime))==0){ + if (strcmp(getName(tn), getName(boo)) == 0) { + return TYPE_PRIMITIVE; + } + if (strcmp(getName(tn), getName(recprime)) == 0) { + return TYPE_RECORD_TYPE; + } + if (strcmp(getName(tn), getName(funtypeprime)) == 0) { return TYPE_FUNCTION_TYPE; } - if(strcmp(getType(tn),getName(arrayprim))==0){ - return TYPE_ARRAY; + if (strcmp(getName(tn), getName(arrayprim)) == 0) { + return TYPE_ARRAY_TYPE; // changed from TYPE_ARRAY cuz } - else{ + if (strcmp(getName(tn), getName(undefined)) == 0) { + return TYPE_UNDEFINED; + } else { + if (strcmp(getType(tn), getName(funtypeprime)) == 0) { + printdebug("passed in a function to getAdInfoType"); + return TYPE_FUNCTION_DECLARATION; + } + if (strcmp(getType(tn), getName(arrayprim)) == 0) { + printdebug("passed in an array to getAdInfoType"); + return TYPE_ARRAY_TYPE; + } + if (strcmp(getType(tn), getName(recprime)) == 0) { + printdebug("passed in a record to getAdInfoType"); + return TYPE_RECORD; + } + printdebug( + "passed in an entry that is not a primitive type, array, " + "or record. Invalid."); return TYPE_FUNCTION_DECLARATION; } } @@ -440,184 +604,360 @@ TableNode *CreateEntry(SymbolTable *table, TableNode *typeOf, char *id, AdInfo *ad) { if (table == NULL) { - printf("Null reference to table"); - return NULL; + printdebug("Null reference to table"); + return undefined; } + /* TableNode* topDef = (table_lookup(getAncestor(table),typeOf)); if(topDef == NULL){ - printf("This type is not defined at the top level\n"); + printdebug("This type is not defined at the top level"); return NULL; } */ if (typeOf == NULL) { - printf("This is not pointing to a proper definition\n"); - return NULL; + printdebug("Passing an NULL Type Node to Create Entry"); + return undefined; } - TableNode *newEntry = (TableNode *)malloc(sizeof(TableNode)); + if (typeOf == undefined) { + printdebug("Passing an undefined Type Node to Create Entry"); + return undefined; + } + + TableNode *newEntry = (TableNode *)calloc(1, sizeof(TableNode)); newEntry->theType = typeOf /*topDef*/; newEntry->theName = id; newEntry->additionalinfo = ad; if (table->entries == NULL) { table->entries = newEntry; + printdebug("[CreateEntry] Adding %s to the symbol table", id); return newEntry; } else { TableNode *oldEntry = table->entries; table->entries = newEntry; newEntry->next = oldEntry; + printdebug("[CreateEntry] Adding %s to the symbol table", id); return newEntry; } } char *getType(TableNode *tn) { - if(tn == NULL){ - printf("passed a NULL table entry to getType\n"); - return ""; - } - if(tn->theType == NULL){ - printf("type of entry is currently NULL, undefined type \n"); - return ""; - } - return tn->theType->theName; } -char *getName(TableNode *tn) { return tn->theName; } -int getLine(SymbolTable *st) { return st->Line_Number; } -int getColumn(SymbolTable *st) { return st->Column_Number; } -TableNode* addName(TableNode *tn, char* str){ - if(tn == NULL){ - printf("passed a Null table node to the addName function. Invalid./n"); - return tn; - } -} - -SymbolTable* setLineNumber(SymbolTable *st,int line){ - if(st == NULL){ - printf("passed a Null Symbol Table to the setLineNumber function. Invalid./n"); - return st; - } - st->Line_Number = line; - } - -SymbolTable* setColumnNumber(SymbolTable *st,int column){ - if(st == NULL){ - printf("passed a Null Symbol Table to the setColumnNumber function. Invalid./n"); - return st; - } - st->Line_Number = column; + if (tn == NULL) { + printdebug("passed a NULL table entry to getType"); + return getName(undefined); } -/* -//we use false for type defs and true for functions for parameter of typeOf -TableNode* Define(SymbolTable* table, bool typeOf, char* id) { -if(table ==NULL || table->Parent_Scope != NULL){ - printf("No valid table given for header defs\n"); - return NULL; + if (tn == undefined) { + printdebug("passed an undefined table entry to getType"); + return getName(undefined); + } + if (tn->theType == NULL) { + printdebug("type of entry is currently NULL type"); + return getName(undefined); + } + if (tn->theType == undefined) { + printdebug("type of entry is currently undefined type"); + return getName(undefined); + } + return tn->theType->theName; } +char *getName(TableNode *tn) { + if (tn == NULL) { + printdebug("passed a NULL table entry to getName"); + return undefined->theName; + } + if (tn == undefined) { + printdebug("passed an undefined table entry to getName"); + return undefined->theName; + } + if (tn->theName == NULL) { + printdebug("name of entry is currently NULL, undefined"); + return undefined->theName; + } + return tn->theName; +} - TableNode* newEntry = (TableNode*)malloc(sizeof(TableNode)); +int getLine(SymbolTable *st) { + if (st == NULL) { + printdebug("passed a NULL symbol table to getLine function. " + "Invalid."); + return -1; + } + return st->Line_Number; +} +int getColumn(SymbolTable *st) { + if (st == NULL) { + printdebug("passed a NULL symbol table to getColumn function. " + "Invalid."); + return -1; + } + return st->Column_Number; +} +TableNode *addName(TableNode *tn, char *str) { + if (tn == NULL) { + printdebug("passed a Null table node to the addName " + "function. Invalid."); + return undefined; + } + if (tn == undefined) { + printdebug("passed an undefined table node to the addName " + "function. Invalid."); + return undefined; + } + if (tn->theName != NULL) { + printdebug( + "Name doesn't look like it is empty before you change. " + "Are you sure you need to update name?"); + return undefined; + } + if (str == NULL) { + printdebug( + "passed a NULL string to the addName function. Invalid."); + return undefined; + } + tn->theName = str; + return tn; +} -//possible issues with referencing text instead of heap -if(typeOf == 0){ - newEntry->theType = typey; +SymbolTable *setLineNumber(SymbolTable *st, int line) { + if (st == NULL) { + printdebug("passed a Null Symbol Table to the setLineNumber " + "function. Invalid."); + return st; + } + st->Line_Number = line; + return st; } -if (typeOf == 1){ - newEntry->theType = funy; -} -if(table_lookup(table,id) != NULL){ - printf("already defined at the top level, can't define duplicate -names\n"); return NULL; -} - newEntry->theName = id; - if (table->entries == NULL) { - table->entries = newEntry; - return newEntry; - } else { - TableNode* oldEntry = table->entries; - table->entries = newEntry; - newEntry->next = oldEntry; - return newEntry; - } +SymbolTable *setColumnNumber(SymbolTable *st, int column) { + if (st == NULL) { + printdebug("passed a Null Symbol Table to the setColumnNumber " + "function. Invalid."); + return st; + } + st->Line_Number = column; + return st; } -*/ -//only check table that is given + +// only check table that is given TableNode *table_lookup(SymbolTable *table, char *x) { + if (table == NULL) { + printdebug("passed in empty scope. error."); + return undefined; + } TableNode *entrie = table->entries; for (; entrie != NULL; entrie = entrie->next) { if (!strcmp(entrie->theName, x)) { return entrie; } } - return NULL; + return undefined; } -//check current table and all parents + +// check current table and all parents TableNode *look_up(SymbolTable *table, char *x) { if (table == NULL) { - return NULL; + printdebug("passed in empty scope. error."); + return undefined; } TableNode *ret = table_lookup(table, x); - if (ret != NULL) { + if (ret != NULL && ret != undefined) { return ret; } + printdebug( + "could not find %s in scope that started at line %d and column " + "%d so moving up a scope", + x, getLine(table), getColumn(table)); return look_up(table->Parent_Scope, x); } void print_symbol_table(SymbolTable *table, FILE *file_ptr) { - return; + if (table == NULL) { + printdebug( + "%s[FATAL] passed in NULL table to print_symbol_table", + COLOR_RED); + return; + } + if (table->Parent_Scope == NULL) { - fprintf(file_ptr, "%-17s: %-6s : %-6s : %-21s: %-28s\n", "NAME", + fprintf(file_ptr, "%-25s: %-6s : %-6s : %-25s: %-30s\n", "NAME", "SCOPE", "PARENT", "TYPE", "Extra annotation"); } + TableNode *entrie = table->entries; - fprintf(file_ptr, "-----------------:--------:--------:----------------" - "------:---------" - "--------------------\n"); + fprintf(file_ptr, + "-------------------------:--------:--------:------------------" + "--------:------------------------------\n"); int parant_scope = 0; int current_scope = 0; if (table->Parent_Scope != NULL) { - parant_scope = table->Parent_Scope->Line_Number * 1000 + - table->Parent_Scope->Column_Number; + parant_scope = getParent(table)->Line_Number * 1000 + + getParent(table)->Column_Number; current_scope = table->Line_Number * 1000 + table->Column_Number; } else { current_scope = 1001; } if (entrie == NULL) { - fprintf(file_ptr, "%-17s: %06d : %06d : %-21s: %-28s\n", "", + fprintf(file_ptr, "%-25s: %06d : %06d : %-25s: %-30s\n", "", current_scope, parant_scope, "", "Empty Scope"); } - for (entrie != NULL; entrie = entrie->next;) { - if (parant_scope == 0) { - /*have to update*/ if (strcmp(entrie->theType->theName, - "function primitive") || - strcmp(entrie->theType->theName, - "array")) { + for (; entrie != NULL; entrie = getNextEntry(entrie)) { + if (getAdInfoType(entrie) == TYPE_ARRAY_TYPE) { + if (parant_scope == 0) { + + fprintf(file_ptr, + "%-25s: %06d : : %d -> %-20s: " + "%-30s\n", + entrie->theName, current_scope, + entrie->additionalinfo->ArrayAdInfo + ->numofdimensions, + entrie->additionalinfo->ArrayAdInfo + ->typeofarray->theName, + "Type of Array"); + } else { + fprintf(file_ptr, + "%-25s: %06d : : %d -> %-20s: " + "%-30s\n", + entrie->theName, current_scope, + parant_scope, + entrie->additionalinfo->ArrayAdInfo + ->numofdimensions, + entrie->additionalinfo->ArrayAdInfo + ->typeofarray->theName, + "Type of Array"); + } + } + if (getAdInfoType(entrie) == TYPE_RECORD) { + if (parant_scope == 0) { + + fprintf(file_ptr, + "%-25s: %06d : : %-25s: " + "elements-%-30d\n", + entrie->theName, current_scope, + "record", + entrie->additionalinfo->RecAdInfo + ->numofelements); + } else { + fprintf(file_ptr, + "%-25s: %06d : %06d : %-25s: " + "elements-%-30d\n", + entrie->theName, current_scope, + parant_scope, "record", + entrie->additionalinfo->RecAdInfo + ->numofelements); + } + } + if (getAdInfoType(entrie) == TYPE_PRIMITIVE) { + if (parant_scope == 0) { + + fprintf( + file_ptr, + "%-25s: %06d : : %-25s: size-%d " + "bytes\n", + entrie->theName, current_scope, "Primitive", + entrie->additionalinfo->PrimAdInfo->size); + } else { + fprintf( + file_ptr, + "%-25s: %06d : %06d : %-25s: size-%-30d " + "bytes\n", + entrie->theName, current_scope, + parant_scope, "Primitive", + entrie->additionalinfo->PrimAdInfo->size); + } + } + if (getAdInfoType(entrie) == TYPE_FUNCTION_TYPE) { + if (parant_scope == 0) { + + fprintf(file_ptr, + "%-25s: %06d : : %-25s -> " + "%-25s: %-30s\n", + entrie->theName, current_scope, + entrie->additionalinfo->FunTypeAdInfo + ->parameter->theName, + entrie->additionalinfo->FunTypeAdInfo + ->returntype->theName, + "Type of Function"); + } else { + fprintf(file_ptr, + "%-25s: %06d : %06d : %-25s -> %-21s: " + "%-30s\n", + entrie->theName, current_scope, + parant_scope, + entrie->additionalinfo->FunTypeAdInfo + ->parameter->theName, + entrie->additionalinfo->FunTypeAdInfo + ->returntype->theName, + "Type of Function"); + } + } + if (getAdInfoType(entrie) == TYPE_FUNCTION_DECLARATION) { + if (parant_scope == 0) { + + fprintf(file_ptr, + "%-25s: %06d : : %-25s: %-30s\n", + entrie->theName, current_scope, + getType(entrie), "User Defined"); + } else { + fprintf(file_ptr, + "%-25s: %06d : %06d : %-25s: %-30s\n", + entrie->theName, current_scope, + parant_scope, getType(entrie), + "User Defined"); + } + } + if (getAdInfoType(entrie) == TYPE_UNDEFINED) { + if (parant_scope == 0) { + + fprintf(file_ptr, + "%-25s: %06d : : %-25s: %-30s\n", + entrie->theName, current_scope, + "undefined", "undefined entry"); + } else { + fprintf(file_ptr, + "%-25s: %06d : %06d : %-25s: %-30s\n", + entrie->theName, current_scope, + parant_scope, "undefined", + "undefined entry"); } - fprintf(file_ptr, - "%-17s: %06d : : %-21s: %-28s\n", - entrie->theName, current_scope, - entrie->theType->theName, "Extra annotation"); - } else { - fprintf(file_ptr, "%-17s: %06d : %06d : %-21s: %-28s\n", - entrie->theName, current_scope, parant_scope, - entrie->theType->theName, "Extra annotation"); } } - if (table->Children_Scope != NULL) { - ListOfTable *node = table->Children_Scope; + if (getChildren(table) != NULL) { + ListOfTable *node = getChildren(table); for (; node != NULL; node = node->next) { - print_symbol_table(node->table, file_ptr); + if ((node->table) == NULL) { + print_symbol_table(node->table, file_ptr); + } else { + if ((node->table)->Line_Number == -1) { + continue; + } else { + print_symbol_table(node->table, + file_ptr); + } + } } } - if (table->Parent_Scope == NULL) { - fprintf(file_ptr, "-----------------:--------:--------:--------" - "--------------:-------" - "----------------------\n"); + if (getParent(table) == NULL) { + fprintf(file_ptr, + "-------------------------:--------:--------:----------" + "----------------:------------------------------\n"); } } -//get top most symbol table +// get top most symbol table SymbolTable *getAncestor(SymbolTable *table) { + if (table == NULL) { + printdebug("passing a NULL reference to getAncestor. Invalid."); + return NULL; + } if (table->Parent_Scope == NULL) { // if table has no parent, return itself + printdebug("already at top scope!"); + if (table == cur) { + printdebug("passed in the current scope"); + } else { + printdebug("passed in a different scope"); + } return table; } else { // call function recursively to grab ancestor @@ -653,17 +993,26 @@ SymbolTable *removeEntry(SymbolTable *scope, char *search) { return scope; } -//almost certainly don't need to use the below function since type checking happens by passing types up the grammar +// almost certainly don't need to use the below function since type checking +// happens by passing types up the grammar bool typeCheck(char *firstID, char *secondID) { TableNode *entry1 = look_up(cur, firstID); TableNode *entry2 = look_up(cur, secondID); if (entry1 == NULL) { - printf("first type not defined\n"); + printdebug("first type is NULL in type check. Invalid."); + return false; + } + if (entry1 == undefined) { + printdebug("first type is undefined in type check. Invalid."); return false; } if (entry2 == NULL) { - printf("second type not defined\n"); + printdebug("second type is NULL in type check. Invalid."); + return false; + } + if (entry2 == undefined) { + printdebug("second type is undefined in type check. Invalid."); return false; } if (table_lookup(getAncestor(cur), getType(look_up(cur, firstID))) == @@ -691,26 +1040,34 @@ bool typeCheck(char *firstID, char *secondID) { return false; } -SymbolTable *getParent(SymbolTable *st) { return st->Parent_Scope; } +SymbolTable *getParent(SymbolTable *st) { + if (st == NULL) { + printdebug("passed a NULL symbol table to getParent function. " + "Invalid."); + return NULL; + } + if (st->Parent_Scope == NULL) { + printdebug("passed a top level scope to getParent function. " + "Invalid."); + return NULL; + } + return st->Parent_Scope; +} ListOfTable *getChildren(SymbolTable *st) { return st->Children_Scope; } SymbolTable *getFirstChild(ListOfTable *lt) { return lt->table; } ListOfTable *getRestOfChildren(ListOfTable *lt) { return lt->next; } TableNode *getFirstEntry(SymbolTable *st) { return st->entries; } -TableNode *getNextEntry(TableNode *tn) { return tn->next; } -// uncomment the below main function along with the headers above for a simple -// standalone test of table and entry creation -/* - int main(){ - char* String = "STRING"; - char* X = "X"; - SymbolTable* Second = CreateScope(NULL, 2,2); - printf("Line number is %d, Column number of scope is - %d\n",Second->Line_Number,Second->Column_Number); TableNode* First_Entry = - CreateEntry(Second,String,X); - - printf("The type of the first entry is %s\n",First_Entry->theType); - return 0; - } - */ +// Segfaults when passed an invalid table node! +TableNode *getNextEntry(TableNode *tn) { + if (tn == NULL) { + printdebug("passed a NULL table node to getNextEntry"); + return undefined; + } + if (tn == undefined) { + printdebug("passed an undefined table node to getNextEntry"); + return undefined; + } + return tn->next; +} diff --git a/src/symbol_table.h b/src/symbol_table.h index de37098..5f87b5b 100644 --- a/src/symbol_table.h +++ b/src/symbol_table.h @@ -1,3 +1,4 @@ +#include #include #include #include @@ -9,26 +10,12 @@ typedef struct { int size; } primitive_info; -/*This structure can be subsumed into the structure below (1-d array of chars) -typedef struct{ - //shouldn't need to store any values since would be compiled at runtime - //int length; - //char* location; -}string_info; -*/ - typedef struct { int numofdimensions; - // the above value tells you how long the below array is. For example if - // num of dimensions is 5, I can store 1,3,2,5,9 to define > int* - // arr; shouldn't need to store any values (like sizes of dimenions or - // the location int* sizesofdimensions; do have to store type of array struct TableNode *typeofarray; } array_info; typedef struct { - // similar to above we define a record to hold the number of elements - // and an array of tablenodes (types) that it contains in the > int numofelements; struct SymbolTable *recordScope; } record_info; @@ -47,19 +34,16 @@ typedef union { primitive_info *PrimAdInfo; array_info *ArrayAdInfo; record_info *RecAdInfo; - // string_info* StringAdInfo; function_declaration_info *FunDecAdInfo; function_type_info *FunTypeAdInfo; } AdInfo; typedef struct ListOfTable { struct SymbolTable *table; - // struct ListOfTable* prev; struct ListOfTable *next; } ListOfTable; typedef struct TableNode { - // reference to the type entry that this is struct TableNode *theType; char *theName; AdInfo *additionalinfo; @@ -74,30 +58,100 @@ typedef struct SymbolTable { int Column_Number; } SymbolTable; +typedef enum { + TYPE_STRING = 1, + TYPE_ARRAY_TYPE = 2, + TYPE_RECORD_TYPE = 3, + TYPE_FUNCTION_DECLARATION = 4, + TYPE_FUNCTION_TYPE = 5, + TYPE_PRIMITIVE = 6, + TYPE_ALL_ELSE = 7, + TYPE_UNDEFINED = 8, + TYPE_RECORD = 9, + TYPE_ARRAY = 10 +} types; + +AdInfo *CreatePrimitiveInfo(int size); +int getPrimSize(TableNode *definition); +AdInfo *CreateArrayInfo(int dim, TableNode *type); +int getNumArrDim(TableNode *definition); +TableNode *getArrType(TableNode *definition); +AdInfo *CreateRecordInfo(int length, SymbolTable *recordScope); +int getRecLength(TableNode *definition); +SymbolTable *getRecList(TableNode *definition); +TableNode *setRecSize(TableNode *tn, int n); +int getRecSize(SymbolTable *tn); +AdInfo *CreateFunctionDeclarationInfo(int line, bool asorregular); +int getStartLine(TableNode *definition); +TableNode *setStartLine(TableNode *tn, int start); +bool getAsKeyword(TableNode *definition); +TableNode *setAsKeyword(TableNode *tn, bool as); +AdInfo *CreateFunctionTypeInfo(TableNode *parameter, TableNode *returntype); +TableNode *getParameter(TableNode *definition); +TableNode *getReturn(TableNode *definition); SymbolTable *CreateScope(SymbolTable *ParentScope, int Line, int Column); +SymbolTable *init(SymbolTable *start); +TableNode *populateTypeAndInfo(TableNode *tn, TableNode *type, AdInfo *info); +int getAdInfoType(TableNode *tn); +TableNode *CreateEntry(SymbolTable *table, TableNode *typeOf, char *id, + AdInfo *ad); +char *getType(TableNode *tn); +char *getName(TableNode *tn); +int getLine(SymbolTable *st); +int getColumn(SymbolTable *st); +TableNode *addName(TableNode *tn, char *str); +SymbolTable *setLineNumber(SymbolTable *st, int line); +SymbolTable *setColumnNumber(SymbolTable *st, int column); TableNode *table_lookup(SymbolTable *table, char *x); TableNode *look_up(SymbolTable *table, char *x); void print_symbol_table(SymbolTable *table, FILE *file_ptr); - SymbolTable *getAncestor(SymbolTable *table); +SymbolTable *removeEntry(SymbolTable *scope, char *search); +bool typeCheck(char *firstID, char *secondID); SymbolTable *getParent(SymbolTable *st); ListOfTable *getChildren(SymbolTable *st); SymbolTable *getFirstChild(ListOfTable *lt); ListOfTable *getRestOfChildren(ListOfTable *lt); TableNode *getFirstEntry(SymbolTable *st); TableNode *getNextEntry(TableNode *tn); -SymbolTable *init(SymbolTable *scope); -int getPrimSize(TableNode *definition); -int getNumArrDim(TableNode *definition); -TableNode *getArrType(TableNode *definition); -int getRecLength(TableNode *definition); -SymbolTable *getRecList(TableNode *definition); -int getStartLine(TableNode *definition); -bool getAsKeyword(TableNode *definition); -TableNode *getParameter(TableNode *definition); -TableNode *getReturn(TableNode *definition); -char *getType(TableNode *tn); -char *getName(TableNode *tn); -int getLine(SymbolTable *st); -int getColumn(SymbolTable *st); +void printdebug_impl(char *file, int line, const char *format, ...); +#define printdebug(format, ...) \ + printdebug_impl(__FILE__, __LINE__, format, ##__VA_ARGS__) + +extern int yylex(void); +extern char *yytext; +extern int yyleng; +extern int yychar; +extern SymbolTable *cur; +extern int line_number; +extern int column_number; +extern FILE *yyin; +extern bool DEBUG; + +extern TableNode *funprime; +extern TableNode *arrayprim; +extern TableNode *integ; +extern TableNode *addr; +extern TableNode *chara; +extern TableNode *stri; +extern TableNode *boo; +extern TableNode *recprime; +extern TableNode *funtypeprime; +extern TableNode *undefined; + +extern char *COLOR_RED; +extern char *COLOR_GREEN; +extern char *COLOR_ORANGE; +extern char *COLOR_BLUE; +extern char *COLOR_PURPLE; +extern char *COLOR_CYAN; +extern char *COLOR_LIGHTGRAY; +extern char *COLOR_DARKGRAY; +extern char *COLOR_LIGHTRED; +extern char *COLOR_LIGHTGREEN; +extern char *COLOR_YELLOW; +extern char *COLOR_LIGHTBLUE; +extern char *COLOR_LIGHTPURPLE; +extern char *COLOR_LIGHTCYAN; +extern char *COLOR_WHITE; \ No newline at end of file diff --git a/test.sh b/test.sh new file mode 100755 index 0000000..9c32bed --- /dev/null +++ b/test.sh @@ -0,0 +1,166 @@ +#!/bin/bash + +# Test Tool # +# The Translators - Spring 2025 # + +RED='\033[0;31m' +GREEN='\033[0;32m' +ORANGE='\033[0;33m' +BLUE='\033[0;34m' +PURPLE='\033[0;35m' +CYAN='\033[0;36m' +LIGHTGRAY='\033[0;37m' +DARKGRAY='\033[1;30m' +LIGHTRED='\033[1;31m' +LIGHTGREEN='\033[1;32m' +YELLOW='\033[1;33m' +LIGHTBLUE='\033[1;34m' +LIGHTPURPLE='\033[1;35m' +LIGHTCYAN='\033[1;36m' +WHITE='\033[1;37m' + +if [ ! -f "./alpha" ]; then + echo -e "${RED}[ERROR] ${YELLOW}File ./alpha not found!${WHITE}" + exit 1 +fi + +if [ ! -d "./out" ]; then + mkdir -p out +fi + +SWITCH=${YELLOW} +count=0 + +switchfunc() { + if [ $count -eq 0 ]; then + count=1 + SWITCH=${YELLOW} + else + count=0 + SWITCH='\033[0;35m' + fi +} + +if [ $# -eq 0 ]; then + echo -e "${YELLOW}[INFO] ${WHITE}Running all tests...${WHITE}" + echo -e "${YELLOW}[INFO] ${ORANGE}Testing SPRINT-1 ---------------------------\n${WHITE}" + for file in ./tests/sprint1/test/*; do + if [ -f "$file" ]; then + filename=$(basename -- "$file") + echo -e "- ${SWITCH}Running test: ${LIGHTBLUE}$filename ${SWITCH}-----${WHITE}" + ./alpha -st "$file" -debug + echo -e "${SWITCH}----- End of test: ${LIGHTBLUE}$filename ${SWITCH}-${WHITE}\n" + switchfunc + fi + done + echo -e "" + + echo -e "${YELLOW}[INFO] ${ORANGE}Testing SPRINT-2 ---------------------------\n${WHITE}" + for file in ./tests/sprint2/test/*; do + if [ -f "$file" ]; then + filename=$(basename -- "$file") + echo -e "- ${SWITCH}Running test: ${LIGHTBLUE}$filename ${SWITCH}-----${WHITE}" + ./alpha -st "$file" -debug + echo -e "${SWITCH}----- End of test: ${LIGHTBLUE}$filename ${SWITCH}-${WHITE}\n" + switchfunc + fi + done + echo -e "" + + echo -e "${YELLOW}[INFO] ${ORANGE}Testing SPRINT-3 ---------------------------\n${WHITE}" + for file in ./tests/sprint3/test/*; do + if [ -f "$file" ]; then + filename=$(basename -- "$file") + echo -e "- ${SWITCH}Running test: ${LIGHTBLUE}$filename ${SWITCH}-----${WHITE}" + ./alpha -st "$file" -debug + echo -e "${SWITCH}----- End of test: ${LIGHTBLUE}$filename ${SWITCH}-${WHITE}\n" + switchfunc + fi + done + echo -e "" + + echo -e "${YELLOW}[INFO] ${ORANGE}Testing SPRINT-4 ---------------------------\n${WHITE}" + for file in ./tests/sprint4/test/*; do + if [ -f "$file" ]; then + filename=$(basename -- "$file") + echo -e "- ${SWITCH}Running test: ${LIGHTBLUE}$filename ${SWITCH}-----${WHITE}" + ./alpha -st "$file" -debug + echo -e "${SWITCH}----- End of test: ${LIGHTBLUE}$filename ${SWITCH}-${WHITE}\n${WHITE}" + switchfunc + fi + done + +else + if [ "$1" == "--help" ]; then + echo -e "${YELLOW}[INFO] ${WHITE}Usage: ./test.sh [prefix]" + echo -e "${YELLOW}[INFO] ${WHITE}--help: show this help message" + echo -e "${YELLOW}[INFO] ${WHITE}--file : run test with file" + exit 0 + fi + if [[ "$1" == "--file" ]]; then + shift + if [ $# -eq 0 ]; then + echo -e "${RED}[ERROR] ${YELLOW}No file specified!${WHITE}" + exit 1 + fi + if [ -f "$1" ]; then + filename=$(basename -- "$1") + echo -e "- ${SWITCH}Running test: ${LIGHTBLUE}$filename ${SWITCH}-----${WHITE}" + ./alpha -st "$1" -debug + echo -e "${SWITCH}----- End of test: ${LIGHTBLUE}$filename ${SWITCH}-${WHITE}" + exit 1 + else + echo -e "${RED}[ERROR] ${YELLOW}File $1 not found!${WHITE}" + exit 1 + fi + fi + + if [[ "$1" == "sp1" ]]; then + echo -e "${YELLOW}[INFO] ${WHITE}Running tests with prefix $1..." + for file in ./tests/sprint1/test/*; do + if [[ "$file" == *"$1"* ]]; then + filename=$(basename -- "$file") + echo -e "- ${SWITCH}Running test: ${LIGHTBLUE}$filename ${SWITCH}-----${WHITE}" + ./alpha -st "$file" -debug + echo -e "${SWITCH}----- End of test: ${LIGHTBLUE}$filename ${SWITCH}-${WHITE}\n" + switchfunc + fi + done + elif [[ "$1" == "sp2" ]]; then + echo -e "${YELLOW}[INFO] ${WHITE}Running tests with prefix $1..." + for file in ./tests/sprint2/test/*; do + if [[ "$file" == *"$1"* ]]; then + filename=$(basename -- "$file") + echo -e "- ${SWITCH}Running test: ${LIGHTBLUE}$filename ${SWITCH}-----${WHITE}" + ./alpha -st "$file" -debug + echo -e "${SWITCH}----- End of test: ${LIGHTBLUE}$filename ${SWITCH}-${WHITE}\n" + switchfunc + fi + done + elif [[ "$1" == "sp3" ]]; then + echo -e "${YELLOW}[INFO] ${WHITE}Running tests with prefix $1..." + for file in ./tests/sprint3/test/*; do + if [[ "$file" == *"$1"* ]]; then + filename=$(basename -- "$file") + echo -e "- ${SWITCH}Running test: ${LIGHTBLUE}$filename ${SWITCH}-----${WHITE}" + ./alpha -st "$file" -debug + echo -e "${SWITCH}----- End of test: ${LIGHTBLUE}$filename ${SWITCH}-${WHITE}\n" + switchfunc + fi + done + elif [[ "$1" == "sp4" ]]; then + echo -e "${YELLOW}[INFO] ${WHITE}Running tests with prefix $1..." + for file in ./tests/sprint4/test/*; do + if [[ "$file" == *"$1"* ]]; then + filename=$(basename -- "$file") + echo -e "- ${SWITCH}Running test: ${LIGHTBLUE}$filename ${SWITCH}-----${WHITE}" + ./alpha -st "$file" -debug + echo -e "${SWITCH}----- End of test: ${LIGHTBLUE}$filename ${SWITCH}-${WHITE}\n" + switchfunc + fi + done + else + echo -e "${RED}[ERROR] ${YELLOW}Invalid prefix $1!${WHITE}" + exit 1 + fi +fi \ No newline at end of file diff --git a/tests/sprint2/test/test_carls_mistake.alpha b/tests/sprint2/test/sp2_carls_mistake.alpha similarity index 77% rename from tests/sprint2/test/test_carls_mistake.alpha rename to tests/sprint2/test/sp2_carls_mistake.alpha index fb75ca3..2f4c1ef 100644 --- a/tests/sprint2/test/test_carls_mistake.alpha +++ b/tests/sprint2/test/sp2_carls_mistake.alpha @@ -1,6 +1,7 @@ type rec: [integer: x; integer: y] type T1: integer -> integer type T2: rec -> integer +type arr : 1 -> integer function foo : T1 function bar1 : T2 @@ -18,10 +19,10 @@ bar2 as (r,s) := { entry(arg) := { [ integer: result ; rec: w] result := foo(5); - w := reserve(w); (* see types.alpha – reserve returns a value of type address, which can be assigned to array and record variables*) + w := reserve w; (* see types.alpha – reserve returns a value of type address, which can be assigned to array and record variables*) w.x := 5; w.y := 7; result := bar1(w); (* pass w (a rec type value) to bar1 *) result := bar2(5,7); (* implicitly build a rec type value, assign 5 and 7 to fields x and y, but call them r and s *) return 0; -} \ No newline at end of file +} diff --git a/tests/sprint2/test/sp2_function_types.alpha b/tests/sprint2/test/sp2_function_types.alpha new file mode 100644 index 0000000..509de78 --- /dev/null +++ b/tests/sprint2/test/sp2_function_types.alpha @@ -0,0 +1,17 @@ +type Boolean2Boolean: Boolean -> Boolean +type integer2integer: integer -> integer +type character2integer: character -> integer +type Boolean2integer: Boolean -> integer +type string2integer: string -> integer +function integerXinteger2integer: integerXinteger (*-> integer +type integerXinteger2Boolean: integerXinteger -> Boolean +type characterXcharacter2Boolean: characterXcharacter -> Boolean +type BooleanXBoolean2Boolean: BooleanXBoolean -> Boolean +type integer2address: integer -> address +type address2integer: address -> integer +external function printInteger: integer2integer +external function printCharacter: character2integer +external function printBoolean: Boolean2integer +external function reserve: integer2address +external function release: address2integer +function entry: string2integer*) \ No newline at end of file diff --git a/tests/sprint2/test/test_invalid_recop.alpha b/tests/sprint2/test/sp2_invalid_recop.alpha similarity index 100% rename from tests/sprint2/test/test_invalid_recop.alpha rename to tests/sprint2/test/sp2_invalid_recop.alpha diff --git a/tests/sprint2/test/test_invalid_release.alpha b/tests/sprint2/test/sp2_invalid_release.alpha similarity index 100% rename from tests/sprint2/test/test_invalid_release.alpha rename to tests/sprint2/test/sp2_invalid_release.alpha diff --git a/tests/sprint2/test/sp2_library.alpha b/tests/sprint2/test/sp2_library.alpha index 9bacd6c..866857c 100644 --- a/tests/sprint2/test/sp2_library.alpha +++ b/tests/sprint2/test/sp2_library.alpha @@ -7,9 +7,9 @@ You should #include this file at the start of your alpha file. Some useful types are defined below. *) type string: 1 -> character -type BooleanXBoolean: [Boolean: x, y] -type characterXcharacter: [character: x, y] -type integerXinteger: [integer: x, y] +type BooleanXBoolean: [Boolean: x; Boolean: y] +type characterXcharacter: [character: x; character: y] +type integerXinteger: [integer: x; integer: y] type Boolean2Boolean: Boolean -> Boolean type integer2integer: integer -> integer @@ -25,6 +25,4 @@ type address2integer: address -> integer external function printInteger: integer2integer external function printCharacter: character2integer external function printBoolean: Boolean2integer -external function reserve: integer2address -external function release: address2integer function entry: string2integer diff --git a/tests/sprint2/test/sp2_llnode.alpha b/tests/sprint2/test/sp2_llnode.alpha index 6b4912e..43007ef 100644 --- a/tests/sprint2/test/sp2_llnode.alpha +++ b/tests/sprint2/test/sp2_llnode.alpha @@ -9,6 +9,7 @@ function foo : T1 function bar1 : T2 function bar2 : T2 function make_list : list + make_list(a) := { [integer:orig_a; address: ret; address: curr; address: temp] if (a < 0 | a = 0) then { diff --git a/tests/sprint2/test/test_valid_assignable_and_mem.alpha b/tests/sprint2/test/sp2_valid_assignable_and_mem.alpha similarity index 100% rename from tests/sprint2/test/test_valid_assignable_and_mem.alpha rename to tests/sprint2/test/sp2_valid_assignable_and_mem.alpha diff --git a/tests/sprint3/test/sp3_boolean_binary_op_typecheck.alpha b/tests/sprint3/test/sp3_boolean_binary_op_typecheck.alpha new file mode 100644 index 0000000..5952129 --- /dev/null +++ b/tests/sprint3/test/sp3_boolean_binary_op_typecheck.alpha @@ -0,0 +1,6 @@ +entry(arg) := { + [integer:x; address: arr; address: arr2; Boolean : b2; Boolean : b1] + b2 := 3 < x; + b1 := arr = 2; + b1 := 6<7 & arr2=7; +} diff --git a/tests/sprint3/test/sp3_boolean_unary_op_typecheck.alpha b/tests/sprint3/test/sp3_boolean_unary_op_typecheck.alpha new file mode 100644 index 0000000..12db768 --- /dev/null +++ b/tests/sprint3/test/sp3_boolean_unary_op_typecheck.alpha @@ -0,0 +1,5 @@ +entry(arg) := { + [integer:x; address: arr; address: arr2; Boolean : b2; Boolean : b1] + b2 := !(3 < 2); + b1 := !5; +} diff --git a/tests/sprint3/test/sp3_carls_second_mistake.alpha b/tests/sprint3/test/sp3_carls_second_mistake.alpha new file mode 100644 index 0000000..6d1d614 --- /dev/null +++ b/tests/sprint3/test/sp3_carls_second_mistake.alpha @@ -0,0 +1,25 @@ +type string: 1 -> character +type a_of_s: 1 -> string + +(* maybe some other type definitions *) + +entry(arg) := { + [ string: one_name; string: another_name; a_of_s: many_names ] + one_name := "a string literal"; + another_name := reserve another_name(4); (* reserve space for an an array of character, with 4 members *) + another_name(0) := 'C'; + another_name(1) := 'a'; + another_name(2) := 'r'; + another_name(3) := 'l'; + many_names := reserve many_names(3); + many_names(0) := one_name; + many_names(1) := another_name; + many_names(2) := reserve many_names(2)(6); (* reserve space for an item of the same type as a_of_s(2), an array of character, with 6 members *) + many_names(2)(0) := 'P'; + many_names(2)(1) := 'a'; + many_names(2)(2) := 'r'; + many_names(2)(3) := 't'; + many_names(2)(4) := 'h'; + 0(2)(5) := 'o'; + return 0; +} \ No newline at end of file diff --git a/tests/sprint3/test/sp3_integer_binary_op_typecheck.alpha b/tests/sprint3/test/sp3_integer_binary_op_typecheck.alpha new file mode 100644 index 0000000..5b13147 --- /dev/null +++ b/tests/sprint3/test/sp3_integer_binary_op_typecheck.alpha @@ -0,0 +1,9 @@ +entry(arg) := { + [integer:x; address: arr; address: arr2; Boolean : b2; Boolean : b1; character : a] + x := 3 + 2 * 8; + x := 3 - 2 / 8; + x := a * 2 % 8; + b2 := 3 * 2 % 8; + x := 3 % 2 * 8; + x := 3 + arr - 8; +} diff --git a/tests/sprint3/test/sp3_integer_unary_op_typecheck.alpha b/tests/sprint3/test/sp3_integer_unary_op_typecheck.alpha new file mode 100644 index 0000000..31e01a7 --- /dev/null +++ b/tests/sprint3/test/sp3_integer_unary_op_typecheck.alpha @@ -0,0 +1,6 @@ +entry(arg) := { + [integer:x; address: arr; address: arr2; Boolean : b2; Boolean : b1] + x := -8; + x := -b1; + b2 := -x; +}