X-Git-Url: https://ocean-lang.org/code/?a=blobdiff_plain;f=csrc%2Fparsergen.mdc;h=82d09b3ed1b497362b77ff7a264dff837499c39a;hb=1bfa4fc8cfc5fafa5b2b3ae6bdd9b77a4242e74a;hp=d2ff89844d2e616e0f10e470c0a7dbffde9492a7;hpb=5281589bf4d9a66ce106b160e1272f1c51d7ac15;p=ocean diff --git a/csrc/parsergen.mdc b/csrc/parsergen.mdc index d2ff898..82d09b3 100644 --- a/csrc/parsergen.mdc +++ b/csrc/parsergen.mdc @@ -100,6 +100,7 @@ symbol. struct production { unsigned short precedence; enum assoc assoc; + char line_like; ## production fields }; struct grammar { @@ -277,6 +278,9 @@ declares how it associates. This level is stored in each symbol listed and may be inherited by any production which uses the symbol. A production inherits from the last symbol which has a precedence. +The symbols on the first precedence line have the lowest precedence. +Subsequent lines introduce symbols with higher precedence. + ###### grammar fields struct text current_type; int type_isref; @@ -493,12 +497,15 @@ Now we have all the bits we need to parse a full production. goto abort; } vs = sym_find(g, tk.txt); - if (vs->type != Virtual) { + if (vs->num == TK_newline) + p.line_like = 1; + else if (vs->type != Virtual) { err = "symbol after $$ must be virtual"; goto abort; + } else { + p.precedence = vs->precedence; + p.assoc = vs->assoc; } - p.precedence = vs->precedence; - p.assoc = vs->assoc; tk = token_next(state); } if (tk.num == TK_open) { @@ -1287,12 +1294,11 @@ When itemsets are created we assign a precedence to the itemset from the complete item, if there is one. We ignore the possibility of there being two and don't (currently) handle precedence in such grammars. When completing a grammar we ignore any item where DOT is -followed by a terminal with a precedence lower (numerically higher) -than that for the itemset. Unless the terminal has right -associativity, we also ignore items where the terminal has the same -precedence. The result is that unwanted items are still in the -itemset, but the terminal doesn't get into the go to set, so the item -is ineffective. +followed by a terminal with a precedence lower than that for the +itemset. Unless the terminal has right associativity, we also ignore +items where the terminal has the same precedence. The result is that +unwanted items are still in the itemset, but the terminal doesn't get +into the go to set, so the item is ineffective. ###### complete itemset for (i = 0; i < is->items.cnt; i++) { @@ -1311,7 +1317,7 @@ is ineffective. continue; s = pr->body[bs]; if (s->precedence && is->precedence && - is->precedence < s->precedence) + is->precedence > s->precedence) /* This terminal has a low precedence and * shouldn't be shifted */ @@ -1335,8 +1341,12 @@ is ineffective. int to_end; add_first(pr, bs+1, &LA, g, &to_end); if (to_end) { - struct symset ss = set_find(g, is->items.data[i]); - symset_union(&LA, &ss); + if (pr->line_like) + symset_add(&LA, TK_newline, 0); + else { + struct symset ss = set_find(g, is->items.data[i]); + symset_union(&LA, &ss); + } } sn = save_set(g, LA); LA = set_find(g, sn); @@ -1404,8 +1414,7 @@ with a pre-existing itemset). pos = symset_find(&newitemset, pr->head->num); if (bp + 1 == pr->body_size && pr->precedence > 0 && - (precedence == 0 || - pr->precedence < precedence)) { + pr->precedence > precedence) { // new itemset is reducible and has a precedence. precedence = pr->precedence; assoc = pr->assoc; @@ -1634,6 +1643,8 @@ it up a bit. First the items, with production number and associativity. printf(" [%d%s]", s->precedence, assoc_names[s->assoc]); } + if (pr->line_like) + printf(" $$NEWLINE"); printf("\n"); } @@ -1799,14 +1810,20 @@ counted, and are reported as non-critical. This will not affect a int p = item_prod(itm); int bp = item_index(itm); struct production *pr = g->productions[p]; + struct symbol *s; - if (bp < pr->body_size && - pr->body[bp]->type == Terminal) { - /* shiftable */ - int sym = pr->body[bp]->num; - if (symset_find(&shifts, sym) < 0) - symset_add(&shifts, sym, itm); - } + if (bp >= pr->body_size || + pr->body[bp]->type != Terminal) + /* not shiftable */ + continue; + + s = pr->body[bp]; + if (s->precedence && is->precedence) + /* Precedence resolves this, so no conflict */ + continue; + + if (symset_find(&shifts, s->num) < 0) + symset_add(&shifts, s->num, itm); } /* Now look for reductions and conflicts */ for (j = 0; j < is->items.cnt; j++) { @@ -1826,7 +1843,7 @@ counted, and are reported as non-critical. This will not affect a int k; for (k = 0; k < la.cnt; k++) { int pos = symset_find(&shifts, la.syms[k]); - if (pos >= 0) { + if (pos >= 0 && la.syms[k] != TK_newline) { if (symset_find(&la, TK_newline) < 0) { printf(" State %d has SHIFT/REDUCE conflict on ", i); cnt++; @@ -1957,7 +1974,8 @@ The go to table is stored in a simple array of `sym` and corresponding short reduce_prod; short reduce_size; short reduce_sym; - short starts_line; + char starts_line; + char newline_only; short min_prefix; }; @@ -2006,13 +2024,15 @@ The go to table is stored in a simple array of `sym` and corresponding } if (prod >= 0) - fprintf(f, "\t[%d] = { %d, goto_%d, %d, %d, %d, %d, %d },\n", + fprintf(f, "\t[%d] = { %d, goto_%d, %d, %d, %d, %d, %d, %d },\n", i, is->go_to.cnt, i, prod, g->productions[prod]->body_size, g->productions[prod]->head->num, - is->starts_line, is->min_prefix); + is->starts_line, + g->productions[prod]->line_like, + is->min_prefix); else - fprintf(f, "\t[%d] = { %d, goto_%d, -1, -1, -1, %d, %d },\n", + fprintf(f, "\t[%d] = { %d, goto_%d, -1, -1, -1, %d, 0, %d },\n", i, is->go_to.cnt, i, is->starts_line, is->min_prefix); } @@ -2105,10 +2125,13 @@ automatically freed. This is equivalent to assigning `NULL` to the pointer. fputs("\n", f); for (i = 0; i < p->body_size; i++) { if (p->body[i]->struct_name.txt && - p->body[i]->isref && - used[i]) + used[i]) { // assume this has been copied out - fprintf(f, "\t\t*(void**)body[%d] = NULL;\n", i); + if (p->body[i]->isref) + fprintf(f, "\t\t*(void**)body[%d] = NULL;\n", i); + else + fprintf(f, "\t\tmemset(body[%d], 0, sizeof(struct %.*s));\n", i, p->body[i]->struct_name.len, p->body[i]->struct_name.txt); + } } free(used); } @@ -2841,7 +2864,13 @@ checks if a given token is in any of these look-ahead sets. continue; } force_reduce: - if (states[tos->state].reduce_prod >= 0) { + if (states[tos->state].reduce_prod >= 0 && + states[tos->state].newline_only && + tk->num != TK_newline && tk->num != TK_eof && tk->num != TK_out) { + /* Anything other than newline in an error as this + * production must end at EOL + */ + } else if (states[tos->state].reduce_prod >= 0) { void **body; void *res; const struct state *nextstate = &states[tos->state]; @@ -3089,8 +3118,8 @@ an error. # calc: grammar - $LEFT * / $LEFT + - + $LEFT * / Session -> Session Line | Line