From 73bd205e38ab03fe3d76403f25300ccfe6433903 Mon Sep 17 00:00:00 2001 From: "Michael D. Lowis" Date: Wed, 21 Apr 2021 13:55:34 -0400 Subject: [PATCH] rearranged grammar to minimize need for forward declarations --- cerise/cerise.h | 4 +- cerise/codegen.c | 113 +++------ cerise/examples/square.c | 5 + cerise/oberon0/OSG.Mod | 6 +- cerise/parser.c | 497 +++++++++++++++++---------------------- 5 files changed, 263 insertions(+), 362 deletions(-) create mode 100644 cerise/examples/square.c diff --git a/cerise/cerise.h b/cerise/cerise.h index 66cfdcf..08df7eb 100644 --- a/cerise/cerise.h +++ b/cerise/cerise.h @@ -125,7 +125,6 @@ typedef struct { void lexfile(Parser* ctx, char* path); void lex(Parser* ctx); void lexprintpos(Parser* p, FILE* file, Tok* tok); -void gettoken(Parser* ctx); void module(Parser* p, Item* item); /* Code Generation @@ -136,9 +135,10 @@ 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_startproc(long long localsz); +void codegen_endproc(void); /* Option Parsing *****************************************************************************/ diff --git a/cerise/codegen.c b/cerise/codegen.c index 6858e81..94d8319 100644 --- a/cerise/codegen.c +++ b/cerise/codegen.c @@ -24,11 +24,6 @@ Type StringType = { void codegen_setint(Item* item, Type* type, long long val) { - if (type == &BoolType) - printf("%s ", val ? "true" : "false"); - else - printf("%lld ", val); - item->mode = ITEM_CONST; item->type = type; item->imm.i = val; @@ -36,8 +31,6 @@ void codegen_setint(Item* item, Type* type, long long val) void codegen_setreal(Item* item, double val) { - printf("%f ", val); - item->mode = ITEM_CONST; item->type = &RealType; item->imm.f = val; @@ -45,68 +38,11 @@ void codegen_setreal(Item* item, double val) void codegen_setstr(Item* item, char* val) { - printf("'%s' ", val); - item->mode = ITEM_CONST; item->type = &StringType; item->imm.s = val; } -/* I do not "get" this code - PROCEDURE MakeConstItem*(VAR x: Item; typ: Type; val: LONGINT); - BEGIN - x.mode := Const; - x.type := typ; - x.a := val - END MakeConstItem; - - PROCEDURE negated(cond: LONGINT): LONGINT; - BEGIN - IF cond < 8 THEN - cond := cond+8 - ELSE - cond := cond-8 - END ; - RETURN cond - END negated; - - PROCEDURE Not*(VAR x: Item); (* x := ~x *) - VAR t: LONGINT; - BEGIN - IF x.mode # Cond THEN loadCond(x) END ; - x.r := negated(x.r); - t := x.a; - x.a := x.b; - x.b := t - END Not; - - - PROCEDURE MulOp*(VAR x, y: Item); (* x := x * y *) - BEGIN - IF (x.mode = Const) & (y.mode = Const) THEN - x.a := x.a * y.a - ELSIF (y.mode = Const) & (y.a = 2) THEN - load(x); - Put1(Lsl, x.r, x.r, 1) - ELSIF y.mode = Const THEN - load(x); - Put1(Mul, x.r, x.r, y.a) - ELSIF x.mode = Const THEN - load(y); - Put1(Mul, y.r, y.r, x.a); - x.mode := Reg; - x.r := y.r - ELSE - load(x); - load(y); - Put0(Mul, RH-2, x.r, y.r); - DEC(RH); - x.r := RH-1 - END - END MulOp; - -*/ - static int items_const(Item* a, Item* b) { return ((a->mode == ITEM_CONST) && (b->mode == ITEM_CONST)); @@ -126,40 +62,40 @@ static void const_binop(int op, Item* a, Item* b) case AND: a->imm.i = a->imm.i && b->imm.i; break; case OR: a->imm.i = a->imm.i || b->imm.i; break; - case EQ: - a->imm.i = a->imm.i == b->imm.i; + case EQ: + a->imm.i = a->imm.i == b->imm.i; a->type = &BoolType; break; case NEQ: - a->imm.i = a->imm.i != b->imm.i; + a->imm.i = a->imm.i != b->imm.i; a->type = &BoolType; break; case '<': - a->imm.i = a->imm.i < b->imm.i; + 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->imm.i = a->imm.i <= b->imm.i; a->type = &BoolType; break; case '>': - a->imm.i = a->imm.i > b->imm.i; + 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->imm.i = a->imm.i >= b->imm.i; a->type = &BoolType; break; // case IS: break; - default: - assert(!"not a valid op"); + default: + assert(!"not a valid op"); break; } } @@ -172,38 +108,38 @@ static void const_binop(int op, Item* a, Item* b) 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; + 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->imm.f = a->imm.f != b->imm.f; a->type = &BoolType; break; case '<': - a->imm.f = a->imm.f < b->imm.f; + 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->imm.f = a->imm.f <= b->imm.f; a->type = &BoolType; break; case '>': - a->imm.f = a->imm.f > b->imm.f; + 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->imm.f = a->imm.f >= b->imm.f; a->type = &BoolType; break; - default: - assert(!"not a valid op"); + default: + assert(!"not a valid op"); break; } } @@ -270,3 +206,16 @@ void codegen_binop(int op, Item* a, Item* b) assert(!"not supported"); } } + +void codegen_startproc(long long localsz) +{ + printf(" pushq rbp\n"); + printf(" movq rsp, rbp\n"); + printf(" sub $%lld, rsp\n", localsz); +} + +void codegen_endproc(void) +{ + printf(" pop rbp"); + printf(" ret"); +} diff --git a/cerise/examples/square.c b/cerise/examples/square.c new file mode 100644 index 0000000..751e42a --- /dev/null +++ b/cerise/examples/square.c @@ -0,0 +1,5 @@ +// Type your code here, or load an example. +int square(int num) { + volatile int foo[4]; + return num * num; +} diff --git a/cerise/oberon0/OSG.Mod b/cerise/oberon0/OSG.Mod index f7c15dd..f54a5c1 100644 --- a/cerise/oberon0/OSG.Mod +++ b/cerise/oberon0/OSG.Mod @@ -432,7 +432,11 @@ MODULE OSG; (* NW 19.12.94 / 20.10.07 / OSGX 9.5.2017*) END Open; PROCEDURE Header*(size: LONGINT); - BEGIN entry := pc*4; Put1(Sub, SP, SP, 4); Put2(Stw, LNK, SP, 0); invalSB + BEGIN + entry := pc*4; + Put1(Sub, SP, SP, 4); + Put2(Stw, LNK, SP, 0); + invalSB END Header; PROCEDURE MakeFileName(VAR FName: OSS.Ident; name, ext: ARRAY OF CHAR); diff --git a/cerise/parser.c b/cerise/parser.c index bdebddb..a5a9f69 100644 --- a/cerise/parser.c +++ b/cerise/parser.c @@ -16,6 +16,28 @@ void name(Parser* p, Item* item) #endif +/* Default Symbols + *****************************************************************************/ +static Symbol BoolSym = { + .class = SYM_TYPE, + .name = "Bool", + .type = &BoolType +}; + +static Symbol IntSym = { + .next = &BoolSym, + .class = SYM_TYPE, + .name = "Int", + .type = &IntType +}; + +static Symbol RealSym = { + .next = &IntSym, + .class = SYM_TYPE, + .name = "Real", + .type = &RealType +}; + /* Parsing Routines *****************************************************************************/ static Tok* peek(Parser* p) @@ -195,179 +217,144 @@ static void check_bool2(Parser* p, Item* a, Item* b) /* Grammar Definition *****************************************************************************/ -void module(Parser* p, Item* item); -void import_list(Parser* p, Item* item); -void declaration_seq(Parser* p, Item* item); -void statement_seq(Parser* p, Item* item); -void const_decl(Parser* p, Item* item); -void expression(Parser* p, Item* item); -void simple_expr(Parser* p, Item* item); -void term(Parser* p, Item* item); -void factor(Parser* p, Item* item); -void designator(Parser* p, Item* item); -void qualident(Parser* p, Item* item); -void expr_list(Parser* p, Item* item); -RULE(module) -{ - expect(p, MODULE); - char* sname = expect_text(p, IDENT); - /* TODO: Check that it matches filename here */ - expect(p, ';'); - if (matches(p, IMPORT)) - { - import_list(p, item); - } - declaration_seq(p, item); - if (accept(p, BEGIN)) - { - statement_seq(p, item); - } - expect(p, END); - char* ename = expect_text(p, IDENT); - if (strcmp(sname, ename)) - { - error(p, "Expected module name '%s', recieved '%s' instead", sname, ename); - } - expect(p, ';'); -} +static void expression(Parser* p, Item* item); -RULE(import_list) -{ - (void)item; - expect(p, IMPORT); - while (1) - { - expect(p, IDENT); - if (accept(p, '=')) - { - expect(p, IDENT); - } - if (matches(p, ';')) - { - break; - } - expect(p, ','); - } - expect(p, ';'); -} +//RULE(expr_list) +//{ +// while (1) +// { +// expression(p); +// if (!accept(p, ',')) +// { +// break; +// } +// } +//} -RULE(declaration_seq) +RULE(qualident) { - if (accept(p, CONST)) - { - const_decl(p, item); - expect(p, ';'); - } - if (accept(p, TYPE)) - { -// type_decl(p, item); - expect(p, ';'); - } - if (accept(p, VAR)) + char* name = expect_text(p, IDENT); + Symbol* sym = symbol_get(p, name); + + if (sym->class == SYM_CONST) { -// var_decl(p, item); - expect(p, ';'); + item->mode = ITEM_CONST; + item->imm = sym->imm; } +// if (accept(p, '.')) +// { +// expect(p, IDENT); +// } } -RULE(statement_seq) +RULE(designator) { - (void)p, (void)item; + qualident(p, item); +// /* selector */ +// switch ((int)peek(p)->type) +// { +// case '.': +// expect(p, IDENT); +// break; +// +// case '[': +// expr_list(p); +// expect(p, ']'); +// break; +// +// case '^': +// expect(p, '^'); +// break; +// +// case '(': +// qualident(p); +// expect(p, ')'); +// break; +// } } -RULE(const_decl) +RULE(factor) { -/* - VAR - obj, first: OSG.Object; - x: OSG.Item; - tp: OSG.Type; - L: LONGINT; - - (* ... *) - - WHILE sym = OSS.ident DO - NewObj(obj, OSG.Const); - OSS.Get(sym); - IF sym = OSS.eql THEN - OSS.Get(sym) - ELSE - OSS.Mark("=?") - END; - expression(x); - IF x.mode = OSG.Const THEN - obj.val := x.a; - obj.type := x.type - ELSE - OSS.Mark("expression not constant") - END ; - Check(OSS.semicolon, "; expected") - END -*/ + switch ((int)peek(p)->type) + { + case INT: + codegen_setint(item, &IntType, peek(p)->value.integer); + consume(p); + break; + case REAL: + codegen_setreal(item, peek(p)->value.floating); + consume(p); + break; - while (1) - { - char* name = NULL; - bool export = false; - Symbol* sym = NULL; + case STRING: + codegen_setstr(item, peek(p)->text); + consume(p); + break; - name = expect_text(p, IDENT); - export = accept(p, '*'); - sym = symbol_new(p, name, SYM_CONST, export); - expect(p, '='); - expression(p, item); +// case NIL: +// codegen_nil(item); +// consume(p); +// break; - sym->imm = item->imm; - (void)sym; + case BOOL: + codegen_setint(item, &BoolType, peek(p)->value.integer); + consume(p); + break; - 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); - } + case '(': + expect(p, '('); + expression(p, item); + expect(p, ')'); + break; - if (!accept(p, ',')) - { + case NOT: + consume(p); + factor(p, item); + check_bool(p, item); + codegen_unop(NOT, item); + break; + + case IDENT: + designator(p, item); +// actual_params(p); break; - } } } -RULE(expression) +RULE(term) { - // expression = SimpleExpression [relation SimpleExpression]. - // relation = "=" | "!=" | "<" | "<=" | ">" | ">=" | "is". + factor(p, item); - int ops[] = { EQ, NEQ, '<', LTEQ, '>', GTEQ, IS, 0 }; - simple_expr(p, item); - if (matches_oneof(p, ops)) + while (matches_oneof(p, (int[]){'*', '/', '%', AND, 0})) { Item right = { 0 }; int op = consume(p); - simple_expr(p, &right); - check_num2(p, item, &right); - codegen_binop(op, item, &right); + factor(p, &right); + switch(op) + { + case '*': + case '/': + case '%': + check_num2(p, item, &right); + codegen_binop(op, item, &right); + break; + + case AND: + check_bool2(p, item, &right); + codegen_binop(op, item, &right); + break; + + default: + assert(!"not supported"); + break; + } } } RULE(simple_expr) { - // SimpleExpression = ["+" | "-"] term {AddOperator term}. - // AddOperator = "+" | "-" | "or". - /* first term and +/- */ if (matches_oneof(p, (int[]){'+', '-', 0})) { @@ -399,166 +386,121 @@ RULE(simple_expr) } } -RULE(term) +RULE(expression) { - // term = factor {MulOperator factor}. - // MulOperator = "*" | "/" | "and". - factor(p, item); - while (matches_oneof(p, (int[]){'*', '/', '%', AND, 0})) + int ops[] = { EQ, NEQ, '<', LTEQ, '>', GTEQ, IS, 0 }; + simple_expr(p, item); + if (matches_oneof(p, ops)) { Item right = { 0 }; int op = consume(p); - factor(p, &right); - switch(op) - { - case '*': - check_num2(p, item, &right); - codegen_binop(op, item, &right); - break; - - case '/': - check_num2(p, item, &right); - codegen_binop(op, item, &right); - break; - - case '%': - check_int2(p, item, &right); - codegen_binop(op, item, &right); - break; - - case AND: - check_bool2(p, item, &right); - codegen_binop(op, item, &right); - break; - - default: - assert(!"not supported"); - break; - } + simple_expr(p, &right); + check_num2(p, item, &right); + codegen_binop(op, item, &right); } } -/* -factor = number - | string - | "nil" - | "true" - | "false" - | designator [ActualParameters] - | "(" expression ")" - | "not" factor. -*/ - -RULE(factor) +RULE(var_decl) { - switch ((int)peek(p)->type) - { - case INT: - codegen_setint(item, &IntType, peek(p)->value.integer); - consume(p); - break; - - case REAL: - codegen_setreal(item, peek(p)->value.floating); - consume(p); - break; - - case STRING: - codegen_setstr(item, peek(p)->text); - consume(p); - break; - -// case NIL: -// codegen_nil(item); -// consume(p); -// break; + (void)p, (void)item; +} - case BOOL: - codegen_setint(item, &BoolType, peek(p)->value.integer); - consume(p); - break; +RULE(type_decl) +{ + (void)p, (void)item; +} - case '(': - expect(p, '('); - expression(p, item); - expect(p, ')'); - break; +RULE(const_decl) +{ + while (1) + { + char* name = NULL; + bool export = false; + Symbol* sym = NULL; - case NOT: - consume(p); - factor(p, item); - check_bool(p, item); - codegen_unop(NOT, item); - break; + name = expect_text(p, IDENT); + export = accept(p, '*'); + sym = symbol_new(p, name, SYM_CONST, export); + expect(p, '='); + expression(p, item); + sym->imm = item->imm; - case IDENT: - designator(p, item); -// actual_params(p); + if (!accept(p, ',')) + { break; + } } } -/* - designator = qualident {selector}. - selector = "." ident | "[" ExpList "]" | "^" | "(" qualident ")". - ExpList = expression {"," expression}. - qualident = [ident "."] ident. +RULE(statement_seq) +{ + (void)p, (void)item; +} - ActualParameters = "(" [ExpList] ")" . -*/ -RULE(designator) +RULE(declaration_seq) { - qualident(p, item); -// /* selector */ -// switch ((int)peek(p)->type) -// { -// case '.': -// expect(p, IDENT); -// break; -// -// case '[': -// expr_list(p); -// expect(p, ']'); -// break; -// -// case '^': -// expect(p, '^'); -// break; -// -// case '(': -// qualident(p); -// expect(p, ')'); -// break; -// } + if (accept(p, CONST)) + { + const_decl(p, item); + expect(p, ';'); + } + if (accept(p, TYPE)) + { +// type_decl(p, item); + expect(p, ';'); + } + if (accept(p, VAR)) + { +// var_decl(p, item); + expect(p, ';'); + } } -RULE(qualident) +RULE(import_list) { - char* name = expect_text(p, IDENT); - Symbol* sym = symbol_get(p, name); + (void)item; + expect(p, IMPORT); + while (1) + { + expect(p, IDENT); + if (accept(p, '=')) + { + expect(p, IDENT); + } + if (matches(p, ';')) + { + break; + } + expect(p, ','); + } + expect(p, ';'); +} - if (sym->class == SYM_CONST) +RULE(module) +{ + expect(p, MODULE); + char* sname = expect_text(p, IDENT); + /* TODO: Check that it matches filename here */ + expect(p, ';'); + if (matches(p, IMPORT)) { - item->mode = ITEM_CONST; - item->imm = sym->imm; + import_list(p, item); } -// if (accept(p, '.')) -// { -// expect(p, IDENT); -// } + declaration_seq(p, item); + if (accept(p, BEGIN)) + { + codegen_startproc(0); + statement_seq(p, item); + codegen_endproc(); + } + expect(p, END); + char* ename = expect_text(p, IDENT); + if (strcmp(sname, ename)) + { + error(p, "Expected module name '%s', recieved '%s' instead", sname, ename); + } + expect(p, ';'); } -// -//RULE(expr_list) -//{ -// while (1) -// { -// expression(p); -// if (!accept(p, ',')) -// { -// break; -// } -// } -//} /* Grammar Unit Tests *****************************************************************************/ @@ -567,9 +509,10 @@ RULE(qualident) Parser Ctx = {0}; -void parse_init(char* fname, char* string) +static void parse_init(char* fname, char* string) { memset(&Ctx, 0, sizeof(Ctx)); + Ctx.scope = &RealSym; LexFile* file = calloc(sizeof(LexFile), 1u); file->path = strdup(fname); file->fbeg = file->fpos = strdup(string); -- 2.49.0