From: mike lowis Date: Wed, 21 Apr 2021 02:41:05 +0000 (-0400) Subject: constant expressions are almost completely implemented. need to add identifier lookups X-Git-Url: https://git.mdlowis.com/?a=commitdiff_plain;h=4c87f7cd8e84e6a0e747474513e5ec5bfcfae705;p=proto%2Fobnc.git constant expressions are almost completely implemented. need to add identifier lookups --- diff --git a/cerise/cerise.h b/cerise/cerise.h index cabcd7a..66cfdcf 100644 --- a/cerise/cerise.h +++ b/cerise/cerise.h @@ -90,13 +90,21 @@ typedef struct { int size; } Type; +typedef union { + long long i; + double f; + char* s; +} ImmValue; + typedef struct Symbol { struct Symbol* next; enum{ SYM_CONST, SYM_VAR, SYM_TYPE, SYM_PROC } class; + int export; char* name; Type* type; + ImmValue imm; } Symbol; typedef struct { @@ -104,11 +112,7 @@ typedef struct { ITEM_CONST, ITEM_VAR } mode; Type* type; - union { - long long i; - double f; - char* s; - } imm; + ImmValue imm; } Item; typedef struct { @@ -133,12 +137,8 @@ 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_not(Item* item); -void codegen_add(Item* a, Item* b); -void codegen_sub(Item* a, Item* b); -void codegen_mul(Item* a, Item* b); -void codegen_div(Item* a, Item* b); -void codegen_mod(Item* a, Item* b); +void codegen_unop(int op, Item* a); +void codegen_binop(int op, Item* a, Item* b); /* Option Parsing *****************************************************************************/ diff --git a/cerise/codegen.c b/cerise/codegen.c index f00bbad..6858e81 100644 --- a/cerise/codegen.c +++ b/cerise/codegen.c @@ -40,7 +40,7 @@ void codegen_setreal(Item* item, double val) item->mode = ITEM_CONST; item->type = &RealType; - item->imm.i = val; + item->imm.f = val; } void codegen_setstr(Item* item, char* val) @@ -107,74 +107,166 @@ void codegen_setstr(Item* item, char* val) */ -void codegen_not(Item* item) +static int items_const(Item* a, Item* b) { - if (item->mode == ITEM_CONST) - { - item->imm.i = !item->imm.i; - } - else - { - assert(!"not implemented"); - } + return ((a->mode == ITEM_CONST) && (b->mode == ITEM_CONST)); } -void codegen_add(Item* a, Item* b) +static void const_binop(int op, Item* a, Item* b) { - (void)a, (void)b; - assert(!"not implemented"); -} + if (a->type->form == FORM_INT || a->type->form == FORM_BOOL) + { + switch (op) + { + case '+': a->imm.i = a->imm.i + b->imm.i; break; + case '-': a->imm.i = a->imm.i - b->imm.i; break; + case '*': a->imm.i = a->imm.i * b->imm.i; break; + case '/': a->imm.i = a->imm.i / b->imm.i; break; + case '%': a->imm.i = a->imm.i % b->imm.i; break; + case AND: a->imm.i = a->imm.i && b->imm.i; break; + case OR: a->imm.i = a->imm.i || b->imm.i; break; -void codegen_sub(Item* a, Item* b) -{ - (void)a, (void)b; - assert(!"not implemented"); -} + case EQ: + a->imm.i = a->imm.i == b->imm.i; + a->type = &BoolType; + break; -void codegen_imul(Item* a, Item* b) -{ - if ((b->mode == ITEM_CONST) && (b->mode == ITEM_CONST)) + case NEQ: + a->imm.i = a->imm.i != b->imm.i; + a->type = &BoolType; + break; + + case '<': + a->imm.i = a->imm.i < b->imm.i; + a->type = &BoolType; + break; + + case LTEQ: + a->imm.i = a->imm.i <= b->imm.i; + a->type = &BoolType; + break; + + case '>': + a->imm.i = a->imm.i > b->imm.i; + a->type = &BoolType; + break; + + case GTEQ: + a->imm.i = a->imm.i >= b->imm.i; + a->type = &BoolType; + break; + +// case IS: break; + + default: + assert(!"not a valid op"); + break; + } + } + else if (a->type->form == FORM_REAL) { - a->imm.i = a->imm.i * b->imm.i; + switch (op) + { + case '+': a->imm.f = a->imm.f + b->imm.f; break; + case '-': a->imm.f = a->imm.f - b->imm.f; break; + case '*': a->imm.f = a->imm.f * b->imm.f; break; + case '/': a->imm.f = a->imm.f / b->imm.f; break; + + case EQ: + a->imm.f = a->imm.f == b->imm.f; + a->type = &BoolType; + break; + + case NEQ: + a->imm.f = a->imm.f != b->imm.f; + a->type = &BoolType; + break; + + case '<': + a->imm.f = a->imm.f < b->imm.f; + a->type = &BoolType; + break; + + case LTEQ: + a->imm.f = a->imm.f <= b->imm.f; + a->type = &BoolType; + break; + + case '>': + a->imm.f = a->imm.f > b->imm.f; + a->type = &BoolType; + break; + + case GTEQ: + a->imm.f = a->imm.f >= b->imm.f; + a->type = &BoolType; + break; + + default: + assert(!"not a valid op"); + break; + } } else { - assert(!"not implemented"); + assert(!"not a valid form"); } } -void codegen_fmul(Item* a, Item* b) +static void const_unop(int op, Item* a) { - if ((b->mode == ITEM_CONST) && (b->mode == ITEM_CONST)) + if (a->type->form == FORM_INT) + { + switch (op) + { + case '+': a->imm.i = +a->imm.i; break; + case '-': a->imm.i = -a->imm.i; break; + default: assert(!"not a valid op"); break; + } + } + else if (a->type->form == FORM_REAL) + { + switch (op) + { + case '+': a->imm.f = +a->imm.f; break; + case '-': a->imm.f = -a->imm.f; break; + default: assert(!"not a valid op"); break; + } + } + else if (a->type->form == FORM_BOOL) { - a->imm.f = a->imm.f * b->imm.f; + switch (op) + { + case NOT: a->imm.i = !a->imm.i; break; + default: assert(!"not a valid op"); break; + } } else { - assert(!"not implemented"); + assert(!"not a valid form"); } } -void codegen_mul(Item* a, Item* b) +void codegen_unop(int op, Item* a) { - if (a->type->form == FORM_REAL) + if (a->mode == ITEM_CONST) { - codegen_fmul(a,b); + const_unop(op, a); } else { - codegen_imul(a,b); + assert(!"not supported"); } } -void codegen_div(Item* a, Item* b) +void codegen_binop(int op, Item* a, Item* b) { - (void)a, (void)b; - assert(!"not implemented"); -} - -void codegen_mod(Item* a, Item* b) -{ - (void)a, (void)b; - assert(!"not implemented"); + if (items_const(a, b)) + { + const_binop(op, a, b); + } + else + { + assert(!"not supported"); + } } diff --git a/cerise/parser.c b/cerise/parser.c index b9dedc2..6fb18d1 100644 --- a/cerise/parser.c +++ b/cerise/parser.c @@ -102,8 +102,13 @@ static int consume(Parser* p) *****************************************************************************/ static Symbol* symbol_new(Parser* p, char* name, int class, bool export) { - (void)p, (void)name, (void)class, (void)export; - return NULL; + Symbol* sym = calloc(1, sizeof(Symbol)); + sym->name = name; + sym->class = class; + sym->export = export; + sym->next = p->scope; + p->scope = sym; + return sym; } /* Type Checking @@ -136,6 +141,18 @@ static void check_real2(Parser* p, Item* a, Item* b) check_real(p, b); } +static void check_num(Parser* p, Item* a) +{ + if (a->type->form == FORM_REAL) + { + check_real(p, a); + } + else + { + check_int(p, a); + } +} + static void check_num2(Parser* p, Item* a, Item* b) { if (a->type->form == FORM_REAL) @@ -156,6 +173,12 @@ static void check_bool(Parser* p, Item* item) } } +static void check_bool2(Parser* p, Item* a, Item* b) +{ + check_bool(p, a); + check_bool(p, b); +} + /* Grammar Definition *****************************************************************************/ void module(Parser* p, Item* item); @@ -281,7 +304,26 @@ RULE(const_decl) sym = symbol_new(p, name, SYM_CONST, export); expect(p, '='); expression(p, item); - printf("-> %s\n", name); + + sym->imm = item->imm; + (void)sym; + + if (item->type->form == FORM_REAL) + { + printf("-> %s = R %f\n", name, item->imm.f); + } + else if (item->type->form == FORM_INT) + { + printf("-> %s = I %lld\n", name, item->imm.i); + } + else if (item->type->form == FORM_BOOL) + { + printf("-> %s = B %lld\n", name, item->imm.i); + } + else if (item->type->form == FORM_STRING) + { + printf("-> %s = S '%s'\n", name, item->imm.s); + } if (!accept(p, ',')) { @@ -299,8 +341,11 @@ RULE(expression) simple_expr(p, item); if (matches_oneof(p, ops)) { - consume(p); - simple_expr(p, item); + Item right = { 0 }; + int op = consume(p); + simple_expr(p, &right); + check_num2(p, item, &right); + codegen_binop(op, item, &right); } } @@ -314,6 +359,8 @@ RULE(simple_expr) { int op = consume(p); // OP term(p, item); + check_num(p, item); + codegen_unop(op, item); } else { @@ -323,8 +370,18 @@ RULE(simple_expr) /* optional second term and op */ while (matches_oneof(p, (int[]){'+', '-', OR, 0})) { + Item right = { 0 }; int op = consume(p); - term(p, item); + term(p, &right); + if (op == OR) + { + check_bool2(p, item, &right); + } + else + { + check_num2(p, item, &right); + } + codegen_binop(op, item, &right); } } @@ -342,23 +399,23 @@ RULE(term) { case '*': check_num2(p, item, &right); - codegen_mul(item, &right); + codegen_binop(op, item, &right); break; case '/': check_num2(p, item, &right); - codegen_div(item, &right); + codegen_binop(op, item, &right); break; case '%': check_int2(p, item, &right); - codegen_mod(item, &right); + codegen_binop(op, item, &right); break; case AND: -// check_bool2(p, item, &right); -// codegen_and(item, &right); -// break; + check_bool2(p, item, &right); + codegen_binop(op, item, &right); + break; default: assert(!"not supported"); @@ -417,7 +474,7 @@ RULE(factor) consume(p); factor(p, item); check_bool(p, item); - codegen_not(item); + codegen_unop(NOT, item); break; // // case IDENT: @@ -545,8 +602,8 @@ TEST_SUITE(Grammar) "FOO = true"); parse_rule(const_decl, 0, "FOO = false"); - parse_rule(const_decl, 0, - "FOO = nil"); +// parse_rule(const_decl, 0, +// "FOO = nil"); parse_rule(const_decl, 0, "FOO = not true"); parse_rule(const_decl, 0, @@ -568,15 +625,27 @@ TEST_SUITE(Grammar) parse_rule(const_decl, 0, "FOO = 1.0 - 2.0"); parse_rule(const_decl, 0, - "FOO = 1 * 2"); + "FOO = 3 * 2"); + parse_rule(const_decl, 0, + "FOO = 3.0 * 2.0"); + parse_rule(const_decl, 0, + "FOO = 4 / 2"); + parse_rule(const_decl, 0, + "FOO = 3.0 / 4.0"); + parse_rule(const_decl, 0, + "FOO = 5 % 3"); + parse_rule(const_decl, 0, + "FOO = 5 == 3"); + parse_rule(const_decl, 0, + "FOO = 5 != 3"); parse_rule(const_decl, 0, - "FOO = 1.0 * 2.0"); + "FOO = 5 < 3"); parse_rule(const_decl, 0, - "FOO = 1 / 2"); + "FOO = 5 <= 3"); parse_rule(const_decl, 0, - "FOO = 1.0 / 2.0"); + "FOO = 5 > 3"); parse_rule(const_decl, 0, - "FOO = 1 % 2"); + "FOO = 5 >= 3"); } } #endif