From 51ba21ffd913b8eb700699567567560f99a2aa9c Mon Sep 17 00:00:00 2001 From: NeilBrown Date: Fri, 7 Jun 2019 08:51:23 +1000 Subject: [PATCH] parsergen: allow prefix code for do_reduce to be provided. This allow common variables to be declared and initialised for all reduce fragments. Use this in oceani to declare 'c' holding the parser context, so we don't need to call config2context in so many places. Signed-off-by: NeilBrown --- csrc/oceani.mdc | 108 ++++++++++++++++++++++----------------------- csrc/parsergen.mdc | 18 +++++--- 2 files changed, 67 insertions(+), 59 deletions(-) diff --git a/csrc/oceani.mdc b/csrc/oceani.mdc index 1f4805e..f36bbdb 100644 --- a/csrc/oceani.mdc +++ b/csrc/oceani.mdc @@ -123,6 +123,9 @@ structures can be used. #define config2context(_conf) container_of(_conf, struct parse_context, \ config) +###### Parser: reduce + struct parse_context *c = config2context(config); + ###### Parser: code #include @@ -1002,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: @@ -1675,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) @@ -1698,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; @@ -2001,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; @@ -2053,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); } }$ @@ -2159,7 +2160,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); } }$ @@ -2170,7 +2171,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); } }$ @@ -2181,7 +2182,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); } }$ @@ -2268,38 +2269,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) { @@ -2307,16 +2308,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) { @@ -2325,22 +2326,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; @@ -2353,9 +2354,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; @@ -3259,7 +3260,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 { @@ -3530,7 +3531,7 @@ defined. $0->thenpart = $<2; $0->condpart = $3.condpart; $3.condpart = NULL; $0->dopart = $3.dopart; $3.dopart = NULL; - var_block_close(config2context(config), CloseSequential); + var_block_close(c, CloseSequential); }$ | forPart WhilePart CondSuffix ${ $0 = $<3; @@ -3538,7 +3539,7 @@ defined. $0->thenpart = NULL; $0->condpart = $2.condpart; $2.condpart = NULL; $0->dopart = $2.dopart; $2.dopart = NULL; - var_block_close(config2context(config), CloseSequential); + var_block_close(c, CloseSequential); }$ | whilePart CondSuffix ${ $0 = $<2; @@ -3554,14 +3555,14 @@ defined. $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; @@ -3577,7 +3578,7 @@ defined. $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 @@ -3586,12 +3587,12 @@ defined. | else OpenScope Block ${ $0 = new(cond_statement); $0->elsepart = $<3; - 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 @@ -3612,11 +3613,11 @@ defined. ThenPart -> Then OpenScope SimpleStatements ${ $0 = reorder_bilist($<3); - var_block_close(config2context(config), CloseSequential); + var_block_close(c, CloseSequential); }$ | Then OpenScope Block ${ $0 = $<3; - var_block_close(config2context(config), CloseSequential); + var_block_close(c, CloseSequential); }$ // This scope is closed in CondSuffix @@ -3654,13 +3655,13 @@ defined. $0.type = Xcond_statement; $0.condpart = $<3; $0.thenpart = $<5; - var_block_close(config2context(config), CloseParallel); + var_block_close(c, CloseParallel); }$ | if OpenScope Block Then OpenScope Block ${ $0.type = Xcond_statement; $0.condpart = $<3; $0.thenpart = $<6; - var_block_close(config2context(config), CloseParallel); + var_block_close(c, CloseParallel); }$ $*exec @@ -3966,7 +3967,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; @@ -3974,17 +3975,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); } @@ -4043,7 +4044,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); @@ -4057,11 +4057,11 @@ analysis is a bit more interesting at this level. $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) abort(); }$ | ERROR ${ - tok_err(config2context(config), + tok_err(c, "error: unhandled parse error", &$1); }$ @@ -4075,7 +4075,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; } }$ diff --git a/csrc/parsergen.mdc b/csrc/parsergen.mdc index 2fdbf45..478482e 100644 --- a/csrc/parsergen.mdc +++ b/csrc/parsergen.mdc @@ -1872,13 +1872,14 @@ pieces of code provided in the grammar file, so they are generated first. ###### parser_generate - static void gen_parser(FILE *f, struct grammar *g, char *file, char *name) + static void gen_parser(FILE *f, struct grammar *g, char *file, char *name, + struct code_node *pre_reduce) { gen_known(f, g); gen_non_term(f, g); gen_goto(f, g); gen_states(f, g); - gen_reduce(f, g, file); + gen_reduce(f, g, file, pre_reduce); gen_free(f, g); fprintf(f, "#line 0 \"gen_parser\"\n"); @@ -2112,14 +2113,18 @@ automatically freed. This is equivalent to assigning `NULL` to the pointer. ###### functions - static void gen_reduce(FILE *f, struct grammar *g, char *file) + static void gen_reduce(FILE *f, struct grammar *g, char *file, + struct code_node *code) { int i; - fprintf(f, "#line 0 \"gen_reduce\"\n"); + fprintf(f, "#line 1 \"gen_reduce\"\n"); fprintf(f, "static int do_reduce(int prod, void **body, struct token_config *config, void *ret)\n"); fprintf(f, "{\n"); fprintf(f, "\tint ret_size = 0;\n"); + if (code) + code_node_print(f, code, file); + fprintf(f, "#line 4 \"gen_reduce\"\n"); fprintf(f, "\tswitch(prod) {\n"); for (i = 0; i < g->production_count; i++) { struct production *p = g->productions[i]; @@ -2316,6 +2321,7 @@ parser with neither. "grammar" must be provided. struct code_node *hdr = NULL; struct code_node *code = NULL; struct code_node *gram = NULL; + struct code_node *pre_reduce = NULL; for (s = table; s; s = s->next) { struct text sec = s->section; if (tag && !strip_tag(&sec, tag)) @@ -2326,6 +2332,8 @@ parser with neither. "grammar" must be provided. code = s->code; else if (text_is(sec, "grammar")) gram = s->code; + else if (text_is(sec, "reduce")) + pre_reduce = s->code; else { fprintf(stderr, "Unknown content section: %.*s\n", s->section.len, s->section.txt); @@ -2397,7 +2405,7 @@ file with the code section (if any) and the parser tables and function. if (f) { if (code) code_node_print(f, code, infile); - gen_parser(f, g, infile, name); + gen_parser(f, g, infile, name, pre_reduce); fclose(f); } else { fprintf(stderr, "Cannot create %s.c\n", -- 2.43.0