/** * \pre * - \c *edgesp and \c edge_counts were computed by * \c ielr_compute_internal_follow_edges. * \post * - \c *always_followsp is a new \c bitsetv with \c ngotos rows and * \c ntokens columns. * - <tt>(*always_followsp)[i][j]</tt> is set iff token \c j is an always * follow (that is, it's computed by internal and successor edges) of goto * \c i. * - Rows of \c *edgesp have been realloc'ed and extended to include * successor follow edges. \c edge_counts has not been updated. */ static void ielr_compute_always_follows (goto_number ***edgesp, int const edge_counts[], bitsetv *always_followsp) { *always_followsp = bitsetv_create (ngotos, ntokens, BITSET_FIXED); { goto_number *edge_array = xnmalloc (ngotos, sizeof *edge_array); goto_number i; for (i = 0; i < ngotos; ++i) { goto_number nedges = edge_counts[i]; { int j; transitions *trans = states[to_state[i]]->transitions; FOR_EACH_SHIFT (trans, j) bitset_set ((*always_followsp)[i], TRANSITION_SYMBOL (trans, j)); for (; j < trans->num; ++j) { symbol_number sym = TRANSITION_SYMBOL (trans, j); if (nullable[sym - ntokens]) edge_array[nedges++] = map_goto (to_state[i], sym); } } if (nedges - edge_counts[i]) { (*edgesp)[i] = xnrealloc ((*edgesp)[i], nedges + 1, sizeof *(*edgesp)[i]); memcpy ((*edgesp)[i] + edge_counts[i], edge_array + edge_counts[i], (nedges - edge_counts[i]) * sizeof *(*edgesp)[i]); (*edgesp)[i][nedges] = END_NODE; } } free (edge_array); } relation_digraph (*edgesp, ngotos, always_followsp); if (trace_flag & trace_ielr) { fprintf (stderr, "always follow edges:\n"); relation_print (*edgesp, ngotos, stderr); fprintf (stderr, "always_follows:\n"); debug_bitsetv (*always_followsp); } }
static void build_relations(void) { int i; int j; int k; Value_t *rulep; Value_t *rp; shifts *sp; int length; int nedges; int done_flag; Value_t state1; Value_t stateno; int symbol1; int symbol2; Value_t *shortp; Value_t *edge; Value_t *states; Value_t **new_includes; includes = NEW2(ngotos, Value_t *); edge = NEW2(ngotos + 1, Value_t); states = NEW2(maxrhs + 1, Value_t); for (i = 0; i < ngotos; i++) { nedges = 0; state1 = from_state[i]; symbol1 = accessing_symbol[to_state[i]]; for (rulep = derives[symbol1]; *rulep >= 0; rulep++) { length = 1; states[0] = state1; stateno = state1; for (rp = ritem + rrhs[*rulep]; *rp >= 0; rp++) { symbol2 = *rp; sp = shift_table[stateno]; k = sp->nshifts; for (j = 0; j < k; j++) { stateno = sp->shift[j]; if (accessing_symbol[stateno] == symbol2) break; } states[length++] = stateno; } add_lookback_edge(stateno, *rulep, i); length--; done_flag = 0; while (!done_flag) { done_flag = 1; rp--; if (ISVAR(*rp)) { stateno = states[--length]; edge[nedges++] = map_goto(stateno, *rp); if (nullable[*rp] && length > 0) done_flag = 0; } } } if (nedges) { includes[i] = shortp = NEW2(nedges + 1, Value_t); for (j = 0; j < nedges; j++) shortp[j] = edge[j]; shortp[nedges] = -1; } } new_includes = transpose(includes, ngotos); for (i = 0; i < ngotos; i++) if (includes[i]) FREE(includes[i]); FREE(includes); includes = new_includes; FREE(edge); FREE(states); }
static void initialize_F(void) { int i; int j; int k; shifts *sp; Value_t *edge; unsigned *rowp; Value_t *rp; Value_t **reads; int nedges; int stateno; int symbol; int nwords; nwords = ngotos * tokensetsize; F = NEW2(nwords, unsigned); reads = NEW2(ngotos, Value_t *); edge = NEW2(ngotos + 1, Value_t); nedges = 0; rowp = F; for (i = 0; i < ngotos; i++) { stateno = to_state[i]; sp = shift_table[stateno]; if (sp) { k = sp->nshifts; for (j = 0; j < k; j++) { symbol = accessing_symbol[sp->shift[j]]; if (ISVAR(symbol)) break; SETBIT(rowp, symbol); } for (; j < k; j++) { symbol = accessing_symbol[sp->shift[j]]; if (nullable[symbol]) edge[nedges++] = map_goto(stateno, symbol); } if (nedges) { reads[i] = rp = NEW2(nedges + 1, Value_t); for (j = 0; j < nedges; j++) rp[j] = edge[j]; rp[nedges] = -1; nedges = 0; } } rowp += tokensetsize; } SETBIT(F, 0); digraph(reads); for (i = 0; i < ngotos; i++) { if (reads[i]) FREE(reads[i]); } FREE(reads); FREE(edge); }
/** * \pre: * - \c ritem_sees_lookahead_set was computed by * \c ielr_compute_ritem_sees_lookahead_set. * \post: * - Each of \c *edgesp and \c *edge_countsp is a new array of size * \c ::ngotos. * - <tt>(*edgesp)[i]</tt> points to a \c goto_number array of size * <tt>(*edge_countsp)[i]+1</tt>. * - In such a \c goto_number array, the last element is \c ::END_NODE. * - All remaining elements are the indices of the gotos to which there is an * internal follow edge from goto \c i. * - There is an internal follow edge from goto \c i to goto \c j iff both: * - The from states of gotos \c i and \c j are the same. * - The transition nonterminal for goto \c i appears as the first RHS * symbol of at least one production for which both: * - The LHS is the transition symbol of goto \c j. * - All other RHS symbols are nullable nonterminals. * - In other words, the follows of goto \c i include the follows of * goto \c j and it's an internal edge because the from states are the * same. */ static void ielr_compute_internal_follow_edges (bitset ritem_sees_lookahead_set, goto_number ***edgesp, int **edge_countsp) { *edgesp = xnmalloc (ngotos, sizeof **edgesp); *edge_countsp = xnmalloc (ngotos, sizeof **edge_countsp); { bitset sources = bitset_create (ngotos, BITSET_FIXED); goto_number i; for (i = 0; i < ngotos; ++i) (*edge_countsp)[i] = 0; for (i = 0; i < ngotos; ++i) { int nsources = 0; { rule **rulep; for (rulep = derives[states[to_state[i]]->accessing_symbol - ntokens]; *rulep; ++rulep) { /* If there is at least one RHS symbol, if the first RHS symbol is a nonterminal, and if all remaining RHS symbols (if any) are nullable nonterminals, create an edge from the LHS symbol's goto to the first RHS symbol's goto such that the RHS symbol's goto will be the source of the edge after the eventual relation_transpose below. Unlike in ielr_compute_always_follows, I use a bitset for edges rather than an array because it is possible that multiple RHS's with the same first symbol could fit and thus that we could end up with redundant edges. With the possibility of redundant edges, it's hard to know ahead of time how large to make such an array. Another possible redundancy is that source and destination might be the same goto. Eliminating all these possible redundancies now might possibly help performance a little. I have not proven any of this, but I'm guessing the bitset shouldn't entail much of a performance penalty, if any. */ if (bitset_test (ritem_sees_lookahead_set, (*rulep)->rhs - ritem)) { goto_number source = map_goto (from_state[i], item_number_as_symbol_number (*(*rulep)->rhs)); if (i != source && !bitset_test (sources, source)) { bitset_set (sources, source); ++nsources; ++(*edge_countsp)[source]; } } } } if (nsources == 0) (*edgesp)[i] = NULL; else { (*edgesp)[i] = xnmalloc (nsources + 1, sizeof *(*edgesp)[i]); { bitset_iterator biter_source; bitset_bindex source; int j = 0; BITSET_FOR_EACH (biter_source, sources, source, 0) (*edgesp)[i][j++] = source; } (*edgesp)[i][nsources] = END_NODE; } bitset_zero (sources); } bitset_free (sources); } relation_transpose (edgesp, ngotos); if (trace_flag & trace_ielr) { fprintf (stderr, "internal_follow_edges:\n"); relation_print (*edgesp, ngotos, stderr); } }
/** * \note * - FIXME: It might be an interesting experiment to compare the space and * time efficiency of computing \c item_lookahead_sets either: * - Fully up front. * - Just-in-time, as implemented below. * - Not at all. That is, just let annotations continue even when * unnecessary. */ bool ielr_item_has_lookahead (state *s, symbol_number lhs, size_t item, symbol_number lookahead, state ***predecessors, bitset **item_lookahead_sets) { if (!item_lookahead_sets[s->number]) { size_t i; item_lookahead_sets[s->number] = xnmalloc (s->nitems, sizeof item_lookahead_sets[s->number][0]); for (i = 0; i < s->nitems; ++i) item_lookahead_sets[s->number][i] = NULL; } if (!item_lookahead_sets[s->number][item]) { item_lookahead_sets[s->number][item] = bitset_create (ntokens, BITSET_FIXED); /* If this kernel item is the beginning of a RHS, it must be the kernel item in the start state, and so its LHS has no follows and no goto to check. If, instead, this kernel item is the successor of the start state's kernel item, there are still no follows and no goto. This situation is fortunate because we want to avoid the - 2 below in both cases. Actually, IELR(1) should never invoke this function for either of those cases because (1) follow_kernel_items will never reference a kernel item for this RHS because the end token blocks sight of the lookahead set from the RHS's only nonterminal, and (2) no reduction has a lookback dependency on this lookahead set. Nevertheless, I didn't change this test to an aver just in case the usage of this function evolves to need those two cases. In both cases, the current implementation returns the right result. */ if (s->items[item] > 1) { /* If the LHS symbol of this item isn't known (because this is a top-level invocation), go get it. */ if (!lhs) { unsigned int i; for (i = s->items[item]; !item_number_is_rule_number (ritem[i]); ++i) ; lhs = rules[item_number_as_rule_number (ritem[i])].lhs->number; } /* If this kernel item is next to the beginning of the RHS, then check all predecessors' goto follows for the LHS. */ if (item_number_is_rule_number (ritem[s->items[item] - 2])) { state **predecessor; aver (lhs != accept->number); for (predecessor = predecessors[s->number]; *predecessor; ++predecessor) bitset_or (item_lookahead_sets[s->number][item], item_lookahead_sets[s->number][item], goto_follows[map_goto ((*predecessor)->number, lhs)]); } /* If this kernel item is later in the RHS, then check all predecessor items' lookahead sets. */ else { state **predecessor; for (predecessor = predecessors[s->number]; *predecessor; ++predecessor) { size_t predecessor_item; for (predecessor_item = 0; predecessor_item < (*predecessor)->nitems; ++predecessor_item) if ((*predecessor)->items[predecessor_item] == s->items[item] - 1) break; aver (predecessor_item != (*predecessor)->nitems); ielr_item_has_lookahead (*predecessor, lhs, predecessor_item, 0 /*irrelevant*/, predecessors, item_lookahead_sets); bitset_or (item_lookahead_sets[s->number][item], item_lookahead_sets[s->number][item], item_lookahead_sets[(*predecessor)->number] [predecessor_item]); } } } } return bitset_test (item_lookahead_sets[s->number][item], lookahead); }