From bc19c16a058914f27b97e9f7047e69b3bb7020ad Mon Sep 17 00:00:00 2001 From: SantriptaSharma Date: Fri, 24 Nov 2023 01:39:34 +0530 Subject: [PATCH] complete translator (a4): missing type validation & feats --- 15_A4.y | 269 ++++++++++++++++-- 15_A4_translator.c | 15 +- 15_A4_translator.h | 9 +- .../bubble_sort.nc => bubble_sort.nc | 3 + corecursive_fibonacci.nc | 25 ++ .../error_test.nc => error_test.nc | 0 sample_output_A3/corecursive_fibonacci.nc | 23 -- simpletest.nc | 2 +- testfiblist.nc | 45 +++ testthing.nc | 12 +- 10 files changed, 331 insertions(+), 72 deletions(-) rename sample_output_A3/bubble_sort.nc => bubble_sort.nc (93%) create mode 100644 corecursive_fibonacci.nc rename sample_output_A3/error_test.nc => error_test.nc (100%) delete mode 100644 sample_output_A3/corecursive_fibonacci.nc create mode 100644 testfiblist.nc diff --git a/15_A4.y b/15_A4.y index e90fcb7..20ec1c4 100644 --- a/15_A4.y +++ b/15_A4.y @@ -115,6 +115,7 @@ guard: { $$ = MakeList(quads_size); Emit(Jump(AImm(0))); } /* expressions */ /* TODO: validate types and add implicit conversions Compatible Types: (int, char, temp, array, any_ptr) + now, temps need types too for cross validation */ constant: INTCONST @@ -135,22 +136,77 @@ primary_expression: postfix_expression: primary_expression | postfix_expression '[' expression ']' { - // TODO: add error detection, make sure $1 is a pointer - $$ = PURE_EXPR(GenTemp()); Emit(IndexRead(ASym($$), ASym($1), ASym($3))); + if ($1.sym->type.kind != ARRAY_PTR && $1.sym->type.kind != PRIMITIVE_PTR && $1.sym->type.kind != ARRAY_T) { + yyerror("can't index non-array type"); + YYABORT; + } + + enum KIND_T kind = $1.sym->type.kind == ARRAY_PTR ? PRIMITIVE_PTR : PRIMITIVE_T; + $$ = PURE_EXPR(SymInit(kind)); + size_t len = strlen($1.sym->name) + 15; + char *name = malloc(len); + sprintf(name, "%s__[%d]", $1.sym->name, current_table->temp_count++); + $$.sym->name = name; + $$.sym->type = $1.sym->type.kind == PRIMITIVE_PTR ? prim2type($1.sym->type.primitive) : prim2type($1.sym->type.array.base); + $$.sym->size = GetSize($$.sym->type); + + SymInsert($$.sym); + + Emit(IndexRead(ASym($$), ASym($1), ASym($3))); } | postfix_expression '(' argument_expression_list ')' { - // TODO: call, validate number and type of params - log("postfix-expression") - DestroyArgList($3); + // TODO: validate type of params + if ($1.sym->type.kind != FUNC_T) { + yyerror("can't call non-function type"); + YYABORT; + } + + if ($1.sym->type.func.arg_list == NULL) { + yyerror("function does not take any parameters"); + YYABORT; + } + + size_t argc = 0; + + ArgList *it = $1.sym->type.func.arg_list; + ArgList *it2 = $3; + + while (it != NULL && it2 != NULL) { + Emit(Param(ASym(it2->elem.expr))); + + argc += 1; + it = it->next; + it2 = it2->next; + } + + if (it != NULL || it2 != NULL) { + yyerror("function call has wrong number of parameters"); + YYABORT; + } + + $$ = PURE_EXPR(GenTemp()); + + Emit(CallAss(ASym($$), ASym($1), AImm(argc))); } | postfix_expression '(' ')' { - // TODO: call, validate number and type of params - log("postfix-expression") + if ($1.sym->type.kind != FUNC_T) { + yyerror("can't call non-function type"); + YYABORT; + } + + if ($1.sym->type.func.arg_list != NULL) { + yyerror("function does not take 0 parameters"); + YYABORT; + } + + $$ = PURE_EXPR(GenTemp()); + + Emit(CallAss(ASym($$), ASym($1), AImm(0))); } - | postfix_expression ARROW IDENTIFIER { - // TODO: not sure what to do here? we don't have structs + /* | postfix_expression ARROW IDENTIFIER { + // not sure what to do here? we don't have structs log("postfix-expression") - } + } */ argument_expression_list: assignment_expression {$$ = MakeArgList(ARG_EXPR($1));} @@ -161,10 +217,46 @@ argument_expression_list: unary_expression: postfix_expression | '&' unary_expression {$$ = PURE_EXPR(GenTemp()); Emit(UnaryOp(ADDR, ASym($$), ASym($2)));} - | '*' unary_expression {$$ = PURE_EXPR(GenTemp()); Emit(UnaryOp(DEREF, ASym($$), ASym($2)));} + | '*' unary_expression { + if ($2.sym->type.kind != ARRAY_PTR && $2.sym->type.kind != PRIMITIVE_PTR && $2.sym->type.kind != ARRAY_T) { + yyerror("can't dereference non-pointer type"); + YYABORT; + } + + enum KIND_T kind = $2.sym->type.kind == ARRAY_PTR ? ARRAY_T : PRIMITIVE_T; + size_t len = strlen($2.sym->name) + 4; + char *name = malloc(len); + sprintf(name, "*__%s", $2.sym->name); + + $$ = PURE_EXPR(SymInit(kind)); + + $$.sym = SymLookup(name); + + if ($$.sym != NULL) { + free(name); + } else { + $$ = PURE_EXPR(SymInit(kind)); + $$.sym->name = name; + $$.sym->type = $2.sym->type.kind != PRIMITIVE_T ? prim2type($2.sym->type.array.base) : prim2type($2.sym->type.primitive); + $$.sym->size = GetSize($$.sym->type); + + SymInsert($$.sym); + } + + Emit(UnaryOp(DEREF, ASym($$), ASym($2))); + } | '+' unary_expression {$$ = PURE_EXPR(GenTemp()); Emit(UnaryOp(POS, ASym($$), ASym($2)));} | '-' unary_expression {$$ = PURE_EXPR(GenTemp()); Emit(UnaryOp(NEG, ASym($$), ASym($2)));} - | '!' unary_expression {$$ = $2;} + | '!' unary_expression { + if ($2.truelist == NULL) { + $2.truelist = MakeList(quads_size); + Emit(JumpIf(AImm(0), ASym($2))); + $2.falselist = MakeList(quads_size); + Emit(Jump(AImm(0))); + } + + $$ = BOOL_EXPR($2.sym, $2.falselist, $2.truelist); + } multiplicative_expression: unary_expression @@ -179,37 +271,140 @@ additive_expression: relational_expression: additive_expression - | relational_expression '<' additive_expression {log("relational-expression")} - | relational_expression '>' additive_expression {log("relational-expression")} - | relational_expression LEQ additive_expression {log("relational-expression")} - | relational_expression GEQ additive_expression {log("relational-expression")} + | relational_expression '<' additive_expression { + QuadList *tl = MakeList(quads_size); + Emit(JumpIfLess(AImm(0), ASym($1), ASym($3))); + QuadList *fl = MakeList(quads_size); + Emit(Jump(AImm(0))); + $$ = BOOL_EXPR($1.sym, tl, fl); + } + | relational_expression '>' additive_expression { + QuadList *tl = MakeList(quads_size); + Emit(JumpIfGreater(AImm(0), ASym($1), ASym($3))); + QuadList *fl = MakeList(quads_size); + Emit(Jump(AImm(0))); + + $$ = BOOL_EXPR($1.sym, tl, fl); + } + | relational_expression LEQ additive_expression { + QuadList *tl = MakeList(quads_size); + Emit(JumpIfLessEqual(AImm(0), ASym($1), ASym($3))); + QuadList *fl = MakeList(quads_size); + Emit(Jump(AImm(0))); + + $$ = BOOL_EXPR($1.sym, tl, fl); + } + | relational_expression GEQ additive_expression { + QuadList *tl = MakeList(quads_size); + Emit(JumpIfGreaterEqual(AImm(0), ASym($1), ASym($3))); + QuadList *fl = MakeList(quads_size); + Emit(Jump(AImm(0))); + + $$ = BOOL_EXPR($1.sym, tl, fl); + } equality_expression: relational_expression - | equality_expression CEQ relational_expression {log("equality-expression")} - | equality_expression NEQ relational_expression {log("equality-expression")} + | equality_expression CEQ relational_expression { + QuadList *tl = MakeList(quads_size); + Emit(JumpIfEqual(AImm(0), ASym($1), ASym($3))); + QuadList *fl = MakeList(quads_size); + Emit(Jump(AImm(0))); + + $$ = BOOL_EXPR($1.sym, tl, fl); + } + | equality_expression NEQ relational_expression { + QuadList *tl = MakeList(quads_size); + Emit(JumpIfNotEqual(AImm(0), ASym($1), ASym($3))); + QuadList *fl = MakeList(quads_size); + Emit(Jump(AImm(0))); + + $$ = BOOL_EXPR($1.sym, tl, fl); + } logical_AND_expression: equality_expression - | logical_AND_expression LAND equality_expression {log("logical-AND-expression")} + | logical_AND_expression { + if ($1.truelist == NULL) { + $1.truelist = MakeList(quads_size); + Emit(JumpIf(AImm(0), ASym($1))); + $1.falselist = MakeList(quads_size); + Emit(Jump(AImm(0))); + } + } LAND marker equality_expression { + if ($5.truelist == NULL) { + $5.truelist = MakeList(quads_size); + Emit(JumpIf(AImm(0), ASym($5))); + $5.falselist = MakeList(quads_size); + Emit(Jump(AImm(0))); + } + + Backpatch($1.truelist, $4); + + $$ = BOOL_EXPR($1.sym, $5.truelist, Merge($1.falselist, $5.falselist)); + } logical_OR_expression: logical_AND_expression - | logical_OR_expression LOR logical_AND_expression {log("logical-OR-expression")} + | logical_OR_expression { + if ($1.truelist == NULL) { + $1.truelist = MakeList(quads_size); + Emit(JumpIf(AImm(0), ASym($1))); + $1.falselist = MakeList(quads_size); + Emit(Jump(AImm(0))); + } + } LOR marker logical_AND_expression { + if ($5.truelist == NULL) { + $5.truelist = MakeList(quads_size); + Emit(JumpIf(AImm(0), ASym($5))); + $5.falselist = MakeList(quads_size); + Emit(Jump(AImm(0))); + } + + Backpatch($1.falselist, $4); + + $$ = BOOL_EXPR($1.sym, Merge($1.truelist, $5.truelist), $5.falselist); + } conditional_expression: logical_OR_expression - | logical_OR_expression '?' expression ':' conditional_expression {log("conditional-expression")} + | logical_OR_expression { + if ($1.truelist == NULL) { + $1.truelist = MakeList(quads_size); + Emit(JumpIf(AImm(0), ASym($1))); + $1.falselist = MakeList(quads_size); + Emit(Jump(AImm(0))); + } + } '?' marker expression guard ':' marker conditional_expression guard { + Backpatch($1.truelist, $4); + Backpatch($1.falselist, $8); + + $$ = PURE_EXPR(GenTemp()); + Backpatch($6, quads_size); + Emit(Mov(ASym($$), ASym($5))); + size_t q = quads_size; + Emit(Jump(AImm(0))); + + Backpatch($10, quads_size); + Emit(Mov(ASym($$), ASym($9))); + quads[q].rd.imm = quads_size; + } assignment_expression: conditional_expression - | unary_expression '=' assignment_expression {log("assignment-expression")} + | unary_expression '=' assignment_expression { + if ($1.sym->type.kind == FUNC_T || $1.sym->type.kind == TEMP_T) { + yyerror("functions & temps can't be assigned to"); + YYABORT; + } + + Emit(Mov(ASym($1), ASym($3))); + } expression: assignment_expression /* Declarations */ -// TODO: test this, seems to be complete, build a debug printer for symbols declaration: type_specifier init_declarator ';' { $$ = $2; @@ -242,6 +437,7 @@ declaration: } Symbol *existing = SymLookup($$.sym->name); + $$.sym->size = GetSize($$.sym->type); if (existing != NULL && $$.sym->type.kind != FUNC_T) { char err[384]; @@ -393,7 +589,7 @@ compound_statement: block_item_list: block_item - | block_item_list marker block_item { Backpatch($1, $2); $$ = $3; } + | block_item_list marker block_item { Backpatch($1, $2); $$ = $3; Backpatch($$, quads_size); } block_item: declaration { $$ = NULL; } @@ -407,10 +603,24 @@ expression_statement: opt_expression ';' { $$ = NULL; } selection_statement: - IF '(' expression ')' marker statement { Backpatch($3.truelist, $5); $$ = Merge($3.falselist, $6); } + IF '(' expression ')' marker statement { + if ($3.truelist != NULL) { + Backpatch($3.truelist, $5); $$ = Merge($3.falselist, $6); + } else { + Emit(JumpIf(AImm($5), ASym($3))); + $$ = MakeList(quads_size); + Emit(Jump(AImm(0))); + } + } | IF '(' expression ')' marker statement guard ELSE marker statement { - Backpatch($3.truelist, $5); Backpatch($3.falselist, $9); - $$ = Merge($6, $7); $$ = Merge($$, $10); + if ($3.truelist != NULL) { + Backpatch($3.truelist, $5); Backpatch($3.falselist, $9); + $$ = Merge($6, $7); $$ = Merge($$, $10); + } else { + Emit(JumpIf(AImm($5), ASym($3))); + Emit(Jump(AImm($9))); + $$ = Merge($6, $10); + } } iteration_statement: @@ -419,7 +629,7 @@ iteration_statement: QuadList *fl = $6.has_expr ? $6.expr.falselist : NULL; Backpatch(tl, $12); Backpatch($10, $5); Backpatch($13, $8); - Emit(Jump(AImm($5))); + Emit(Jump(AImm($8))); $$ = fl; } @@ -480,10 +690,11 @@ function_definition: current_table = $2.sym->inner_table; - // TODO: annotate statements with next lists and fill them in properly, function code guard??? + Emit(FnLabel(ASym($2))); } compound_statement { current_table = &glb_table; + Backpatch($4, quads_size); Emit(Return(AImm(0))); } %% diff --git a/15_A4_translator.c b/15_A4_translator.c index 3f63f53..2009a3d 100644 --- a/15_A4_translator.c +++ b/15_A4_translator.c @@ -26,7 +26,7 @@ static void FreeQuads() } static const char *OpSym[] = { - [ADD] "+", [SUB] "-", [MUL] "*", [DIV] "/", [MOD] "%%", + [ADD] "+", [SUB] "-", [MUL] "*", [DIV] "/", [MOD] "%", [POS] "+", [NEG] "-", [ADDR] "&", [DEREF] "*", [JLT] "<", [JGT] ">", [JEQ] "==", [JNE] "!=", [JLE] "<=", [JGE] ">=", }; @@ -129,7 +129,6 @@ static void DisplayAddr(Addr a) { } } -// TODO: too many assumptions about type of address, generalise to DisplayAddr void DisplayQuad(Quad q) { switch (q.opcode) { case ADD: @@ -180,9 +179,9 @@ void DisplayQuad(Quad q) { break; case CAL: if (q.rs.kind == SYMBOL_A) - printf("%s = call %s, %d", q.rs.sym->name, q.rd.sym->name, 10000); + printf("%s = call %s, %d", q.rs.sym->name, q.rd.sym->name, q.rt.imm); else if (q.rs.kind == IMMEDIATE) { - printf("call %s, %d", q.rd.sym->name, 10000); + printf("call %s, %d", q.rd.sym->name, q.rd.imm); } break; case RET: @@ -210,11 +209,15 @@ void DisplayQuad(Quad q) { printf("%s = ", q.rd.sym->name); DisplayAddr(q.rs); break; + case FN_LABEL: + printf("%s:", q.rd.sym->name); + break; } } void DisplayQuads() { for (int i = 0; i < quads_size; i++) { + if (quads[i].opcode == FN_LABEL) printf("\n"); printf("%d: ", i); DisplayQuad(quads[i]); printf("\n"); @@ -496,7 +499,7 @@ Symbol *StringLookupOrInsert(const char *str) { Symbol *GenTemp() { - char name[16]; + char name[20]; sprintf(name, "__t_%d_", current_table->temp_count++); Symbol *sym = SymLookupOrInsert(name); @@ -574,8 +577,8 @@ int main() { yyparse(); - DisplayQuads(); SymTableDispl(current_table); + DisplayQuads(); FreeTables(); FreeQuads(); diff --git a/15_A4_translator.h b/15_A4_translator.h index 6d7c9bc..0e4f639 100644 --- a/15_A4_translator.h +++ b/15_A4_translator.h @@ -34,10 +34,9 @@ QuadList *Merge(QuadList *list1, QuadList *list2); void Backpatch(QuadList *list, int dest); void FreeList(QuadList *list); -// TODO: remove not if assignment finally does not ask for it, a couple places to remove from typedef struct { enum OPCODE {ADD, SUB, MUL, DIV, MOD, MOV, POS, NEG, ADDR, DEREF, JMP, JIF, JNT, - JLT, JGT, JEQ, JNE, JLE, JGE, PAR, CAL, RET, INDR, INDW, PTRW} opcode; + JLT, JGT, JEQ, JNE, JLE, JGE, PAR, CAL, RET, INDR, INDW, PTRW, FN_LABEL} opcode; Addr rs, rt, rd; } Quad; @@ -62,12 +61,13 @@ void Emit(Quad q); #define JumpIfLessEqual(dest, op1, op2) ((Quad){JLE, op1, op2, dest}) #define JumpIfGreaterEqual(dest, op1, op2) ((Quad){JGE, op1, op2, dest}) #define Param(source) ((Quad){PAR, source, AImm(0), AImm(0)}) -#define Call(func) ((Quad){CAL, AImm(0), AImm(0), func}) -#define CallAss(dest, func) ((Quad){CAL, dest, AImm(0), func}) +#define Call(func, args) ((Quad){CAL, AImm(0), args, func}) +#define CallAss(dest, func, args) ((Quad){CAL, dest, args, func}) #define Return(val) ((Quad){RET, val, AImm(0), AImm(0)}) #define IndexRead(dest, source, index) ((Quad){INDR, source, index, dest}) #define IndexWrite(dest, index, source) ((Quad){INDW, source, index, dest}) #define DerefWrite(dest, source) ((Quad){PTRW, dest, AImm(0), source}) +#define FnLabel(label) ((Quad){FN_LABEL, AImm(0), AImm(0), label}) void DisplayQuad(Quad q); void DisplayQuads(); @@ -137,6 +137,7 @@ typedef struct _ExprAttrib { } ExprAttrib; #define PURE_EXPR(x) ((ExprAttrib){.sym = x, .truelist = NULL, .falselist = NULL}) +#define BOOL_EXPR(x, tl, fl) ((ExprAttrib){.sym = x, .truelist = tl, .falselist = fl}) typedef struct _ArgListElem { enum {EXPR, DECL} kind; diff --git a/sample_output_A3/bubble_sort.nc b/bubble_sort.nc similarity index 93% rename from sample_output_A3/bubble_sort.nc rename to bubble_sort.nc index f9db7cb..03e8112 100644 --- a/sample_output_A3/bubble_sort.nc +++ b/bubble_sort.nc @@ -1,7 +1,10 @@ // Forward declarations void swap(int *p, int *q); void readArray(int size); +void readInt(int *dest); +void printStr(char *str); void printArray(int size); +void printInt(int i); void bubbleSort(int n); int arr[20]; // Global array // Driver program to test above functions diff --git a/corecursive_fibonacci.nc b/corecursive_fibonacci.nc new file mode 100644 index 0000000..ff17398 --- /dev/null +++ b/corecursive_fibonacci.nc @@ -0,0 +1,25 @@ +// Find fibonacci by co-recursion +int f_odd(int n); +int f_even(int n); +void printStr(char *c); +void printInt(int i); + +int fibonacci(int n) { + return (n % 2 == 0)? f_even(n): f_odd(n); +} +int f_odd(int n) { + return (n == 1)? 1: f_even(n-1) + f_odd(n-2); +} +int f_even(int n) { + return (n == 0)? 0: f_odd(n-1) + f_even(n-2); +} +int main() { + int n = 10; + int r; + r = fibonacci(n); + printStr("fibo("); + printInt(n); + printStr(") = "); + printInt(r); + return 0; +} \ No newline at end of file diff --git a/sample_output_A3/error_test.nc b/error_test.nc similarity index 100% rename from sample_output_A3/error_test.nc rename to error_test.nc diff --git a/sample_output_A3/corecursive_fibonacci.nc b/sample_output_A3/corecursive_fibonacci.nc deleted file mode 100644 index 80975bd..0000000 --- a/sample_output_A3/corecursive_fibonacci.nc +++ /dev/null @@ -1,23 +0,0 @@ -// Find fibonacci by co-recursion -int f_odd(int n); -int f_even(int n); -int fibonacci(int n) { -return (n % 2 == 0)? f_even(n): f_odd(n); -} -int f_odd(int n) { -return (n == 1)? 1: f_even(n-1) + f_odd(n-2); -} -int f_even(int n) { -return (n == 0)? 0: f_odd(n-1) + f_even(n-2); -} -int main() { -int n = 10; -int r; -r = fibonacci(n); -printStr("fibo("); -printInt(n); -printStr(") = "); -printInt(r); -return 0; - -} \ No newline at end of file diff --git a/simpletest.nc b/simpletest.nc index 1d3aa20..7cb1b43 100644 --- a/simpletest.nc +++ b/simpletest.nc @@ -1,7 +1,7 @@ int GLOB = 1; char POPPING_thing = 'c'; -void printf(); +void printf(char *c, int argv); int main(int argc, char *argv) { int i = GLOB; diff --git a/testfiblist.nc b/testfiblist.nc new file mode 100644 index 0000000..66f33f2 --- /dev/null +++ b/testfiblist.nc @@ -0,0 +1,45 @@ +// assume these work, for a moment please +void* malloc(int size); +void free(void *block); +int printf(char *fmt, int d); // no variadics 😔 +int atoi(char *ascii); + +int *make_fib_list(int a, int b, int n) { + if (n < 2) return 0; + + int *list = malloc(n * 4); + + int i; + list[0] = a; + list[1] = b; + + for (i = 2; i < n; i = i + 1) { + list[i] = list[i - 1] + list[i - 2]; + i = i; + if (i == i && n && a || b && (n < 10 || 5)) { + printf("nothing went wrong!", 0); + int port = 10 + 'c'; + } else { + port = 15 + ':d'; + printf("something went wrong :(", 0); + } + } + + return list; +} + +int main(int argc) { + char *argv[3]; // char *argv[] or char **argv not possible 😢 + + int n = argc; + + n = n ? n : argc; + n = argc; + + int *list = make_fib_list(3, 6, n); + + int i; + for (i = 0; i < n; i = i + 1) printf("%d, ", list[i]); + + printf("\n", 0); +} \ No newline at end of file diff --git a/testthing.nc b/testthing.nc index e359f74..e8a8935 100644 --- a/testthing.nc +++ b/testthing.nc @@ -1,13 +1,7 @@ int a = 5 + 3 + "garbo king"; int d = a + 5; -int *make_fib_list(int a, int d, char *thing, void *list_copied); +int *make_fib_list(int a, int b, int n); int b = 110 + 'c' + "garbo king" + a; void garbo(); -char c = 352[10] + 12 * 32 - 3 * 4 * "okiii"; -void garbo(); - -int *make_fib_list(int a, char d, int *af) { - int car = "dream_machine" + a; - garbo(); -// int thing = 10 -} \ No newline at end of file +char c = (352[10] + 12) * 32 - 3 * 4 * "okiii"; +void garbo(); \ No newline at end of file