From 52d94bc4c4b69e3807dbeee4ad6911c8efbd69c2 Mon Sep 17 00:00:00 2001 From: "Michael D. Lowis" Date: Thu, 22 Apr 2021 16:12:28 -0400 Subject: [PATCH] got primitive code generation working for assignments --- cerise/build.sh | 4 +- cerise/cerise.h | 22 ++++- cerise/codegen.c | 195 ++++++++++++++++++++++++++++++++++++----- cerise/oberon0/OSG.Mod | 3 +- cerise/parser.c | 109 +++++++++++++---------- cerise/tests/Module.m | 19 +++- cerise/tests/Module.s | 25 ++++++ 7 files changed, 299 insertions(+), 78 deletions(-) create mode 100644 cerise/tests/Module.s diff --git a/cerise/build.sh b/cerise/build.sh index a6d65d1..e0a3c86 100755 --- a/cerise/build.sh +++ b/cerise/build.sh @@ -3,5 +3,7 @@ ctags -R & cc -g -D CERISE_TESTS -Wall -Wextra --std=c99 -o cerisec-test *.c \ && ./cerisec-test \ && cc -g -Wall -Wextra --std=c99 -o cerisec *.c \ - && ./cerisec tests/Module.m + && ./cerisec tests/Module.m | tee tests/Module.s \ + && cc -o Module tests/Module.s +rm Module #[ $? -gt 0 ] && printf "\a" diff --git a/cerise/cerise.h b/cerise/cerise.h index 5b6a02d..98bfe07 100644 --- a/cerise/cerise.h +++ b/cerise/cerise.h @@ -112,6 +112,7 @@ typedef struct { ITEM_CONST, ITEM_VAR } mode; Type* type; + int reg; ImmValue imm; } Item; @@ -129,14 +130,31 @@ void compile(char* fname); /* Code Generation *****************************************************************************/ +/* opcodes */ +enum AsmOp { + /* Assembly Operations */ + OP_LOAD = 0, OP_STORE, OP_MOVE, + OP_CMP, OP_ADD, OP_SUB, OP_MUL, OP_DIV, OP_MOD, + OP_EQ, OP_NEQ, OP_LT, OP_GT, OP_LTEQ, OP_GTEQ, + + OP_CALL, OP_RET, +}; + +enum Regs { + IMM = 0, + RAX, RBX, RCX, RDX, RBP, RSP, RSI, RDI, + R8, R9, R10, R11, R12, R13, R14, R15, +}; + extern Type BoolType, IntType, RealType, StringType; void codegen_setint(Item* item, Type* type, long long val); void codegen_setreal(Item* item, double val); void codegen_setstr(Item* item, char* val); -void codegen_unop(int op, Item* a); -void codegen_binop(int op, Item* a, Item* b); +void codegen_main(char* modname); void codegen_startproc(char* name, long long localsz); void codegen_endproc(void); +void codegen_unop(int op, Item* a); +void codegen_binop(int op, Item* a, Item* b); void codegen_store(Item* a, Item* b); diff --git a/cerise/codegen.c b/cerise/codegen.c index 5e2708f..08848ef 100644 --- a/cerise/codegen.c +++ b/cerise/codegen.c @@ -24,22 +24,25 @@ Type StringType = { void codegen_setint(Item* item, Type* type, long long val) { - item->mode = ITEM_CONST; - item->type = type; + item->mode = ITEM_CONST; + item->type = type; + item->reg = IMM; item->imm.i = val; } void codegen_setreal(Item* item, double val) { - item->mode = ITEM_CONST; - item->type = &RealType; + item->mode = ITEM_CONST; + item->type = &RealType; + item->reg = IMM; item->imm.f = val; } void codegen_setstr(Item* item, char* val) { - item->mode = ITEM_CONST; - item->type = &StringType; + item->mode = ITEM_CONST; + item->type = &StringType; + item->reg = IMM; item->imm.s = val; } @@ -183,6 +186,44 @@ static void const_unop(int op, Item* a) } } +void codegen_main(char* modname) +{ + codegen_startproc("main", 0); +// op_l (OP_CALL, modname); + printf(" call %s\n", modname); + codegen_endproc(); +} + +void codegen_startproc(char* name, long long localsz) +{ + printf(" .text\n"); + printf(" .globl %s\n", name); + printf("%s:\n", name); + +// op_r (OP_PUSH, RBP); + printf(" pushq %%rbp\n"); + if (localsz > 0) + { +// op_rr (OP_MOVE, RSP, RBP); + printf(" movq %%rsp, %%rbp\n"); +// op_ri (OP_SUB, localsz, RSP); + printf(" sub $%lld, %%rsp\n\n", localsz); + } + else + { +// op_rr (OP_MOVE, RSP, RBP); + printf(" movq %%rsp, %%rbp\n\n"); + } +} + +void codegen_endproc(void) +{ +// op_r (OP_POP, RBP); +// op_0 (OP_RET); + printf("\n pop %%rbp\n"); + printf(" ret\n\n"); +} + void codegen_unop(int op, Item* a) { if (a->mode == ITEM_CONST) @@ -207,26 +248,134 @@ void codegen_binop(int op, Item* a, Item* b) } } -void codegen_startproc(char* name, long long localsz) -{ - printf(" .text\n"); - printf(" .globl %s\n", name); - printf("%s:\n", name); - printf(" pushq %%rbp\n"); - printf(" movq %%rsp, %%rbp\n"); - if (localsz > 0) - { - printf(" sub $%lld, %%rsp\n", localsz); - } -} +/* + PROCEDURE GetSB; + BEGIN + IF curSB = 1 THEN + Put2(Ldw, SB, 0, pc-fixorgD); + fixorgD := pc-1; + curSB := 0 + END + END GetSB; -void codegen_endproc(void) -{ - printf(" pop %%rbp\n"); - printf(" ret\n"); -} + PROCEDURE load(VAR x: Item); + BEGIN + IF x.mode # Reg THEN + IF x.mode = Var THEN + IF x.r > 0 THEN (*local*) + Put2(Ldw, RH, SP, x.a) + ELSE + GetSB; + Put2(Ldw, RH, SB, x.a) + END ; + x.r := RH; + incR + ELSIF x.mode = Par THEN + Put2(Ldw, RH, x.r, x.a); + Put2(Ldw, RH, RH, 0); + x.r := RH; + incR + ELSIF x.mode = Const THEN + IF (x.a >= 10000H) OR (x.a < -10000H) THEN + OSS.Mark("const too large") + END ; + Put1(Mov, RH, 0, x.a); + x.r := RH; + incR + ELSIF x.mode = RegI THEN + Put2(Ldw, x.r, x.r, x.a) + ELSIF x.mode = Cond THEN + Put3(2, negated(x.r), 2); + FixLink(x.b); + Put1(Mov, RH, 0, 1); + Put3(2, 7, 1); + FixLink(x.a); + Put1(Mov, RH, 0, 0); + x.r := RH; + incR + END ; + x.mode := Reg + END + END load; + + PROCEDURE Store*(VAR x, y: Item); (* x := y *) + BEGIN + load(y); + IF x.mode = Var THEN + IF x.r > 0 THEN (*local*) + Put2(Stw, y.r, SP, x.a) + ELSE + GetSB; + Put2(Stw, y.r, SB, x.a) + END + ELSIF x.mode = Par THEN + Put2(Ldw, RH, SP, x.a); + Put2(Stw, y.r, RH, x.b) + ELSIF x.mode = RegI THEN + Put2(Stw, y.r, x.r, x.a); + DEC(RH) + ELSE + OSS.Mark("illegal assignment") + END ; + DEC(RH) + END Store; + +*/ void codegen_store(Item* a, Item* b) { + if (a->mode == ITEM_VAR && b->reg == IMM) + { + printf(" movq $%lld, %s(%%rip)\n", b->imm.i, a->imm.s); + } (void)a, (void)b; } + + +/* + +add %r10,%r11 // add r10 and r11, put result in r11 +add $5,%r10 // add 5 to r10, put result in r10 +call label // call a subroutine / function / procedure +cmp %r10,%r11 // compare register r10 with register r11. The comparison sets flags in the processor status register which affect conditional jumps. +cmp $99,%r11 // compare the number 99 with register r11. The comparison sets flags in the processor status register which affect conditional jumps. +div %r10 // divide rax by the given register (r10), places quotient into rax and remainder into rdx (rdx must be zero before this instruction) +inc %r10 // increment r10 +jmp label // jump to label +je label // jump to label if equal +jne label // jump to label if not equal +jl label // jump to label if less +jg label // jump to label if greater +mov %r10,%r11 // move data from r10 to r11 +mov $99,%r10 // put the immediate value 99 into r10 +mov %r10,(%r11) // move data from r10 to address pointed to by r11 +mov (%r10),%r11 // move data from address pointed to by r10 to r10 +mul %r10 // multiplies rax by r10, places result in rax and overflow in rdx +push %r10 // push r10 onto the stack +pop %r10 // pop r10 off the stack +ret // routine from subroutine (counterpart to call) +syscall // invoke a syscall (in 32-bit mode, use "int $0x80" instead) + +*/ + +//static void emit_op0(AsmOp op) +//{ +//} +// +//static void emit_opreg1(AsmOp op, long long reg) +//{ +//} +// +//static void emit_opimmi(AsmOp op, long long imm) +//{ +//} +// +//static void emit_opimmf(AsmOp op, double imm) +//{ +//} +// +//static void emit_opreg2(AsmOp op, int rega, int regb) +//{ +//} + + diff --git a/cerise/oberon0/OSG.Mod b/cerise/oberon0/OSG.Mod index 29e8753..9e4b750 100644 --- a/cerise/oberon0/OSG.Mod +++ b/cerise/oberon0/OSG.Mod @@ -331,7 +331,8 @@ MODULE OSG; (* NW 19.12.94 / 20.10.07 / OSGX 9.5.2017*) END Relation; PROCEDURE Store*(VAR x, y: Item); (* x := y *) - BEGIN load(y); + BEGIN + load(y); IF x.mode = Var THEN IF x.r > 0 THEN (*local*) Put2(Stw, y.r, SP, x.a) ELSE GetSB; Put2(Stw, y.r, SB, x.a) END ELSIF x.mode = Par THEN Put2(Ldw, RH, SP, x.a); Put2(Stw, y.r, RH, x.b) diff --git a/cerise/parser.c b/cerise/parser.c index 5a5e20c..c315d8d 100644 --- a/cerise/parser.c +++ b/cerise/parser.c @@ -247,6 +247,10 @@ static void check_types(Parser* p, Item* a, Item* b) { check_ints(p, a, b); } + else if (a->type->form == FORM_BOOL) + { + check_bools(p, a, b); + } else { error(p, "type mismatch"); @@ -447,35 +451,43 @@ RULE(expression) RULE(var_decl) { (void)item; - int nsyms = 0; - Symbol* sym = NULL; - Symbol* type = NULL; - char* name = NULL; - bool export = false; - while (1) { + int nsyms = 0; + Symbol* sym = NULL; + Symbol* type = NULL; + char* name = NULL; + bool export = false; + + while (1) + { + name = expect_text(p, IDENT); + export = accept(p, '*'); + sym = symbol_new(p, name, SYM_VAR, export); + nsyms++; + + if (!accept(p, ',')) + { + break; + } + } + + expect(p, ':'); name = expect_text(p, IDENT); - export = accept(p, '*'); - sym = symbol_new(p, name, SYM_VAR, export); - nsyms++; + type = symbol_get(p, SYM_TYPE, name); + + /* apply the type to the newly created symbols */ + for (int i = 0; i < nsyms; i++) + { + sym->type = type->type; + sym = sym->next; + } if (!accept(p, ',')) { break; } } - - expect(p, ':'); - name = expect_text(p, IDENT); - type = symbol_get(p, SYM_TYPE, name); - - /* apply the type to the newly created symbols */ - for (int i = 0; i < nsyms; i++) - { - sym->type = type->type; - sym = sym->next; - } } RULE(type_decl) @@ -558,32 +570,41 @@ END RULE(statement_seq) { - if (matches(p, IDENT)) + while (1) { - Item right = { 0 }; - char* text = expect_text(p, IDENT); - if (accept(p, '=')) + if (matches(p, IDENT)) + { + Item right = { 0 }; + char* text = expect_text(p, IDENT); + if (accept(p, '=')) + { + Symbol* sym = symbol_get(p, SYM_VAR, text); + init_item(item, sym); + item->imm.s = sym->name; + + expression(p, &right); + check_types(p, item, &right); + codegen_store(item, &right); + } + else + { + /* TODO: add function calls and other complex stuff */ + error(p, "expected assignment"); + } + } + else if (matches(p, IF)) { - Symbol* sym = symbol_get(p, SYM_VAR, text); - init_item(item, sym); - expression(p, &right); - check_types(p, item, &right); - codegen_store(item, &right); } else { - /* TODO: add function calls and other complex stuff */ - error(p, "expected assignment"); + error(p, "expected a statement"); + } + expect(p, ';'); + if (matches_oneof(p, (int[]){END, 0})) + { + break; } } - else if (matches(p, IF)) - { - } - else - { - error(p, "expected a statement"); - } - expect(p, ';'); } RULE(declaration_seq) @@ -693,15 +714,7 @@ void compile(char* fname) }, &(Item){0} ); - - printf(" .text\n"); - printf(" .globl main\n"); - printf("main:\n"); - printf(" pushq %%rbp\n"); - printf(" movq %%rsp, %%rbp\n"); - printf(" call Module\n"); - printf(" pop %%rbp\n"); - printf(" ret\n"); + codegen_main("Module"); } /* Grammar Unit Tests diff --git a/cerise/tests/Module.m b/cerise/tests/Module.m index 7eefeac..1b9e811 100644 --- a/cerise/tests/Module.m +++ b/cerise/tests/Module.m @@ -1,6 +1,19 @@ module Module; -const FOO = 42; -var a : Int; + +const + A = true, + B = 42 + ; + +var + a : Bool, + b : Int + ; + begin - a = FOO * 3; + a = true; + a = A; + b = 24; + b = B; +# c = a + b; end Module; diff --git a/cerise/tests/Module.s b/cerise/tests/Module.s new file mode 100644 index 0000000..91f16b4 --- /dev/null +++ b/cerise/tests/Module.s @@ -0,0 +1,25 @@ + .text + .globl Module +Module: + pushq %rbp + movq %rsp, %rbp + + movq $1, a(%rip) + movq $1, a(%rip) + movq $24, b(%rip) + movq $42, b(%rip) + + pop %rbp + ret + + .text + .globl main +main: + pushq %rbp + movq %rsp, %rbp + + call Module + + pop %rbp + ret + -- 2.49.0