X-Git-Url: https://ocean-lang.org/code/?p=ocean;a=blobdiff_plain;f=csrc%2Foceani.mdc;h=97c195382cd8955c4e0c16e154125e5d7fa2e93b;hp=ce70c49e2b6231240905d843456be054ef10ab3d;hb=1dd9f61bbc7e8890b5407ba084793817e55fe502;hpb=5f0e03bbf143c52ef1cbc0c5b9e4910f6cbac291 diff --git a/csrc/oceani.mdc b/csrc/oceani.mdc index ce70c49..97c1953 100644 --- a/csrc/oceani.mdc +++ b/csrc/oceani.mdc @@ -123,6 +123,9 @@ structures can be used. #define config2context(_conf) container_of(_conf, struct parse_context, \ config) +###### Parser: reduce + struct parse_context *c = config2context(config); + ###### Parser: code #include @@ -148,8 +151,8 @@ structures can be used. ## core functions #include - static char Usage[] = "Usage: oceani --trace --print --noexec --brackets" - "--section=SectionName prog.ocn\n"; + static char Usage[] = + "Usage: oceani --trace --print --noexec --brackets --section=SectionName prog.ocn\n"; static const struct option long_options[] = { {"trace", 0, NULL, 't'}, {"print", 0, NULL, 'p'}, @@ -168,9 +171,8 @@ structures can be used. char *section = NULL; struct parse_context context = { .config = { - .ignored = (1 << TK_line_comment) - | (1 << TK_block_comment), - .number_chars = ".,_+-", + .ignored = (1 << TK_mark), + .number_chars = ".,_+- ", .word_start = "_", .word_cont = "_", }, @@ -629,8 +631,8 @@ there are errors. ###### includes #include - #include "string.h" - #include "number.h" + #include "parse_string.h" + #include "parse_number.h" ###### libs myLDLIBS := libnumber.o libstring.o -lgmp @@ -1001,7 +1003,8 @@ like "if" and the code following it. ###### Grammar $void - OpenScope -> ${ scope_push(config2context(config)); }$ + OpenScope -> ${ scope_push(c); }$ + ClosePara -> ${ var_block_close(c, CloseParallel); }$ Each variable records a scope depth and is in one of four states: @@ -1034,7 +1037,6 @@ Each variable records a scope depth and is in one of four states: in scope. It is permanently out of scope now and can be removed from the "in scope" stack. - ###### variable fields int depth, min_depth; enum { OutScope, PendingScope, CondScope, InScope } scope; @@ -1093,7 +1095,7 @@ list of in_scope names. v = t->previous; free_value(t->val); - if (t->min_depth == 0) + if (t->depth == 0) // This is a global constant free_exec(t->where_decl); free(t); @@ -1455,7 +1457,9 @@ propagation is needed. ###### core functions static struct type *propagate_types(struct exec *prog, struct parse_context *c, int *ok, - struct type *type, int rules) + struct type *type, int rules); + static struct type *__propagate_types(struct exec *prog, struct parse_context *c, int *ok, + struct type *type, int rules) { struct type *t; @@ -1476,6 +1480,16 @@ propagation is needed. return Tnone; } + static struct type *propagate_types(struct exec *prog, struct parse_context *c, int *ok, + struct type *type, int rules) + { + struct type *ret = __propagate_types(prog, c, ok, type, rules); + + if (c->parse_error) + *ok = 0; + return ret; + } + #### Interpreting Interpreting an `exec` doesn't require anything but the `exec`. State @@ -1491,7 +1505,6 @@ in `val` or the pointer to a value in `lval`. If `lval` is set, but a simple value is required, `inter_exec()` will dereference `lval` to get the value. - ###### core functions struct lrval { @@ -1664,7 +1677,6 @@ make a copy of an array with controllable depth. $0->array.member = $<4; $0->array.vsize = NULL; { - struct parse_context *c = config2context(config); char tail[3]; mpq_t num; if (number_parse(num, tail, $2.txt) == 0) @@ -1687,13 +1699,12 @@ make a copy of an array with controllable depth. }$ | [ IDENTIFIER ] Type ${ { - struct parse_context *c = config2context(config); struct variable *v = var_ref(c, $2.txt); if (!v) - tok_err(config2context(config), "error: name undeclared", &$2); + tok_err(c, "error: name undeclared", &$2); else if (!v->constant) - tok_err(config2context(config), "error: array size must be a constant", &$2); + tok_err(c, "error: array size must be a constant", &$2); $0 = calloc(1, sizeof(struct type)); *($0) = array_prototype; @@ -1732,9 +1743,9 @@ make a copy of an array with controllable depth. ###### print binode cases case Index: - print_exec(b->left, -1, 0); + print_exec(b->left, -1, bracket); printf("["); - print_exec(b->right, -1, 0); + print_exec(b->right, -1, bracket); printf("]"); break; @@ -1747,13 +1758,11 @@ make a copy of an array with controllable depth. t = propagate_types(b->left, c, ok, NULL, rules & Rnoconstant); if (!t || t->compat != array_compat) { type_err(c, "error: %1 cannot be indexed", prog, t, 0, NULL); - *ok = 0; return NULL; } else { if (!type_compat(type, t->array.member, rules)) { type_err(c, "error: have %1 but need %2", prog, t->array.member, rules, type); - *ok = 0; } return t->array.member; } @@ -1920,7 +1929,7 @@ function will be needed. case Xfieldref: { struct fieldref *f = cast(fieldref, e); - print_exec(f->left, -1, 0); + print_exec(f->left, -1, bracket); printf(".%.*s", f->name.len, f->name.txt); break; } @@ -1950,19 +1959,15 @@ function will be needed. f->left, st, 0, NULL); else if (f->index == -2) { f->index = find_struct_index(st, f->name); - if (f->index < 0) { + if (f->index < 0) type_err(c, "error: cannot find requested field in %1", f->left, st, 0, NULL); - *ok = 0; - } } if (f->index >= 0) { struct type *ft = st->structure.fields[f->index].type; - if (!type_compat(type, ft, rules)) { + if (!type_compat(type, ft, rules)) type_err(c, "error: have %1 but need %2", prog, ft, rules, type); - *ok = 0; - } return ft; } break; @@ -1994,43 +1999,47 @@ function will be needed. } ###### top level grammar - DeclareStruct -> struct IDENTIFIER FieldBlock ${ { - struct type *t = - add_type(config2context(config), $2.txt, &structure_prototype); - int cnt = 0; - struct fieldlist *f; - - for (f = $3; f; f=f->prev) - cnt += 1; - - t->structure.nfields = cnt; - t->structure.fields = calloc(cnt, sizeof(struct field)); - f = $3; - while (cnt > 0) { - cnt -= 1; - t->structure.fields[cnt] = f->f; - f->f.init = val_prepare(Tnone); - f = f->prev; - } - } }$ + DeclareStruct -> struct IDENTIFIER FieldBlock Newlines ${ { + struct type *t = + add_type(c, $2.txt, &structure_prototype); + int cnt = 0; + struct fieldlist *f; + + for (f = $3; f; f=f->prev) + cnt += 1; + + t->structure.nfields = cnt; + t->structure.fields = calloc(cnt, sizeof(struct field)); + f = $3; + while (cnt > 0) { + cnt -= 1; + t->structure.fields[cnt] = f->f; + f->f.init = val_prepare(Tnone); + f = f->prev; + } + } }$ $*fieldlist - FieldBlock -> Open SimpleFieldList Close ${ $0 = $<2; }$ - | Open Newlines SimpleFieldList Close ${ $0 = $<3; }$ - | : FieldList ${ $0 = $<2; }$ - - FieldList -> Field NEWLINE ${ $0 = $<1; }$ - | FieldList NEWLINE ${ $0 = $<1; }$ - | FieldList Field NEWLINE ${ - $2->prev = $<1; - $0 = $<2; + FieldBlock -> { IN OptNL FieldLines OUT OptNL } ${ $0 = $ SimpleFieldList Newlines ${ $0 = $prev = $ Field ; ${ $0 = $<1; }$ - | SimpleFieldList Field ; ${ - $2->prev = $<1; - $0 = $<2; + SimpleFieldList -> Field ${ $0 = $prev = $ IDENTIFIER : Type = Expression ${ { int ok; @@ -2041,10 +2050,10 @@ function will be needed. $0->f.init = val_prepare($0->f.type); do { ok = 1; - propagate_types($<5, config2context(config), &ok, $3, 0); + propagate_types($<5, c, &ok, $3, 0); } while (ok == 2); if (!ok) - config2context(config)->parse_error = 1; + c->parse_error = 1; else $0->f.init = interp_exec($5); } }$ @@ -2063,7 +2072,7 @@ function will be needed. { int i; - fprintf(f, "struct %.*s:\n", t->name.len, t->name.txt); + fprintf(f, "struct %.*s\n", t->name.len, t->name.txt); for (i = 0; i < t->structure.nfields; i++) { struct field *fl = t->structure.fields + i; @@ -2147,7 +2156,7 @@ an executable. if (number_parse($0->val.num, tail, $1.txt) == 0) mpq_init($0->val.num); if (tail[0]) - tok_err(config2context(config), "error: unsupported number suffix", + tok_err(c, "error: unsupported number suffix", &$1); } }$ @@ -2158,7 +2167,7 @@ an executable. char tail[3]; string_parse(&$1, '\\', &$0->val.str, tail); if (tail[0]) - tok_err(config2context(config), "error: unsupported string suffix", + tok_err(c, "error: unsupported string suffix", &$1); } }$ @@ -2169,7 +2178,7 @@ an executable. char tail[3]; string_parse(&$1, '\\', &$0->val.str, tail); if (tail[0]) - tok_err(config2context(config), "error: unsupported string suffix", + tok_err(c, "error: unsupported string suffix", &$1); } }$ @@ -2190,11 +2199,9 @@ an executable. case Xval: { struct val *val = cast(val, prog); - if (!type_compat(type, val->val.type, rules)) { + if (!type_compat(type, val->val.type, rules)) type_err(c, "error: expected %1%r found %2", prog, type, rules, val->val.type); - *ok = 0; - } return val->val.type; } @@ -2258,38 +2265,38 @@ link to find the primary instance. $*var VariableDecl -> IDENTIFIER : ${ { - struct variable *v = var_decl(config2context(config), $1.txt); + struct variable *v = var_decl(c, $1.txt); $0 = new_pos(var, $1); $0->var = v; if (v) v->where_decl = $0; else { - v = var_ref(config2context(config), $1.txt); + v = var_ref(c, $1.txt); $0->var = v; - type_err(config2context(config), "error: variable '%v' redeclared", + type_err(c, "error: variable '%v' redeclared", $0, NULL, 0, NULL); - type_err(config2context(config), "info: this is where '%v' was first declared", + type_err(c, "info: this is where '%v' was first declared", v->where_decl, NULL, 0, NULL); } } }$ | IDENTIFIER :: ${ { - struct variable *v = var_decl(config2context(config), $1.txt); + struct variable *v = var_decl(c, $1.txt); $0 = new_pos(var, $1); $0->var = v; if (v) { v->where_decl = $0; v->constant = 1; } else { - v = var_ref(config2context(config), $1.txt); + v = var_ref(c, $1.txt); $0->var = v; - type_err(config2context(config), "error: variable '%v' redeclared", + type_err(c, "error: variable '%v' redeclared", $0, NULL, 0, NULL); - type_err(config2context(config), "info: this is where '%v' was first declared", + type_err(c, "info: this is where '%v' was first declared", v->where_decl, NULL, 0, NULL); } } }$ | IDENTIFIER : Type ${ { - struct variable *v = var_decl(config2context(config), $1.txt); + struct variable *v = var_decl(c, $1.txt); $0 = new_pos(var, $1); $0->var = v; if (v) { @@ -2297,16 +2304,16 @@ link to find the primary instance. v->where_set = $0; v->val = val_prepare($<3); } else { - v = var_ref(config2context(config), $1.txt); + v = var_ref(c, $1.txt); $0->var = v; - type_err(config2context(config), "error: variable '%v' redeclared", + type_err(c, "error: variable '%v' redeclared", $0, NULL, 0, NULL); - type_err(config2context(config), "info: this is where '%v' was first declared", + type_err(c, "info: this is where '%v' was first declared", v->where_decl, NULL, 0, NULL); } } }$ | IDENTIFIER :: Type ${ { - struct variable *v = var_decl(config2context(config), $1.txt); + struct variable *v = var_decl(c, $1.txt); $0 = new_pos(var, $1); $0->var = v; if (v) { @@ -2315,25 +2322,25 @@ link to find the primary instance. v->val = val_prepare($<3); v->constant = 1; } else { - v = var_ref(config2context(config), $1.txt); + v = var_ref(c, $1.txt); $0->var = v; - type_err(config2context(config), "error: variable '%v' redeclared", + type_err(c, "error: variable '%v' redeclared", $0, NULL, 0, NULL); - type_err(config2context(config), "info: this is where '%v' was first declared", + type_err(c, "info: this is where '%v' was first declared", v->where_decl, NULL, 0, NULL); } } }$ $*exec Variable -> IDENTIFIER ${ { - struct variable *v = var_ref(config2context(config), $1.txt); + struct variable *v = var_ref(c, $1.txt); $0 = new_pos(var, $1); if (v == NULL) { /* This might be a label - allocate a var just in case */ - v = var_decl(config2context(config), $1.txt); + v = var_decl(c, $1.txt); if (v) { - v->val = val_prepare(Tlabel); - v->val.label = &v->val; + v->val = val_prepare(Tnone); + v->where_decl = $0; v->where_set = $0; } } @@ -2343,9 +2350,9 @@ link to find the primary instance. $*type Type -> IDENTIFIER ${ - $0 = find_type(config2context(config), $1.txt); + $0 = find_type(c, $1.txt); if (!$0) { - tok_err(config2context(config), + tok_err(c, "error: undefined type", &$1); $0 = Tnone; @@ -2385,7 +2392,6 @@ link to find the primary instance. struct variable *v = var->var; if (!v) { type_err(c, "%d:BUG: no variable!!", prog, NULL, 0, NULL); // NOTEST - *ok = 0; // NOTEST return Tnone; // NOTEST } if (v->merged) @@ -2395,9 +2401,11 @@ link to find the primary instance. prog, NULL, 0, NULL); type_err(c, "info: name was defined as a constant here", v->where_decl, NULL, 0, NULL); - *ok = 0; return v->val.type; } + if (v->val.type == Tnone && v->where_decl == prog) + type_err(c, "error: variable used but not declared: %v", + prog, NULL, 0, NULL); if (v->val.type == NULL) { if (type && *ok != 0) { v->val = val_prepare(type); @@ -2411,7 +2419,6 @@ link to find the primary instance. type, rules, v->val.type); type_err(c, "info: this is where '%v' was set to %1", v->where_set, v->val.type, rules, NULL); - *ok = 0; } if (!type) return v->val.type; @@ -2460,8 +2467,11 @@ room for ambiguity, so a full conditional expression is allowed in there. ###### Grammar + $LEFT if $$ifelse + ## expr precedence + $*exec - Expression -> BoolExpr if Expression else Expression ${ { + Expression -> Expression if Expression else Expression $$ifelse ${ { struct binode *b1 = new(binode); struct binode *b2 = new(binode); b1->op = CondExpr; @@ -2472,17 +2482,19 @@ room for ambiguity, so a full conditional expression is allowed in there. b2->right = $<5; $0 = b1; } }$ - | BoolExpr ${ $0 = $<1; }$ + ## expression grammar ###### print binode cases case CondExpr: b2 = cast(binode, b->right); - print_exec(b2->left, -1, 0); + if (bracket) printf("("); + print_exec(b2->left, -1, bracket); printf(" if "); - print_exec(b->left, -1, 0); + print_exec(b->left, -1, bracket); printf(" else "); - print_exec(b2->right, -1, 0); + print_exec(b2->right, -1, bracket); + if (bracket) printf(")"); break; ###### propagate binode cases @@ -2528,73 +2540,83 @@ if the result would make a difference. OrElse, Not, -###### Grammar +###### expr precedence + $LEFT or + $LEFT and + $LEFT not - $*exec - BoolExpr -> BoolExpr or BTerm ${ { +###### expression grammar + | Expression or Expression ${ { struct binode *b = new(binode); b->op = Or; b->left = $<1; b->right = $<3; $0 = b; } }$ - | BoolExpr or else BTerm ${ { + | Expression or else Expression ${ { struct binode *b = new(binode); b->op = OrElse; b->left = $<1; b->right = $<4; $0 = b; } }$ - | BTerm ${ $0 = $<1; }$ - BTerm -> BTerm and BFact ${ { + | Expression and Expression ${ { struct binode *b = new(binode); b->op = And; b->left = $<1; b->right = $<3; $0 = b; } }$ - | BTerm and then BFact ${ { + | Expression and then Expression ${ { struct binode *b = new(binode); b->op = AndThen; b->left = $<1; b->right = $<4; $0 = b; } }$ - | BFact ${ $0 = $<1; }$ - BFact -> not BFact ${ { + | not Expression ${ { struct binode *b = new(binode); b->op = Not; b->right = $<2; $0 = b; } }$ - ## other BFact ###### print binode cases case And: - print_exec(b->left, -1, 0); + if (bracket) printf("("); + print_exec(b->left, -1, bracket); printf(" and "); - print_exec(b->right, -1, 0); + print_exec(b->right, -1, bracket); + if (bracket) printf(")"); break; case AndThen: - print_exec(b->left, -1, 0); + if (bracket) printf("("); + print_exec(b->left, -1, bracket); printf(" and then "); - print_exec(b->right, -1, 0); + print_exec(b->right, -1, bracket); + if (bracket) printf(")"); break; case Or: - print_exec(b->left, -1, 0); + if (bracket) printf("("); + print_exec(b->left, -1, bracket); printf(" or "); - print_exec(b->right, -1, 0); + print_exec(b->right, -1, bracket); + if (bracket) printf(")"); break; case OrElse: - print_exec(b->left, -1, 0); + if (bracket) printf("("); + print_exec(b->left, -1, bracket); printf(" or else "); - print_exec(b->right, -1, 0); + print_exec(b->right, -1, bracket); + if (bracket) printf(")"); break; case Not: + if (bracket) printf("("); printf("not "); - print_exec(b->right, -1, 0); + print_exec(b->right, -1, bracket); + if (bracket) printf(")"); break; ###### propagate binode cases @@ -2606,11 +2628,9 @@ if the result would make a difference. /* both must be Tbool, result is Tbool */ propagate_types(b->left, c, ok, Tbool, 0); propagate_types(b->right, c, ok, Tbool, 0); - if (type && type != Tbool) { + if (type && type != Tbool) type_err(c, "error: %1 operation found where %2 expected", prog, Tbool, 0, type); - *ok = 0; - } return Tbool; ###### interp binode cases @@ -2669,15 +2689,17 @@ expression operator. Eql, NEql, -###### other BFact - | Expr CMPop Expr ${ { +###### expr precedence + $LEFT < > <= >= == != CMPop + +###### expression grammar + | Expression CMPop Expression ${ { struct binode *b = new(binode); b->op = $2.op; b->left = $<1; b->right = $<3; $0 = b; } }$ - | Expr ${ $0 = $<1; }$ ###### Grammar @@ -2697,7 +2719,8 @@ expression operator. case GtrEq: case Eql: case NEql: - print_exec(b->left, -1, 0); + if (bracket) printf("("); + print_exec(b->left, -1, bracket); switch(b->op) { case Less: printf(" < "); break; case LessEq: printf(" <= "); break; @@ -2707,7 +2730,8 @@ expression operator. case NEql: printf(" != "); break; default: abort(); // NOTEST } - print_exec(b->right, -1, 0); + print_exec(b->right, -1, bracket); + if (bracket) printf(")"); break; ###### propagate binode cases @@ -2726,11 +2750,9 @@ expression operator. if (t) t = propagate_types(b->left, c, ok, t, 0); } - if (!type_compat(type, Tbool, 0)) { + if (!type_compat(type, Tbool, 0)) type_err(c, "error: Comparison returns %1 but %2 expected", prog, Tbool, rules, type); - *ok = 0; - } return Tbool; ###### interp binode cases @@ -2779,34 +2801,36 @@ precedence is handled better I might be able to discard this. Absolute, Negate, Bracket, -###### Grammar +###### expr precedence + $LEFT + - Eop + $LEFT * / % ++ Top + $LEFT Uop + $TERM ( ) - $*exec - Expr -> Expr Eop Term ${ { +###### expression grammar + | Expression Eop Expression ${ { struct binode *b = new(binode); b->op = $2.op; b->left = $<1; b->right = $<3; $0 = b; } }$ - | Term ${ $0 = $<1; }$ - Term -> Term Top Factor ${ { + | Expression Top Expression ${ { struct binode *b = new(binode); b->op = $2.op; b->left = $<1; b->right = $<3; $0 = b; } }$ - | Factor ${ $0 = $<1; }$ - Factor -> ( Expression ) ${ { + | ( Expression ) ${ { struct binode *b = new_pos(binode, $1); b->op = Bracket; b->right = $<2; $0 = b; } }$ - | Uop Factor ${ { + | Uop Expression ${ { struct binode *b = new(binode); b->op = $1.op; b->right = $<2; @@ -2834,7 +2858,8 @@ precedence is handled better I might be able to discard this. case Divide: case Concat: case Rem: - print_exec(b->left, indent, 0); + if (bracket) printf("("); + print_exec(b->left, indent, bracket); switch(b->op) { case Plus: fputs(" + ", stdout); break; case Minus: fputs(" - ", stdout); break; @@ -2844,19 +2869,24 @@ precedence is handled better I might be able to discard this. case Concat: fputs(" ++ ", stdout); break; default: abort(); // NOTEST } // NOTEST - print_exec(b->right, indent, 0); + print_exec(b->right, indent, bracket); + if (bracket) printf(")"); break; case Absolute: + if (bracket) printf("("); printf("+"); - print_exec(b->right, indent, 0); + print_exec(b->right, indent, bracket); + if (bracket) printf(")"); break; case Negate: + if (bracket) printf("("); printf("-"); - print_exec(b->right, indent, 0); + print_exec(b->right, indent, bracket); + if (bracket) printf(")"); break; case Bracket: printf("("); - print_exec(b->right, indent, 0); + print_exec(b->right, indent, bracket); printf(")"); break; @@ -2873,22 +2903,18 @@ precedence is handled better I might be able to discard this. * unary ops fit here too */ propagate_types(b->left, c, ok, Tnum, 0); propagate_types(b->right, c, ok, Tnum, 0); - if (!type_compat(type, Tnum, 0)) { + if (!type_compat(type, Tnum, 0)) type_err(c, "error: Arithmetic returns %1 but %2 expected", prog, Tnum, rules, type); - *ok = 0; - } return Tnum; case Concat: /* both must be Tstr, result is Tstr */ propagate_types(b->left, c, ok, Tstr, 0); propagate_types(b->right, c, ok, Tstr, 0); - if (!type_compat(type, Tstr, 0)) { + if (!type_compat(type, Tstr, 0)) type_err(c, "error: Concat returns %1 but %2 expected", prog, Tstr, rules, type); - *ok = 0; - } return Tstr; case Bracket: @@ -2948,7 +2974,6 @@ precedence is handled better I might be able to discard this. rv.str = text_join(left.str, right.str); break; - ###### value functions static struct text text_join(struct text a, struct text b) @@ -3017,46 +3042,63 @@ is in-place. ###### Binode types Block, -###### Grammar - - $void - OptNL -> Newlines - | +###### expr precedence + $TERM pass - Newlines -> NEWLINE - | Newlines NEWLINE +###### Grammar $*binode - Open -> { - | NEWLINE { - Close -> } - | NEWLINE } - Block -> Open Statementlist Close ${ $0 = $<2; }$ - | Open Newlines Statementlist Close ${ $0 = $<3; }$ - | Open SimpleStatements } ${ $0 = reorder_bilist($<2); }$ - | Open Newlines SimpleStatements } ${ $0 = reorder_bilist($<3); }$ - | : Statementlist ${ $0 = $<2; }$ - | : SimpleStatements ${ $0 = reorder_bilist($<2); }$ - - Statementlist -> ComplexStatements ${ $0 = reorder_bilist($<1); }$ + Block -> { IN OptNL Statementlist OUT OptNL } ${ $0 = $ OpenScope { IN OptNL Statementlist OUT OptNL } ${ $0 = $ { OpenScope IN OptNL Statementlist OUT OptNL } ${ $0 = $ { IN OptNL Statementlist OUT OptNL } ${ $0 = $ ComplexStatements ${ $0 = reorder_bilist($ ComplexStatements ComplexStatement ${ - $0 = new(binode); - $0->op = Block; - $0->left = $<1; - $0->right = $<2; + if ($2 == NULL) { + $0 = $<1; + } else { + $0 = new(binode); + $0->op = Block; + $0->left = $<1; + $0->right = $<2; + } }$ - | ComplexStatements NEWLINE ${ $0 = $<1; }$ | ComplexStatement ${ - $0 = new(binode); - $0->op = Block; - $0->left = NULL; - $0->right = $<1; + if ($1 == NULL) { + $0 = NULL; + } else { + $0 = new(binode); + $0->op = Block; + $0->left = NULL; + $0->right = $<1; + } }$ $*exec - ComplexStatement -> SimpleStatements NEWLINE ${ - $0 = reorder_bilist($<1); + ComplexStatement -> SimpleStatements Newlines ${ + $0 = reorder_bilist($left = NULL; $0->right = $<1; }$ - | SimpleStatements ; ${ $0 = $<1; }$ SimpleStatement -> pass ${ $0 = NULL; }$ + | ERROR ${ tok_err(c, "Syntax error in statement", &$1); }$ ## SimpleStatement Grammar ###### print binode cases @@ -3085,10 +3127,10 @@ is in-place. if (b->left == NULL) printf("pass"); else - print_exec(b->left, indent, 0); + print_exec(b->left, indent, bracket); if (b->right) { printf("; "); - print_exec(b->right, indent, 0); + print_exec(b->right, indent, bracket); } } else { // block, one per line @@ -3120,11 +3162,9 @@ is in-place. if (t && t != Tnone && t != Tbool) { if (!type) type = t; - else if (t != type) { + else if (t != type) type_err(c, "error: expected %1%r, found %2", e->left, type, rules, t); - *ok = 0; - } } } return type; @@ -3152,6 +3192,9 @@ same solution. ###### Binode types Print, +##### expr precedence + $TERM print , + ###### SimpleStatement Grammar | print ExpressionList ${ @@ -3193,7 +3236,7 @@ same solution. while (b) { if (b->left) { printf(" "); - print_exec(b->left, -1, 0); + print_exec(b->left, -1, bracket); if (b->right) printf(","); } @@ -3264,7 +3307,7 @@ it is declared, and error will be raised as the name is created as | VariableDecl ${ if ($1->var->where_set == NULL) { - type_err(config2context(config), + type_err(c, "Variable declared with no type or value: %v", $1, NULL, 0, NULL); } else { @@ -3279,9 +3322,9 @@ it is declared, and error will be raised as the name is created as case Assign: do_indent(indent, ""); - print_exec(b->left, indent, 0); + print_exec(b->left, indent, bracket); printf(" = "); - print_exec(b->right, indent, 0); + print_exec(b->right, indent, bracket); if (indent >= 0) printf("\n"); break; @@ -3290,7 +3333,7 @@ it is declared, and error will be raised as the name is created as { struct variable *v = cast(var, b->left)->var; do_indent(indent, ""); - print_exec(b->left, indent, 0); + print_exec(b->left, indent, bracket); if (cast(var, b->left)->var->constant) { if (v->where_decl == v->where_set) { printf("::"); @@ -3308,7 +3351,7 @@ it is declared, and error will be raised as the name is created as } if (b->right) { printf("= "); - print_exec(b->right, indent, 0); + print_exec(b->right, indent, bracket); } if (indent >= 0) printf("\n"); @@ -3340,10 +3383,8 @@ it is declared, and error will be raised as the name is created as propagate_types(b->left, c, ok, t, (b->op == Assign ? Rnoconstant : 0)); } - if (t && t->dup == NULL) { + if (t && t->dup == NULL) type_err(c, "error: cannot assign value of type %1", b, t, 0, NULL); - *ok = 0; - } return Tnone; break; @@ -3386,18 +3427,29 @@ function. ###### Binode types Use, +###### expr precedence + $TERM use + ###### SimpleStatement Grammar | use Expression ${ $0 = new_pos(binode, $1); $0->op = Use; $0->right = $<2; + if ($0->right->type == Xvar) { + struct var *v = cast(var, $0->right); + if (v->var->val.type == Tnone) { + /* Convert this to a label */ + v->var->val = val_prepare(Tlabel); + v->var->val.label = &v->var->val; + } + } }$ ###### print binode cases case Use: do_indent(indent, "use "); - print_exec(b->right, -1, 0); + print_exec(b->right, -1, bracket); if (indent >= 0) printf("\n"); break; @@ -3526,154 +3578,145 @@ defined. ###### ComplexStatement Grammar | CondStatement ${ $0 = $<1; }$ +###### expr precedence + $TERM for then while do + $TERM else + $TERM switch case + ###### Grammar $*cond_statement - // both ForThen and Whilepart open scopes, and CondSuffix only + // A CondStatement must end with EOL, as does CondSuffix and + // IfSuffix. + // ForPart, ThenPart, SwitchPart, CasePart are non-empty and + // may or may not end with EOL + // WhilePart and IfPart include an appropriate Suffix + + + // Both ForPart and Whilepart open scopes, and CondSuffix only // closes one - so in the first branch here we have another to close. - CondStatement -> ForThen WhilePart CondSuffix ${ - $0 = $<3; - $0->forpart = $1.forpart; $1.forpart = NULL; - $0->thenpart = $1.thenpart; $1.thenpart = NULL; - $0->condpart = $2.condpart; $2.condpart = NULL; - $0->dopart = $2.dopart; $2.dopart = NULL; - var_block_close(config2context(config), CloseSequential); + CondStatement -> ForPart OptNL ThenPart OptNL WhilePart CondSuffix ${ + $0 = $forpart = $thenpart = $condpart = $WP.condpart; $WP.condpart = NULL; + $0->dopart = $WP.dopart; $WP.dopart = NULL; + var_block_close(c, CloseSequential); + }$ + | ForPart OptNL WhilePart CondSuffix ${ + $0 = $forpart = $condpart = $WP.condpart; $WP.condpart = NULL; + $0->dopart = $WP.dopart; $WP.dopart = NULL; + var_block_close(c, CloseSequential); }$ | WhilePart CondSuffix ${ - $0 = $<2; - $0->condpart = $1.condpart; $1.condpart = NULL; - $0->dopart = $1.dopart; $1.dopart = NULL; + $0 = $condpart = $WP.condpart; $WP.condpart = NULL; + $0->dopart = $WP.dopart; $WP.dopart = NULL; + }$ + | SwitchPart OptNL CasePart CondSuffix ${ + $0 = $condpart = $next = $0->casepart; + $0->casepart = $condpart = $<1; + | SwitchPart : IN OptNL CasePart CondSuffix OUT Newlines ${ + $0 = $condpart = $next = $0->casepart; + $0->casepart = $condpart = $1.condpart; $1.condpart = NULL; - $0->thenpart = $1.thenpart; $1.thenpart = NULL; + $0 = $condpart = $IP.condpart; $IP.condpart = NULL; + $0->thenpart = $IP.thenpart; $IP.thenpart = NULL; // This is where we close an "if" statement - var_block_close(config2context(config), CloseSequential); + var_block_close(c, CloseSequential); }$ CondSuffix -> IfSuffix ${ $0 = $<1; // This is where we close scope of the whole // "for" or "while" statement - var_block_close(config2context(config), CloseSequential); - }$ - | CasePart CondSuffix ${ - $0 = $<2; - $1->next = $0->casepart; - $0->casepart = $<1; + var_block_close(c, CloseSequential); }$ - - $*casepart - CasePart -> Newlines case Expression OpenScope Block ${ - $0 = calloc(1,sizeof(struct casepart)); - $0->value = $<3; - $0->action = $<5; - var_block_close(config2context(config), CloseParallel); + | Newlines CasePart CondSuffix ${ + $0 = $next = $0->casepart; + $0->casepart = $value = $<2; - $0->action = $<4; - var_block_close(config2context(config), CloseParallel); + | CasePart CondSuffix ${ + $0 = $next = $0->casepart; + $0->casepart = $ Newlines ${ $0 = new(cond_statement); }$ - | Newlines else OpenScope Block ${ - $0 = new(cond_statement); - $0->elsepart = $<4; - var_block_close(config2context(config), CloseElse); - }$ - | else OpenScope Block ${ - $0 = new(cond_statement); - $0->elsepart = $<3; - var_block_close(config2context(config), CloseElse); - }$ - | Newlines else OpenScope CondStatement ${ + | Newlines ElsePart ${ $0 = $ else OpenBlock Newlines ${ $0 = new(cond_statement); - $0->elsepart = $<4; - var_block_close(config2context(config), CloseElse); + $0->elsepart = $elsepart = $<3; - var_block_close(config2context(config), CloseElse); + $0->elsepart = $ case Expression OpenScope ColonBlock ${ + $0 = calloc(1,sizeof(struct casepart)); + $0->value = $action = $ for OpenScope SimpleStatements ${ - $0 = reorder_bilist($<3); - }$ - | for OpenScope Block ${ - $0 = $<3; - }$ - - ThenPart -> then OpenScope SimpleStatements ${ - $0 = reorder_bilist($<3); - var_block_close(config2context(config), CloseSequential); - }$ - | then OpenScope Block ${ - $0 = $<3; - var_block_close(config2context(config), CloseSequential); + ForPart -> for OpenBlock ${ + $0 = $ ThenPart OptNL ${ - $0 = $<1; - }$ - - // This scope is closed in CondSuffix - WhileHead -> while OpenScope Block ${ - $0 = $<3; + ThenPart -> then OpenBlock ${ + $0 = $ ForPart OptNL ThenPartNL ${ - $0.forpart = $<1; - $0.thenpart = $<3; - }$ - | ForPart OptNL ${ - $0.forpart = $<1; - }$ - // This scope is closed in CondSuffix - WhilePart -> while OpenScope Expression Block ${ - $0.type = Xcond_statement; - $0.condpart = $<3; - $0.dopart = $<4; + WhilePart -> while UseBlock OptNL do Block ${ + $0.condpart = $ if OpenScope Expression OpenScope Block ${ - $0.type = Xcond_statement; - $0.condpart = $<3; - $0.thenpart = $<5; - var_block_close(config2context(config), CloseParallel); + IfPart -> if UseBlock OptNL then OpenBlock ClosePara ${ + $0.condpart = $ switch OpenScope Expression ${ - $0 = $<3; + $0 = $forpart) { do_indent(indent, "for"); - if (bracket) printf(" {\n"); else printf(":\n"); + if (bracket) printf(" {\n"); else printf("\n"); print_exec(cs->forpart, indent+1, bracket); if (cs->thenpart) { if (bracket) do_indent(indent, "} then {\n"); else - do_indent(indent, "then:\n"); + do_indent(indent, "then\n"); print_exec(cs->thenpart, indent+1, bracket); } if (bracket) do_indent(indent, "}\n"); @@ -3702,12 +3745,12 @@ defined. if (bracket) do_indent(indent, "while {\n"); else - do_indent(indent, "while:\n"); + do_indent(indent, "while\n"); print_exec(cs->condpart, indent+1, bracket); if (bracket) do_indent(indent, "} do {\n"); else - do_indent(indent, "do:\n"); + do_indent(indent, "do\n"); print_exec(cs->dopart, indent+1, bracket); if (bracket) do_indent(indent, "}\n"); @@ -3772,7 +3815,7 @@ defined. if (bracket) printf(" {\n"); else - printf(":\n"); + printf("\n"); print_exec(cs->elsepart, indent+1, bracket); if (bracket) do_indent(indent, "}\n"); @@ -3911,15 +3954,23 @@ various declarations in the parse context. ###### Parser: grammar $void - Ocean -> DeclarationList + Ocean -> OptNL DeclarationList + + OptNL -> + | OptNL NEWLINE + Newlines -> NEWLINE + | Newlines NEWLINE DeclarationList -> Declaration | DeclarationList Declaration - Declaration -> DeclareConstant + Declaration -> ERROR Newlines ${ + tok_err(c, + "error: unhandled parse error", &$1); + }$ + | DeclareConstant | DeclareProgram | DeclareStruct - | NEWLINE ## top level grammar @@ -3948,20 +3999,18 @@ searching through for the Nth constant for decreasing N. ###### top level grammar - DeclareConstant -> const Open ConstList Close - | const Open Newlines ConstList Close - | const Open SimpleConstList } - | const Open Newlines SimpleConstList } - | const : ConstList - | const SimpleConstList - - ConstList -> ComplexConsts - ComplexConsts -> ComplexConst ComplexConsts - | ComplexConst - ComplexConst -> SimpleConstList NEWLINE - SimpleConstList -> Const ; SimpleConstList + DeclareConstant -> const { IN OptNL ConstList OUT OptNL } Newlines + | const { SimpleConstList } Newlines + | const IN OptNL ConstList OUT Newlines + | const SimpleConstList Newlines + + ConstList -> ConstList SimpleConstLine + | SimpleConstLine + SimpleConstList -> SimpleConstList ; Const | Const - | Const ; SimpleConstList ; + | SimpleConstList ; + SimpleConstLine -> SimpleConstList Newlines + | ERROR Newlines ${ tok_err(c, "Syntax error in constant", &$1); }$ $*type CType -> Type ${ $0 = $<1; }$ @@ -3971,7 +4020,7 @@ searching through for the Nth constant for decreasing N. int ok; struct variable *v; - v = var_decl(config2context(config), $1.txt); + v = var_decl(c, $1.txt); if (v) { struct var *var = new_pos(var, $1); v->where_decl = var; @@ -3979,17 +4028,17 @@ searching through for the Nth constant for decreasing N. var->var = v; v->constant = 1; } else { - v = var_ref(config2context(config), $1.txt); - tok_err(config2context(config), "error: name already declared", &$1); - type_err(config2context(config), "info: this is where '%v' was first declared", + v = var_ref(c, $1.txt); + tok_err(c, "error: name already declared", &$1); + type_err(c, "info: this is where '%v' was first declared", v->where_decl, NULL, 0, NULL); } do { ok = 1; - propagate_types($5, config2context(config), &ok, $3, 0); + propagate_types($5, c, &ok, $3, 0); } while (ok == 2); if (!ok) - config2context(config)->parse_error = 1; + c->parse_error = 1; else if (v) { v->val = interp_exec($5); } @@ -4011,7 +4060,7 @@ searching through for the Nth constant for decreasing N. if (target == -1) { if (i) - printf("const:\n"); + printf("const\n"); target = i; } else { printf(" %.*s :: ", v->name->name.len, v->name->name.txt); @@ -4048,7 +4097,6 @@ analysis is a bit more interesting at this level. ###### top level grammar DeclareProgram -> Program ${ { - struct parse_context *c = config2context(config); if (c->prog) type_err(c, "Program defined a second time", $1, NULL, 0, NULL); @@ -4056,19 +4104,14 @@ analysis is a bit more interesting at this level. c->prog = $<1; } }$ - $*binode - Program -> program OpenScope Varlist Block OptNL ${ + Program -> program OpenScope Varlist ColonBlock Newlines ${ $0 = new(binode); $0->op = Program; - $0->left = reorder_bilist($<3); - $0->right = $<4; - var_block_close(config2context(config), CloseSequential); - if (config2context(config)->scope_stack) abort(); - }$ - | ERROR ${ - tok_err(config2context(config), - "error: unhandled parse error", &$1); + $0->left = reorder_bilist($right = $scope_stack && !c->parse_error) abort(); }$ Varlist -> Varlist ArgDecl ${ @@ -4081,7 +4124,7 @@ analysis is a bit more interesting at this level. $*var ArgDecl -> IDENTIFIER ${ { - struct variable *v = var_decl(config2context(config), $1.txt); + struct variable *v = var_decl(c, $1.txt); $0 = new(var); $0->var = v; } }$ @@ -4183,21 +4226,21 @@ Fibonacci, performs a binary search for a number, and a few other things which will likely grow as the languages grows. ###### File: oceani.mk - tests :: sayhello + demos :: sayhello sayhello : oceani - @echo "===== TEST =====" - ./oceani --section "test: hello" oceani.mdc 55 33 + @echo "===== DEMO =====" + ./oceani --section "demo: hello" oceani.mdc 55 33 -###### test: hello +###### demo: hello - const: - pi ::= 3.1415926 + const + pi ::= 3.141_592_6 four ::= 2 + 2 ; five ::= 10/2 const pie ::= "I like Pie"; cake ::= "The cake is" ++ " a lie" - struct fred: + struct fred size:[four]number name:string alive:Boolean @@ -4212,7 +4255,7 @@ things which will likely grow as the languages grows. */ if A > B: bigger := "yes" - else: + else bigger := "no" print "Is", A, "bigger than", B,"? ", bigger /* If a variable is not used after the 'if', no @@ -4221,7 +4264,7 @@ things which will likely grow as the languages grows. if A > B * 2: double:string = "yes" print A, "is more than twice", B, "?", double - else: + else double := B*2 print "double", B, "is", double @@ -4232,15 +4275,15 @@ things which will likely grow as the languages grows. while a != b: if a < b: b = b - a - else: + else a = a - b print "GCD of", A, "and", B,"is", a else if a <= 0: print a, "is not positive, cannot calculate GCD" - else: + else print b, "is not positive, cannot calculate GCD" - for: + for togo := 10 f1 := 1; f2 := 1 print "Fibonacci:", f1,f2, @@ -4253,21 +4296,21 @@ things which will likely grow as the languages grows. print "" /* Binary search... */ - for: + for lo:= 0; hi := 100 target := 77 - while: + while mid := (lo + hi) / 2 if mid == target: use Found if mid < target: lo = mid - else: + else hi = mid if hi - lo < 1: use GiveUp use True - do: pass + do pass case Found: print "Yay, I found", target case GiveUp: @@ -4280,7 +4323,7 @@ things which will likely grow as the languages grows. // Dad taught me - the first one I ever heard of. for i:=1; then i = i + 1; while i < size: n := list[i-1] * list[i-1] - list[i] = (n / 100) % 10000 + list[i] = (n / 100) % 10 000 print "Before sort:", for i:=0; then i = i + 1; while i < size: @@ -4298,6 +4341,8 @@ things which will likely grow as the languages grows. print "", list[i], print + if 1 == 2 then print "yes"; else print "no" + bob:fred bob.name = "Hello" bob.alive = (bob.name == "Hello")