int PGBuildLR1::MAKE_KERNEL (int camefrom, int symb) { int i, la, c, first_item; // prt_log ("\nFROM STATE %d MAKING STATE %d\n\n", camefrom, n_states); hash_no = 0; first_item = -1; f_lrkernel[n_states] = n_lrkernels; for (c = 0; c < N_clo[camefrom]; c++) // For all closure items. { i = Closure[camefrom][c].item; // Get item #. if (item[i].symb == symb) // If head symbol match? { if (first_item == -1) first_item = i; la = Closure[camefrom][c].LA; // Get old LA. hash_no += N_terms*(i+1) + la; // Add both to hash number. lrkernel [n_lrkernels].item = i+1; // Make new LR1 item. lrkernel [n_lrkernels].LA = la; // Keep same look ahead. // prt_item ("Making LR1 kernel ", i+1, la); if (++n_lrkernels >= max_lrkernels) MemCrash ("Number of LR(1) kernels", max_lrkernels); } } l_lrkernel[n_states] = n_lrkernels; if (n_lrkernels == f_lrkernel[n_states]) InternalError (255); // PRT_LRSTA (n_states); return first_item; }
void PGBuildLR1::MAKE_KERNEL (int state) // Make lrkernel items for state 0. { int p, head; head = 0; // Head symbol is the Goal symbol. f_lrkernel[state] = 0; for (p = F_prod [head]; p < F_prod [head+1]; p++) // Should be only one production. { lrkernel [n_lrkernels].item = f_item[p]; lrkernel [n_lrkernels].LA = 0; // Not used anyway, 0 is safe. if (++n_lrkernels >= max_lrkernels) MemCrash ("Number of LR(1) kernels", max_lrkernels); } l_lrkernel[state] = n_lrkernels; f_final [state] = 0; // Nothing. l_final [state] = 0; // Nothing. }
int PGBuildLR1::TRANSITION (int sym) { uint probe; LRKERNEL temp; int compatible = 1; int fk, lk, nk, ni, fi, i, j, k, x, y, p; // PRT_LRSTA (n_states); fk = f_lrkernel[n_states]; lk = l_lrkernel[n_states]; nk = lk - fk; fi = 0; x = n_states; #ifdef PG_DEBUG PRT_LRSTA (x); #endif if (optn[PG_CLR_PARSER]) { if (nk > 1) { LR1_SORT (lrkernel, fk, lk); } probe = hash_no % max_hashes; while ((y = hash_vector[probe]) != -1) // Get state y with same hash cell. { if (l_lrkernel[y] - f_lrkernel[y] == nk) // Same number of kernels? { for (i = f_lrkernel[x], j = f_lrkernel[y]; i < l_lrkernel[x]; i++, j++) { if (lrkernel[i].item != lrkernel[j].item) goto Next1; if (lrkernel[i].LA != lrkernel[j].LA ) goto Next1; } n_lrkernels = fk; // Reset this. return (y); // Return old state number. } Next1: probe = (hash_no *= 65549) / hash_div; } } else // PG_LR_PARSER or PG_LALR_PARSER { ni = LR0_SORT (lrkernel, fk, lk); if (ni == 1) // Number of lrkernel items is 1 or 0? { i = lrkernel[fk].item; // Get item # if (item[i].symb == -32767) { if (optn[PG_LALR_PARSER]) { p = item [i].prod; // Get production. reduce_state[p] = 1; // Mark production for reduce-state creation. return (-p); // Return production number. } fi = i; // Save the final item. } } probe = hash_no % max_hashes; while ((y = hash_vector[probe]) != -1) // Get state y with same hash cell. { #ifdef PG_DEBUG PRINT ("Comparing to:\n\n"); PRT_LRSTA (y); #endif int n = 0, m = 0; memset (item_added, 0, n_items); for (i = f_lrkernel[x]; i < l_lrkernel[x]; i++) { if (item_added[lrkernel[i].item] == 0) // Item not added yet? { n++; item_added [lrkernel[i].item] = 1; // Add it. } } for (i = f_lrkernel[y]; i < l_lrkernel[y]; i++) { if (item_added[lrkernel[i].item] == 0) goto Next2; // Missmatch! if (item_added[lrkernel[i].item] == 1) // Match!? { m++; item_added [lrkernel[i].item] = 2; } } if (n == m) // LALR(1) satisfied? { if (!optn[PG_LALR_PARSER]) { if (!COMPATIBLE (x, y)) { compatible = 0; goto Next2; } } #ifdef PG_DEBUG PRINT ("Got a match!\n"); #endif n_lrkernels = fk; // Reset this, not a new state. if (fi) // If final item defined? { p = item [fi].prod; // Get production. reduce_state[p] = 1; // Mark production for reduce-state creation. return (-p); // Return production number. } return (y); // Return old state number. } Next2: probe = (hash_no *= 65549) / hash_div; } } if (!compatible) extra_states++; if (fi) // If final item defined by LR or LALR? { #ifdef PG_DEBUG PRINT ("Reduce-ony state!\n"); #endif p = item [fi].prod; // Get production. reduce_state[p] = 1; // Mark production for reduce-state creation. return (-p); // Return production number. } // NEW STATE ... #ifdef PG_DEBUG PRINT ("New state %d\n", n_states); #endif accessor [n_states] = sym; hash_vector [probe] = n_states; DO_CLOSURE (n_states); if (n_states % 50000 == 0) prt_log (" %7d states\n", n_states); if (n_states >= max_states) MemCrash ("Number of states", max_states); return (n_states++); }
void LGCheckGrammar::make_prod (int h, int p) { int t, t0, tn, sym, q, n, P, I, T; F_TAIL [N_PRODS] = N_TAILS; RET_NUMB [N_PRODS] = ret_numb[p]; RET_NAME [N_PRODS] = ret_name[p]; // printf ("\nmake_prod (%d, %d) ...\n", h, p); n = 0; t0 = f_tail[p]; tn = l_tail[p]; for (t = t0; t < tn; t++) { if (vector [t-t0] == 1) // keep this tail ? { n++; sym = tail[t]; Check: if (sym < 0 && nullable [-sym]) { q = f_prod[-sym]; if (l_tail[q] - f_tail[q] == 0) // Null first production? { if (l_tail [q+1] - f_tail [q+1] == 1) // Only one tail on 2nd production? { sym = tail [f_tail[q+1]]; // First (and only) tail of 2nd prod. goto Check; } } } if (N_TAILS >= max_tails) MemCrash ("Number of tail symbols", max_tails); TAILSYM[N_TAILS++] = sym; // if (sym < 0) printf (" %s", head_name[-sym]); // else printf (" %s", term_name[ sym]); } } // if (n == 0) printf ("<null>\n"); // else printf ("\n"); L_TAIL [N_PRODS] = N_TAILS; // Check for previous existence of this production. if (n > 0) { if (n == 1 && -sym == h) goto Undo; for (P = F_PROD [N_HEADS]; P < N_PRODS; P++) { int PLO = L_TAIL [P] - F_TAIL [P]; int PLN = L_TAIL [N_PRODS] - F_TAIL [N_PRODS]; if (PLO == PLN) { I = F_TAIL [N_PRODS]; for (T = F_TAIL [P]; T < L_TAIL [P]; T++) { // char a[50]; // char b[50]; // symstr(TAILSYM[T], a); // symstr(TAILSYM[I], b); // printf ("Comparing %s to %s\n", b, a); if (TAILSYM[T] != TAILSYM[I++]) goto NextP; } // printf ("already exists\n\n"); goto Undo; // Production already exists! } NextP: continue; } // printf ("new production accepted\n"); } else // New production is NULL! { int FP = F_PROD [N_HEADS]; if (N_PRODS > FP) // Already have some productions? { if (F_TAIL [FP] == L_TAIL [FP]) goto Undo; // Already have NULL. } // Move current productions down one. for (P = N_PRODS; P > FP; P--) { F_TAIL [P] = F_TAIL [P-1]; L_TAIL [P] = L_TAIL [P-1]; } // Create NULL production in first place. F_TAIL [P] = F_TAIL [P+1]; L_TAIL [P] = F_TAIL [P+1]; // printf ("<null> production accepted\n"); } if (++N_PRODS >= max_prods) MemCrash ("Number of productions", max_prods); return; Undo: N_TAILS = F_TAIL [N_PRODS]; // Reset number of tails. // printf ("new production rejected\n"); return; }
void LGCheckGrammar::P_UNREACHABLES () { char *head_used; int n_unreachables; int *used_list, h, p, t, s, i, n_used, x; ALLOC (used_list, n_heads); ALLOC (head_used, n_heads); memset(head_used, 0, n_heads); i = 0; // Goal symbol! n_used = 0; // Start with 0. head_used[i] = 1; // Mark goal symbol used. used_list[n_used++] = i; // Add goal symbol to list. // Traverse from goal symbol and mark all nonterminals that are used. for (; i < n_used; i++) { h = used_list[i]; // Pick head from list. // printf ("%s\n", head_name[h]); for (p = f_prod[h]; p < l_prod[h]; p++) // All of its rules. { for (t = f_tail[p]; t < l_tail[p]; t++) // All of its tails. { if ((s = tail[t]) < 0) // Nonterminal? { if (head_used[-s] == 0) // Not used? { head_used[-s] = 1; // Mark it used. used_list[n_used++] = -s; // Add it to list. // printf (" %s used\n", head_name[-s]); } } } } } // Traverse from {ignore} symbols and mark all nonterminals that are used. int n_ignores = 0; for (int H = 0; H < n_heads; H++) { if (head_type[H] & IGNORESYM) { n_ignores++; // printf ("%s unused\n", head_name[H]); i = n_used; head_used[H] = 1; // Mark ignore symbol used. used_list[n_used++] = H; // Add ignore symbol to list. for (; i < n_used; i++) { h = used_list[i]; // Pick head from list. // printf ("%s\n", head_name[h]); for (p = f_prod[h]; p < l_prod[h]; p++) // All of its rules. { for (t = f_tail[p]; t < l_tail[p]; t++) // All of its tails. { if ((s = tail[t]) < 0) // Nonterminal? { if (head_used[-s] == 0) // Not marked yet? { head_used[-s] = 1; // Mark it used. used_list[n_used++] = -s; // Add it to list. // printf (" %s used %d\n", head_name[-s], n_used); } } } } } } } FREE (used_list, n_heads); // List unreachable heads ... n_unreachables = 0; for (h = 0; h < n_heads; h++) { if (!(head_type[h] & IGNORESYM) && head_used[h] == 0) // Not {ignore} and not used? { if (head_line[h] != 0) // Not generated symbol? { if (head_type[h] & SETNAME) // If setname (or escape symbol). { // Nothing. } else if (head_type[h] & LEXICON) // If lexicon symbol. { n_unreachables++; head_type[h] |= UNREACHABLE; x = strlen(head_name[h]) -1; head_name[h][x] = 0; sprintf (string, "<%s> is not reachable from the goal symbol. To ignore, rename to {%s}.\n", head_name[h]+1, head_name[h]+1); head_name[h][x] = '>'; prt_error (string, head_name[h], 0, head_line[h]); } else { n_unreachables++; head_type[h] |= UNREACHABLE; sprintf (string, "%s is not reachable from the goal symbol. To ignore, rename to {%s}.\n", head_name[h], head_name[h]); prt_error (string, head_name[h], 0, head_line[h]); } } } } FREE (head_used, n_heads); // If we have any unreachables ... if (n_ignores && n_errors == 0) { if (n_prods + n_unreachables >= max_prods) MemCrash ("Number of productions", max_prods); if (n_tails + n_unreachables >= max_tails) MemCrash ("Number of tail symbols", max_tails); RenumberProductions (n_ignores); } }