]> ocean-lang.org Git - ocean/blobdiff - csrc/oceani.mdc
parsegen: fix up look-ahead for $$NEWLINE items.
[ocean] / csrc / oceani.mdc
index a3eba942acbd3cd92e407ee61b83446e1893bbf0..af7768dd1d763638d5142987c895d108d2a9f0a1 100644 (file)
@@ -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 <unistd.h>
@@ -169,8 +172,9 @@ structures can be used.
                struct parse_context context = {
                        .config = {
                                .ignored = (1 << TK_line_comment)
-                                        | (1 << TK_block_comment),
-                               .number_chars = ".,_+-",
+                                        | (1 << TK_block_comment)
+                                        | (1 << TK_mark),
+                               .number_chars = ".,_+- ",
                                .word_start = "_",
                                .word_cont = "_",
                        },
@@ -1001,7 +1005,7 @@ like "if" and the code following it.
 ###### Grammar
 
        $void
-       OpenScope -> ${ scope_push(config2context(config)); }$
+       OpenScope -> ${ scope_push(c); }$
 
 Each variable records a scope depth and is in one of four states:
 
@@ -1034,7 +1038,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 +1096,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 +1458,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 +1481,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 +1506,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 +1678,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 +1700,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 +1744,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 +1759,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 +1930,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 +1960,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;
@@ -1996,7 +2002,7 @@ function will be needed.
 ###### top level grammar
        DeclareStruct -> struct IDENTIFIER FieldBlock ${ {
                struct type *t =
-                       add_type(config2context(config), $2.txt, &structure_prototype);
+                       add_type(c, $2.txt, &structure_prototype);
                int cnt = 0;
                struct fieldlist *f;
 
@@ -2014,22 +2020,29 @@ function will be needed.
                }
        } }$
 
+       $void
+       Open -> {
+               | NEWLINE Open
+       Close -> }
+               | NEWLINE Close
        $*fieldlist
-       FieldBlock -> Open SimpleFieldList Close ${ $0 = $<2; }$
-               | Open Newlines SimpleFieldList Close ${ $0 = $<3; }$
+       FieldBlock -> Open FieldList Close ${ $0 = $<2; }$
+               | Open SimpleFieldList } ${ $0 = $<2; }$
                | : FieldList  ${ $0 = $<2; }$
 
-       FieldList -> Field NEWLINE ${ $0 = $<1; }$
-               | FieldList NEWLINE ${ $0 = $<1; }$
-               | FieldList Field NEWLINE ${
+       FieldList -> SimpleFieldList NEWLINE ${ $0 = $<1; }$
+               | FieldList SimpleFieldList NEWLINE ${
                        $2->prev = $<1;
                        $0 = $<2;
                }$
 
-       SimpleFieldList -> Field ; ${ $0 = $<1; }$
-               | SimpleFieldList Field ; ${
-                       $2->prev = $<1;
-                       $0 = $<2;
+       SimpleFieldList -> Field ${ $0 = $<1; }$
+               | SimpleFieldList ; Field ${
+                       $3->prev = $<1;
+                       $0 = $<3;
+               }$
+               | SimpleFieldList ; ${
+                       $0 = $<1;
                }$
 
        Field -> IDENTIFIER : Type = Expression ${ {
@@ -2041,10 +2054,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);
                } }$
@@ -2054,6 +2067,7 @@ function will be needed.
                        $0->f.type = $<3;
                        $0->f.init = val_init($3);
                }$
+               | ERROR ${ tok_err(c, "Syntax error in struct field", &$1); }$
 
 ###### forward decls
        static void structure_print_type(struct type *t, FILE *f);
@@ -2147,7 +2161,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 +2172,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 +2183,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 +2204,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 +2270,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 +2309,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 +2327,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 +2355,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 +2397,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 +2406,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 +2424,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 +2472,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 +2487,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 +2545,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 +2633,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 +2694,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 +2724,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 +2735,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 +2755,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 +2806,35 @@ precedence is handled better I might be able to discard this.
        Absolute, Negate,
        Bracket,
 
-###### Grammar
+###### expr precedence
+       $LEFT + - Eop
+       $LEFT * / % ++ Top
+       $LEFT Uop
 
-       $*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 +2862,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 +2873,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 +2907,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 +2978,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)
@@ -3019,45 +3048,41 @@ is in-place.
 
 ###### Grammar
 
-       $void
-       OptNL -> Newlines
-               |
-
-       Newlines -> NEWLINE
-               | Newlines NEWLINE
-
        $*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); }$
+               | : SimpleStatements $$NEWLINE ${ $0 = reorder_bilist($<2); }$
+               | : Statementlist $$NEWLINE ${ $0 = $<2; }$
 
        Statementlist -> ComplexStatements ${ $0 = reorder_bilist($<1); }$
+               | NEWLINE Statementlist ${ $0 = $<2; }$
 
        ComplexStatements -> 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 ${
+       ComplexStatement -> SimpleStatementLine ${
                        $0 = reorder_bilist($<1);
                        }$
+               | ComplexStatement NEWLINE ${ $0 = $<1; }$
                ## ComplexStatement Grammar
 
        $*binode
@@ -3075,7 +3100,11 @@ is in-place.
                        }$
                | SimpleStatements ; ${ $0 = $<1; }$
 
+       SimpleStatementLine -> SimpleStatements NEWLINE ${ $0 = $<1; }$
+               | SimpleStatementLine NEWLINE ${ $0 = $<1; }$
+
        SimpleStatement -> pass ${ $0 = NULL; }$
+               | ERROR ${ tok_err(c, "Syntax error in statement", &$1); }$
                ## SimpleStatement Grammar
 
 ###### print binode cases
@@ -3085,10 +3114,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 +3149,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;
@@ -3193,7 +3220,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 +3291,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 +3306,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 +3317,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 +3335,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 +3367,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;
@@ -3391,13 +3416,21 @@ function.
                $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;
@@ -3531,36 +3564,46 @@ defined.
        $*cond_statement
        // both ForThen and Whilepart open scopes, and CondSuffix only
        // closes one - so in the first branch here we have another to close.
-       CondStatement -> ForThen WhilePart CondSuffix ${
+       CondStatement -> ForPart ThenPart WhilePart CondSuffix ${
+                       $0 = $<4;
+                       $0->forpart = $<1;
+                       $0->thenpart = $<2;
+                       $0->condpart = $3.condpart; $3.condpart = NULL;
+                       $0->dopart = $3.dopart; $3.dopart = NULL;
+                       var_block_close(c, CloseSequential);
+                       }$
+               |  ForPart WhilePart CondSuffix ${
                        $0 = $<3;
-                       $0->forpart = $1.forpart; $1.forpart = NULL;
-                       $0->thenpart = $1.thenpart; $1.thenpart = NULL;
+                       $0->forpart = $<1;
+                       $0->thenpart = NULL;
                        $0->condpart = $2.condpart; $2.condpart = NULL;
                        $0->dopart = $2.dopart; $2.dopart = NULL;
-                       var_block_close(config2context(config), CloseSequential);
+                       var_block_close(c, CloseSequential);
                        }$
                | WhilePart CondSuffix ${
                        $0 = $<2;
                        $0->condpart = $1.condpart; $1.condpart = NULL;
                        $0->dopart = $1.dopart; $1.dopart = NULL;
                        }$
-               | SwitchPart CondSuffix ${
-                       $0 = $<2;
+               | SwitchPart CasePart CondSuffix ${
+                       $0 = $<3;
                        $0->condpart = $<1;
+                       $2->next = $0->casepart;
+                       $0->casepart = $<2;
                        }$
                | IfPart IfSuffix ${
                        $0 = $<2;
                        $0->condpart = $1.condpart; $1.condpart = NULL;
                        $0->thenpart = $1.thenpart; $1.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);
+                       var_block_close(c, CloseSequential);
                }$
                | CasePart CondSuffix ${
                        $0 = $<2;
@@ -3569,43 +3612,28 @@ defined.
                }$
 
        $*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);
-               }$
-               | case Expression OpenScope Block ${
+       CasePart -> case Expression OpenScope Block ${
                        $0 = calloc(1,sizeof(struct casepart));
                        $0->value = $<2;
                        $0->action = $<4;
-                       var_block_close(config2context(config), CloseParallel);
+                       var_block_close(c, CloseParallel);
                }$
+               | CasePart NEWLINE ${ $0 = $<1; }$
 
        $*cond_statement
-       IfSuffix -> Newlines ${ $0 = new(cond_statement); }$
-               | Newlines else OpenScope Block ${
-                       $0 = new(cond_statement);
-                       $0->elsepart = $<4;
-                       var_block_close(config2context(config), CloseElse);
-               }$
+       IfSuffix ->  ${ $0 = new(cond_statement); }$
+               | IfSuffix NEWLINE ${ $0 = $<1; }$
                | else OpenScope Block ${
                        $0 = new(cond_statement);
                        $0->elsepart = $<3;
-                       var_block_close(config2context(config), CloseElse);
-               }$
-               | Newlines else OpenScope CondStatement ${
-                       $0 = new(cond_statement);
-                       $0->elsepart = $<4;
-                       var_block_close(config2context(config), CloseElse);
+                       var_block_close(c, CloseElse);
                }$
                | else OpenScope CondStatement ${
                        $0 = new(cond_statement);
                        $0->elsepart = $<3;
-                       var_block_close(config2context(config), CloseElse);
+                       var_block_close(c, CloseElse);
                }$
 
-
        $*exec
        // These scopes are closed in CondSuffix
        ForPart -> for OpenScope SimpleStatements ${
@@ -3614,58 +3642,49 @@ defined.
                |  for OpenScope Block ${
                        $0 = $<3;
                }$
+               |  ForPart NEWLINE ${ $0 = $<1; }$
 
        ThenPart -> then OpenScope SimpleStatements ${
                        $0 = reorder_bilist($<3);
-                       var_block_close(config2context(config), CloseSequential);
+                       var_block_close(c, CloseSequential);
                }$
                |  then OpenScope Block ${
                        $0 = $<3;
-                       var_block_close(config2context(config), CloseSequential);
-               }$
-
-       ThenPartNL -> ThenPart OptNL ${
-                       $0 = $<1;
+                       var_block_close(c, CloseSequential);
                }$
+               |  ThenPart NEWLINE ${ $0 = $<1; }$
 
        // This scope is closed in CondSuffix
-       WhileHead -> while OpenScope Block ${
-               $0 = $<3;
-               }$
+       WhileHead -> while OpenScope Block ${ $0 = $<3; }$
+               | WhileHead NEWLINE ${ $0 = $<1; }$
 
        $cond_statement
-       ForThen -> 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;
                }$
-               | WhileHead OptNL do Block ${
+               | WhileHead do Block ${
                        $0.type = Xcond_statement;
                        $0.condpart = $<1;
-                       $0.dopart = $<4;
+                       $0.dopart = $<3;
                }$
+               | WhilePart NEWLINE ${ $0 = $<1; }$
 
        IfPart -> if OpenScope Expression OpenScope Block ${
                        $0.type = Xcond_statement;
                        $0.condpart = $<3;
                        $0.thenpart = $<5;
-                       var_block_close(config2context(config), CloseParallel);
+                       var_block_close(c, CloseParallel);
                }$
-               | if OpenScope Block OptNL then OpenScope Block ${
+               | if OpenScope Block then OpenScope Block ${
                        $0.type = Xcond_statement;
                        $0.condpart = $<3;
-                       $0.thenpart = $<7;
-                       var_block_close(config2context(config), CloseParallel);
+                       $0.thenpart = $<6;
+                       var_block_close(c, CloseParallel);
                }$
+               | IfPart NEWLINE ${ $0 = $<1; }$
 
        $*exec
        // This scope is closed in CondSuffix
@@ -3675,6 +3694,7 @@ defined.
                | switch OpenScope Block ${
                        $0 = $<3;
                }$
+               | SwitchPart NEWLINE ${ $0 = $<1; }$
 
 ###### print exec cases
 
@@ -3920,6 +3940,10 @@ various declarations in the parse context.
                | DeclareProgram
                | DeclareStruct
                | NEWLINE
+               | ERROR NEWLINE ${
+                       tok_err(c,
+                               "error: unhandled parse error", &$1);
+               }$
 
        ## top level grammar
 
@@ -3949,19 +3973,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
+               | const SimpleConstList NEWLINE
 
        ConstList -> ComplexConsts
+               | NEWLINE ConstList
        ComplexConsts -> ComplexConst ComplexConsts
                | ComplexConst
        ComplexConst -> SimpleConstList NEWLINE
-       SimpleConstList -> Const ; SimpleConstList
+       SimpleConstList -> SimpleConstList ; Const
                | Const
-               | Const ; SimpleConstList ;
+               | SimpleConstList ;
 
        $*type
        CType -> Type   ${ $0 = $<1; }$
@@ -3971,7 +3994,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,21 +4002,22 @@ 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);
                }
        } }$
+       | ERROR NEWLINE ${ tok_err(c, "Syntax error in constant", &$1); }$
 
 ###### print const decls
        {
@@ -4048,7 +4072,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 +4079,14 @@ analysis is a bit more interesting at this level.
                        c->prog = $<1;
        } }$
 
-
        $*binode
-       Program -> program OpenScope Varlist Block OptNL ${
+       Program -> program OpenScope Varlist Block ${
                $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);
+               var_block_close(c, CloseSequential);
+               if (c->scope_stack && !c->parse_error) abort();
                }$
 
        Varlist -> Varlist ArgDecl ${
@@ -4081,7 +4099,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;
        } }$
@@ -4191,7 +4209,7 @@ things which will likely grow as the languages grows.
 ###### demo: hello
 
        const:
-               pi ::= 3.1415926
+               pi ::= 3.141_592_6
                four ::= 2 + 2 ; five ::= 10/2
        const pie ::= "I like Pie";
                cake ::= "The cake is"
@@ -4280,7 +4298,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: