]> ocean-lang.org Git - ocean/blobdiff - csrc/oceani.mdc
oceani: add more syntax error handling.
[ocean] / csrc / oceani.mdc
index 342182ee3ae6804f08950595bd3d6a3361eb95f5..a8653cc669adbe9ee21d894ecb9744e99b46ce66 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:
 
@@ -1454,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;
 
@@ -1475,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
@@ -1662,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)
@@ -1685,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;
@@ -1745,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;
                }
@@ -1948,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;
@@ -1994,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;
 
@@ -2012,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 ${ {
@@ -2039,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);
                } }$
@@ -2052,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);
@@ -2145,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);
                        }
                        }$
@@ -2156,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);
                        }
                        }$
@@ -2167,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);
                        }
                        }$
@@ -2188,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;
        }
 
@@ -2256,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) {
@@ -2295,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) {
@@ -2313,22 +2327,22 @@ 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;
@@ -2341,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;
@@ -2383,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)
@@ -2393,7 +2406,6 @@ 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 == NULL) {
@@ -2409,7 +2421,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;
@@ -2604,11 +2615,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
@@ -2724,11 +2733,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
@@ -2871,22 +2878,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:
@@ -3017,44 +3020,43 @@ 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); }$
+               | : Statementlist  ${ $0 = $<2; }$
 
        Statementlist -> ComplexStatements ${ $0 = reorder_bilist($<1); }$
 
        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);
                        }$
+               | Newlines ${ $0 = NULL; }$
                ## ComplexStatement Grammar
 
        $*binode
@@ -3073,6 +3075,7 @@ is in-place.
                | SimpleStatements ; ${ $0 = $<1; }$
 
        SimpleStatement -> pass ${ $0 = NULL; }$
+               | ERROR ${ tok_err(c, "Syntax error in statement", &$1); }$
                ## SimpleStatement Grammar
 
 ###### print binode cases
@@ -3117,11 +3120,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;
@@ -3261,7 +3262,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 {
@@ -3337,10 +3338,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;
@@ -3528,36 +3527,44 @@ 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 ${
+               | whilePart CondSuffix ${
                        $0 = $<2;
                        $0->condpart = $1.condpart; $1.condpart = NULL;
                        $0->dopart = $1.dopart; $1.dopart = NULL;
                        }$
-               | SwitchPart CondSuffix ${
+               | switchPart CondSuffix ${
                        $0 = $<2;
                        $0->condpart = $<1;
                        }$
-               | IfPart IfSuffix ${
+               | 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;
@@ -3565,107 +3572,103 @@ defined.
                        $0->casepart = $<1;
                }$
 
+       $void
+       Case -> case
+               | NEWLINE Case
        $*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);
                }$
 
        $*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); }$
+               | NEWLINE IfSuffix ${ $0 = $<2; }$
                | 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);
                }$
 
+       $void
+       Then -> then
+               | NEWLINE Then
+       While -> while
+               | NEWLINE While
+       Do -> do
+               | NEWLINE Do
        $*exec
        // These scopes are closed in CondSuffix
-       ForPart -> for OpenScope SimpleStatements ${
+       forPart -> for OpenScope SimpleStatements ${
                        $0 = reorder_bilist($<3);
                }$
                |  for OpenScope Block ${
                        $0 = $<3;
                }$
 
-       ThenPart -> then OpenScope SimpleStatements ${
+       ThenPart -> Then OpenScope SimpleStatements ${
                        $0 = reorder_bilist($<3);
-                       var_block_close(config2context(config), CloseSequential);
+                       var_block_close(c, CloseSequential);
                }$
-               |  then OpenScope Block ${
+               |  Then OpenScope Block ${
                        $0 = $<3;
-                       var_block_close(config2context(config), CloseSequential);
-               }$
-
-       ThenPartNL -> ThenPart OptNL ${
-                       $0 = $<1;
+                       var_block_close(c, CloseSequential);
                }$
 
        // This scope is closed in CondSuffix
-       WhileHead -> while OpenScope Block ${
+       WhileHead -> While OpenScope Block ${
                $0 = $<3;
                }$
-
-       $cond_statement
-       ForThen -> ForPart OptNL ThenPartNL ${
-                       $0.forpart = $<1;
-                       $0.thenpart = $<3;
-               }$
-               | ForPart OptNL ${
-                       $0.forpart = $<1;
+       whileHead -> while OpenScope Block ${
+               $0 = $<3;
                }$
 
+       $cond_statement
        // This scope is closed in CondSuffix
-       WhilePart -> while OpenScope Expression Block ${
+       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 = $<3;
+               }$
+       WhilePart -> While OpenScope Expression Block ${
+                       $0.type = Xcond_statement;
+                       $0.condpart = $<3;
                        $0.dopart = $<4;
                }$
+               | WhileHead Do Block ${
+                       $0.type = Xcond_statement;
+                       $0.condpart = $<1;
+                       $0.dopart = $<3;
+               }$
 
-       IfPart -> if OpenScope Expression OpenScope Block ${
+       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);
                }$
 
        $*exec
        // This scope is closed in CondSuffix
-       SwitchPart -> switch OpenScope Expression ${
+       switchPart -> switch OpenScope Expression ${
                        $0 = $<3;
                }$
                | switch OpenScope Block ${
@@ -3916,6 +3919,10 @@ various declarations in the parse context.
                | DeclareProgram
                | DeclareStruct
                | NEWLINE
+               | ERROR NEWLINE ${
+                       tok_err(c,
+                               "error: unhandled parse error", &$1);
+               }$
 
        ## top level grammar
 
@@ -3945,19 +3952,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; }$
@@ -3967,7 +3973,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;
@@ -3975,21 +3981,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
        {
@@ -4044,7 +4051,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);
@@ -4053,16 +4059,16 @@ analysis is a bit more interesting at this level.
        } }$
 
        $*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();
+               var_block_close(c, CloseSequential);
+               if (c->scope_stack && !c->parse_error) abort();
                }$
                | ERROR ${
-                       tok_err(config2context(config),
+                       tok_err(c,
                                "error: unhandled parse error", &$1);
                }$
 
@@ -4076,7 +4082,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;
        } }$
@@ -4186,7 +4192,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"
@@ -4275,7 +4281,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: