]> ocean-lang.org Git - ocean/blobdiff - csrc/oceani.mdc
oceani: updates for new approach to parsing indents.
[ocean] / csrc / oceani.mdc
index a3eba942acbd3cd92e407ee61b83446e1893bbf0..97c195382cd8955c4e0c16e154125e5d7fa2e93b 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>
@@ -148,8 +151,8 @@ structures can be used.
        ## core functions
 
        #include <getopt.h>
-       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 <gmp.h>
-       #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 = $<FL; }$
+               | { SimpleFieldList } ${ $0 = $<SFL; }$
+               | IN OptNL FieldLines OUT ${ $0 = $<FL; }$
+               | SimpleFieldList EOL ${ $0 = $<SFL; }$
+
+       FieldLines -> SimpleFieldList Newlines ${ $0 = $<SFL; }$
+               | FieldLines SimpleFieldList Newlines ${
+                       $SFL->prev = $<FL;
+                       $0 = $<SFL;
                }$
 
-       SimpleFieldList -> Field ; ${ $0 = $<1; }$
-               | SimpleFieldList Field ; ${
-                       $2->prev = $<1;
-                       $0 = $<2;
+       SimpleFieldList -> Field ${ $0 = $<F; }$
+               | SimpleFieldList ; Field ${
+                       $F->prev = $<SFL;
+                       $0 = $<F;
                }$
+               | SimpleFieldList ; ${
+                       $0 = $<SFL;
+               }$
+               | ERROR ${ tok_err(c, "Syntax error in struct field", &$1); }$
 
        Field -> 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 = $<Sl; }$
+               | { SimpleStatements } ${ $0 = reorder_bilist($<SS); }$
+               | SimpleStatements ; ${ $0 = reorder_bilist($<SS); }$
+               | SimpleStatements EOL ${ $0 = reorder_bilist($<SS); }$
+               | IN OptNL Statementlist OUT ${ $0 = $<Sl; }$
+
+       OpenBlock -> OpenScope { IN OptNL Statementlist OUT OptNL } ${ $0 = $<Sl; }$
+               | OpenScope { SimpleStatements } ${ $0 = reorder_bilist($<SS); }$
+               | OpenScope SimpleStatements ; ${ $0 = reorder_bilist($<SS); }$
+               | OpenScope SimpleStatements EOL ${ $0 = reorder_bilist($<SS); }$
+               | IN OpenScope OptNL Statementlist OUT ${ $0 = $<Sl; }$
+
+       UseBlock -> { OpenScope IN OptNL Statementlist OUT OptNL } ${ $0 = $<Sl; }$
+               | { OpenScope SimpleStatements } ${ $0 = reorder_bilist($<SS); }$
+               | IN OpenScope OptNL Statementlist OUT ${ $0 = $<Sl; }$
+
+       ColonBlock -> { IN OptNL Statementlist OUT OptNL } ${ $0 = $<Sl; }$
+               | { SimpleStatements } ${ $0 = reorder_bilist($<SS); }$
+               | : SimpleStatements ; ${ $0 = reorder_bilist($<SS); }$
+               | : SimpleStatements EOL ${ $0 = reorder_bilist($<SS); }$
+               | : IN OptNL Statementlist OUT ${ $0 = $<Sl; }$
+
+       Statementlist -> ComplexStatements ${ $0 = reorder_bilist($<CS); }$
 
        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 ${
-                       $0 = reorder_bilist($<1);
+       ComplexStatement -> SimpleStatements Newlines ${
+                       $0 = reorder_bilist($<SS);
+                       }$
+               |  SimpleStatements ; Newlines ${
+                       $0 = reorder_bilist($<SS);
                        }$
                ## ComplexStatement Grammar
 
@@ -3073,9 +3115,9 @@ is in-place.
                        $0->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 = $<CS;
+                       $0->forpart = $<FP;
+                       $0->thenpart = $<TP;
+                       $0->condpart = $WP.condpart; $WP.condpart = NULL;
+                       $0->dopart = $WP.dopart; $WP.dopart = NULL;
+                       var_block_close(c, CloseSequential);
+                       }$
+               | ForPart OptNL WhilePart CondSuffix ${
+                       $0 = $<CS;
+                       $0->forpart = $<FP;
+                       $0->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 = $<CS;
+                       $0->condpart = $WP.condpart; $WP.condpart = NULL;
+                       $0->dopart = $WP.dopart; $WP.dopart = NULL;
+                       }$
+               | SwitchPart OptNL CasePart CondSuffix ${
+                       $0 = $<CS;
+                       $0->condpart = $<SP;
+                       $CP->next = $0->casepart;
+                       $0->casepart = $<CP;
                        }$
-               | SwitchPart CondSuffix ${
-                       $0 = $<2;
-                       $0->condpart = $<1;
+               | SwitchPart : IN OptNL CasePart CondSuffix OUT Newlines ${
+                       $0 = $<CS;
+                       $0->condpart = $<SP;
+                       $CP->next = $0->casepart;
+                       $0->casepart = $<CP;
                        }$
                | IfPart IfSuffix ${
-                       $0 = $<2;
-                       $0->condpart = $1.condpart; $1.condpart = NULL;
-                       $0->thenpart = $1.thenpart; $1.thenpart = NULL;
+                       $0 = $<IS;
+                       $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 = $<CS;
+                       $CP->next = $0->casepart;
+                       $0->casepart = $<CP;
                }$
-               | case Expression OpenScope Block ${
-                       $0 = calloc(1,sizeof(struct casepart));
-                       $0->value = $<2;
-                       $0->action = $<4;
-                       var_block_close(config2context(config), CloseParallel);
+               | CasePart CondSuffix ${
+                       $0 = $<CS;
+                       $CP->next = $0->casepart;
+                       $0->casepart = $<CP;
                }$
 
-       $*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);
-               }$
-               | else OpenScope Block ${
-                       $0 = new(cond_statement);
-                       $0->elsepart = $<3;
-                       var_block_close(config2context(config), CloseElse);
-               }$
-               | Newlines else OpenScope CondStatement ${
+               | Newlines ElsePart ${ $0 = $<EP; }$
+               | ElsePart ${$0 = $<EP; }$
+
+       ElsePart -> else OpenBlock Newlines ${
                        $0 = new(cond_statement);
-                       $0->elsepart = $<4;
-                       var_block_close(config2context(config), CloseElse);
+                       $0->elsepart = $<OB;
+                       var_block_close(c, CloseElse);
                }$
                | else OpenScope CondStatement ${
                        $0 = new(cond_statement);
-                       $0->elsepart = $<3;
-                       var_block_close(config2context(config), CloseElse);
+                       $0->elsepart = $<CS;
+                       var_block_close(c, CloseElse);
                }$
 
+       $*casepart
+       CasePart -> case Expression OpenScope ColonBlock ${
+                       $0 = calloc(1,sizeof(struct casepart));
+                       $0->value = $<Ex;
+                       $0->action = $<Bl;
+                       var_block_close(c, CloseParallel);
+               }$
 
        $*exec
        // These scopes are closed in CondSuffix
-       ForPart -> 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 = $<Bl;
                }$
 
-       ThenPartNL -> ThenPart OptNL ${
-                       $0 = $<1;
-               }$
-
-       // This scope is closed in CondSuffix
-       WhileHead -> while OpenScope Block ${
-               $0 = $<3;
+       ThenPart -> then OpenBlock ${
+                       $0 = $<OB;
+                       var_block_close(c, CloseSequential);
                }$
 
        $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;
+       WhilePart -> while UseBlock OptNL do Block ${
+                       $0.condpart = $<UB;
+                       $0.dopart = $<Bl;
                }$
-               | WhileHead OptNL do Block ${
-                       $0.type = Xcond_statement;
-                       $0.condpart = $<1;
-                       $0.dopart = $<4;
+               | while OpenScope Expression ColonBlock ${
+                       $0.condpart = $<Exp;
+                       $0.dopart = $<Bl;
                }$
 
-       IfPart -> 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 = $<UB;
+                       $0.thenpart = $<Bl;
+               }$
+               | if OpenScope Expression OpenScope ColonBlock ClosePara ${
+                       $0.condpart = $<Ex;
+                       $0.thenpart = $<Bl;
                }$
-               | if OpenScope Block OptNL then OpenScope Block ${
-                       $0.type = Xcond_statement;
-                       $0.condpart = $<3;
-                       $0.thenpart = $<7;
-                       var_block_close(config2context(config), CloseParallel);
+               | if OpenScope Expression OpenScope OptNL then Block ClosePara ${
+                       $0.condpart = $<Ex;
+                       $0.thenpart = $<Bl;
                }$
 
        $*exec
        // This scope is closed in CondSuffix
        SwitchPart -> switch OpenScope Expression ${
-                       $0 = $<3;
+                       $0 = $<Ex;
                }$
-               | switch OpenScope Block ${
-                       $0 = $<3;
+               | switch UseBlock ${
+                       $0 = $<Bl;
                }$
 
 ###### print exec cases
@@ -3684,13 +3727,13 @@ defined.
                struct casepart *cp;
                if (cs->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($<Vl);
+               $0->right = $<Bl;
+               var_block_close(c, CloseSequential);
+               if (c->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;
        } }$
@@ -4190,14 +4233,14 @@ things which will likely grow as the languages grows.
 
 ###### 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")