abort:
while (tk.num != TK_newline && tk.num != TK_eof)
tk = token_next(state);
+ free(p.body);
return err;
}
s->name.len, s->name.txt);
}
if (errs) {
- free(g);
+ free(g); // FIXME free content
g = NULL;
}
}
fprintf(stderr, "Error at line %d: %s\n",
tk.line, err);
token_close(state);
- free(g);
+ free(g); // FIXME free content
return NULL;
}
done using `add_first` above and only needs to be done once as the
"first" sets are now stable and will not change.
+###### grammar fields
+ struct symset *follow;
+
###### follow code
for (p = 0; p < g->production_count; p++) {
###### follow code
- for (again = 0, p = 0;
+ for (check_again = 0, p = 0;
p < g->production_count;
p < g->production_count-1
- ? p++ : again ? (again = 0, p = 0)
+ ? p++ : check_again ? (check_again = 0, p = 0)
: p++) {
struct production *pr = g->productions[p];
int b;
break;
if (symset_union(&g->follow[bs->num],
&g->follow[pr->head->num]))
- again = 1;
+ check_again = 1;
if (!bs->nullable)
break;
}
We now just need to create and initialise the `follow` list to get a
complete function.
-###### grammar fields
- struct symset *follow;
-
###### functions
static void build_follow(struct grammar *g)
{
- int s, again, p;
+ int s, check_again, p;
g->follow = calloc(g->num_syms, sizeof(g->follow[0]));
for (s = 0; s < g->num_syms; s++)
g->follow[s] = INIT_SYMSET;
continue;
if (s->line_like)
is->starts_line = 1;
- again = 1;
+ check_again = 1;
if (type >= LALR) {
// Need the LA set.
int to_end;
{
struct symset first = INIT_SYMSET;
struct itemset *is;
- int again;
+ int check_again;
unsigned short la = 0;
if (type >= LALR) {
// LA set just has eof
// production 0, offset 0 (with no data)
symset_add(&first, item_num(0, 0), la);
add_itemset(g, first, Non, 0, type);
- for (again = 0, is = g->items;
+ for (check_again = 0, is = g->items;
is;
- is = is->next ?: again ? (again = 0, g->items) : NULL) {
+ is = is->next ?: check_again ? (check_again = 0, g->items) : NULL) {
int i;
struct symset done = INIT_SYMSET;
if (is->completed)
continue;
is->completed = 1;
- again = 1;
+ check_again = 1;
## complete itemset
## derive itemsets
symset_free(done);
}
}
-###### functions
-
static void gen_states(FILE *f, struct grammar *g)
{
int i;
return -1;
}
+### Memory allocation
+
+The `scanner` returns tokens in a local variable - we want them in allocated
+memory so they can live in the `asn_stack`. Similarly the `asn` produced by
+a reduce is in a large buffer. Both of these require some allocation and
+copying, hence `memdup` and `tok_copy`.
+
+###### parser includes
+ #include <memory.h>
+
+###### parser functions
+
+ void *memdup(void *m, int len)
+ {
+ void *ret;
+ if (len == 0)
+ return NULL;
+ ret = malloc(len);
+ memcpy(ret, m, len);
+ return ret;
+ }
+
+ static struct token *tok_copy(struct token tk)
+ {
+ struct token *new = malloc(sizeof(*new));
+ *new = tk;
+ return new;
+ }
+
### The state stack.
The core data structure for the parser is the stack. This tracks all
return indents;
}
-### Memory allocation
-
-The `scanner` returns tokens in a local variable - we want them in allocated
-memory so they can live in the `asn_stack`. Similarly the `asn` produced by
-a reduce is in a large buffer. Both of these require some allocation and
-copying, hence `memdup` and `tokcopy`.
-
-###### parser includes
- #include <memory.h>
-
-###### parser functions
-
- void *memdup(void *m, int len)
- {
- void *ret;
- if (len == 0)
- return NULL;
- ret = malloc(len);
- memcpy(ret, m, len);
- return ret;
- }
-
- static struct token *tok_copy(struct token tk)
- {
- struct token *new = malloc(sizeof(*new));
- *new = tk;
- return new;
- }
-
### The heart of the parser.
Now we have the parser. For each token we might shift it, trigger a