www.pudn.com > 12cocorc.zip > CRT.C
#include#include #include #include #include "crt.h" #include "cra.h" #include "crf.h" #include "collect.h" #include "set.h" #include "crs.h" #define NODES_SIZE 100 /* Graph Node Table */ #define NODES_EXTEND 20 Collection nodes_tab; #define TERM_SIZE 100 /* Terminal Table */ #define TERM_EXTEND 20 Collection term_tab; #define NTERM_SIZE 100 /* Nonterminal Table */ #define NTERM_EXTEND 20 Collection nterm_tab; #define CLASS_SIZE 20 /* Set Table */ #define CLASS_EXTEND 10 Collection class_tab; #define SYMSET_SIZE 20 /* Symbol Sets Table */ #define SYMSET_EXTEND 10 Collection symset_tab; #define PRAGMA_SIZE 5 /* Pragmas Tables */ #define PRAGMA_EXTEND 2 Collection pragma_tab; #define NAME_SIZE 1 /* Names Tables */ #define NAME_EXTEND 1 Collection name_tab; struct SemText global_defs; /* TRUE => Globals Definitions */ int first_weak_set = -1; /* First weak set index in symsettab */ int ignore_case = FALSE; /* TRUE => Ignore case */ FILE *lstfile; int no_sym = 0; Set ANY_SET; /* Set of all characters */ Set ALL_TERMS; /* Set of all Terminals */ static Set FollowVisited; /* Visited graph Nodes in Comp_Follow */ static Set FirstVisited; /* Visited graph Nodes in Comp_First */ static Set Set1; static Set Set2; static int CurrentNt; int C_option = FALSE; /* TRUE => Generate Compiler */ int F_option = FALSE; /* TRUE => First & Follow */ int G_option = FALSE; /* TRUE => Graph listing */ int L_option = FALSE; /* TRUE => Generate listing */ int P_option = FALSE; /* TRUE => Generate Parser Only */ int S_option = FALSE; /* TRUE => Symbol Table Listing */ int T_option = FALSE; /* TRUE => Grammar Test Only */ int D_option = FALSE; /* TRUE => Debug #line */ int Z_option = FALSE; /* TRUE => Generate .hpp and .cpp files */ int A_option = FALSE; /* TRUE => Automata */ int O_option = FALSE; /* TRUE => Generate OR only Terminal Conditions */ int GenCplusplus = FALSE; char Frames_Path[100] = ""; char c_ext[100] = "c"; char h_ext[100] = "h"; static void PrintTerm(int t); static void PrintNTerm(int t); extern int Errors; typedef void (*Graph_Func) (int gp); typedef void (*Graph_FuncInt) (int gp, int p); typedef void (*Graph_FuncSet) (int gp, Set *s); void upcase(char *s) { while (*s) { if (*s >= 'a' && *s <= 'z') *s -= 32; s++; } } /***************************************************************** *** Graph Construction Functions *** ******************************************************************/ /* Create a graph Node and initialize it */ static int MakeGraphNode(int type) { int gp; PGraphNode gn; gp = Collection_New(&nodes_tab); gn = GetGraphP(gp); gn->type = type; gn->next = NIL; gn->pointer1 = NIL; gn->pointer2 = NIL; gn->pointer3 = NIL; gn->pointer4 = NIL; return gp; } /* create a symbol node, Terminal and Nonterminal */ int MakeGraph(int type, int sp) { int gp; PGraphNode gn; gp = MakeGraphNode(type); gn = GetGraphP(gp); CR_ASSERT(gn != NULL); gn->SLine = S_Line; gn->SYMLINK = sp; /* set pointer to Table */ return gp; } /* */ void SetGraphLine(int current, int line) { PGraphNode gn; gn = GetGraphP(current); CR_ASSERT(gn != NULL); gn->SLine = line; } /* create a semantic code node T_SEM , T_ATTR */ int MakeSemGraph(int type, long filepos, int len, int line, int col) { int gp; PGraphNode gn; gp = MakeGraphNode(type); gn = GetGraphP(gp); CR_ASSERT(gn != NULL); gn->SEMPOS = filepos; /*kws*/ gn->SEMLEN = len; gn->SEMLINE = line; gn->SEMCOL = col; return gp; } /* create an operator node with INNER => "link" */ int MakeGraphOp(int type, int link) { int gp; PGraphNode gn; gp = MakeGraphNode(type); gn = GetGraphP(gp); CR_ASSERT(gn != NULL); gn->INNER = link; return gp; } /* link two nodes */ int LinkGraph(int current, int next) { PGraphNode gn; do { gn = GetGraphP(current); CR_ASSERT(gn != NULL); current = gn->next; } while (current!=NIL); gn->next = next; return next; } /* link two alt nodes */ int LinkAltGraph(int current, int nextalt) { PGraphNode gn; gn = GetGraphP(current); CR_ASSERT(gn != NULL); gn->ALT = nextalt; return nextalt; } /* prints a graph to the list file */ void ShowGraph(int gp) { PGraphNode gn; while (gp > NIL) { gn = GetGraphP(gp); CR_ASSERT(gn != NULL); fprintf(lstfile, "%d^", gp); switch(gn->type) { case T_T : case T_WT: { PTermNode tn = GetTermP(gn->SYMLINK); fprintf(lstfile, "%s", tn->name); break; } case T_NT : { PNTermNode ntn = GetNTermP(gn->SYMLINK); fprintf(lstfile, "%s", ntn->name); break; } case T_OPT: fprintf(lstfile, "["); ShowGraph(gn->INNER); fprintf(lstfile, "]"); break; case T_REP: fprintf(lstfile, "{"); ShowGraph(gn->INNER); fprintf(lstfile, "}"); break; case T_ALT: { PGraphNode gn1; fprintf(lstfile, "("); ShowGraph(gn->INNER); gn1 = gn; while (gn1->ALT) { fprintf(lstfile, "|"); gn1 = GetGraphP(gn1->ALT); CR_ASSERT(gn1 != NULL); ShowGraph(gn1->INNER); } fprintf(lstfile, ")"); break; } case T_SEM: fprintf(lstfile, "SEM"); break; case T_ATTR: fprintf(lstfile, "ATTR"); break; case T_SYNC: fprintf(lstfile, "SYNC"); break; case T_ANY: fprintf(lstfile, "ANY"); break; } gp = gn->next; fprintf(lstfile, " "); } fprintf(lstfile, "%d^", gp); } /***************************************************************** *** Pragmas management Functions *** *****************************************************************/ /* compare a Pragma Name with "symbol" */ static int CompPragmaName(PPragmaNode tn, PName name) { return !strcmp(tn->name, name); } int FindPragma(PName name) { int tp; tp = Collection_FirstThat(&pragma_tab, (Collection_Comp) CompPragmaName, name); return tp; } /* install a pragma */ int NewPragma(PName name) { int pp; PPragmaNode pn; pp = Collection_New(&pragma_tab); pn = GetPragmaP(pp); CR_ASSERT(pn != NULL); strcpy(pn->name, name); pn->has_attr = FALSE; return pp; } void SetPragmaText(int sp, int gp) { PPragmaNode pn; PGraphNode gn; pn = GetPragmaP(sp); CR_ASSERT(pn != NULL); gn = GetGraphP(gp); CR_ASSERT(gn != NULL); pn->has_attr = TRUE; pn->sem_text.pos = gn->SEMPOS; pn->sem_text.len = gn->SEMLEN; pn->sem_text.line = gn->SEMLINE; pn->sem_text.col = gn->SEMCOL; } /* add Pragmas to Tokens before generating the Scanner NoSym & MAXT are marks to the last Token and Before first pragma */ void SetupPragmas() { PPragmaNode pn; PTermNode tn; int c, i, tp; c = Collection_Count(&pragma_tab); for (i = 0; i < c; i++) { pn = GetPragmaP(i); CR_ASSERT(pn != NULL); tp = Collection_New(&term_tab); tn = GetTermP(tp); CR_ASSERT(tn != NULL); tn->type = T_PRAGMATOKEN; strcpy(tn->name, pn->name); SetTermName(tn); } } /***************************************************************** *** Names management Functions *** *****************************************************************/ /* compare a Name "Name" with "symbol" */ static int CompNameName(PNameNode tn, PName name) { return !strcmp(tn->name, name); } /* get table index of terminal "symbol" */ int FindName(PName name) { int tp; tp = Collection_FirstThat(&name_tab, (Collection_Comp) CompNameName, name); return tp; } /* set the symbolic name of a terminal */ void NewName(PName name, PName user_name) { int np; PNameNode nn; np = Collection_New(&name_tab); nn = GetNameP(np); CR_ASSERT(nn != NULL); strcpy(nn->name, name); strcpy(nn->user_name, user_name); } /***************************************************************** *** Terminal management Functions *** *****************************************************************/ /* compare a terminal name with "symbol" */ static int CompTermName(PTermNode tn, PName name) { return !strcmp(tn->name, name); } /* get table index of terminal "symbol" */ int FindTerm(PName name) { int tp; tp = Collection_FirstThat(&term_tab, (Collection_Comp) CompTermName, name); return tp; } void SetTermName(PTermNode tn) { char str[MAX_ID_LEN]; char temp[MAX_ID_LEN]; char name[MAX_ID_LEN + 100]; char *t; strcpy(temp, tn->name); name[0] = '\0'; t = temp; if (*t == '"' || *t == '\'') { t++; t[strlen(t) - 1] = '\0'; } while (*t) { SymCharName(*t, str); strcat(name, str); t++; } /* ensure that the name is not longer that MAX_ID_LEN */ name[MAX_ID_LEN - 4] = '\0'; strcat(name, "Sym"); strcpy(tn->gen_name, name); } /* install a new terminal */ int NewTerm(PName name) { int tp; PTermNode tn; char TempName[MAX_STR_LEN]; strcpy(TempName, name); TempName[MAX_ID_LEN - 1] = '\0'; tp = FindTerm(TempName); if (tp != UNDEF) tn = (PTermNode) GetTermP(tp); else { tp = Collection_New(&term_tab); tn = GetTermP(tp); CR_ASSERT(tn != NULL); strcpy(tn->name, TempName); strcpy(tn->gen_name, ""); tn->type = T_CLASSTOKEN; } return tp; } /* return the symbolic name of a terminal */ void GetTermName(int tp, PName name) { PTermNode tn; PNameNode nn; int np; tn = GetTermP(tp); CR_ASSERT(tn != NULL); if (tn->gen_name[0] == '\0') { /* no genname */ np = FindName(tn->name); if (np == UNDEF) SetTermName(tn); else { nn = GetNameP(np); strcpy(tn->gen_name, nn->user_name); } } strcpy(name, tn->gen_name); } /* print each terminal data */ static void Func_ShowTerm(PTermNode tn, int tp) { CR_ASSERT(tn != NULL); fprintf(lstfile, "%3d|%s\t=\t", tp, tn->name); switch (tn->type) { case T_CLASSTOKEN: fprintf(lstfile, "Class Token"); break; case T_CLASSLITTOKEN: fprintf(lstfile, "Class Literal Token"); break; case T_LITTOKEN: fprintf(lstfile, "Literal Token"); break; case T_PRAGMATOKEN: fprintf(lstfile, "Pragma Token"); break; } fprintf(lstfile, "\n"); } /* print terminal table to lstfile */ void ShowTermTab() { fprintf(lstfile, "\nTERMINALS\n"); Collection_ForEachPos(&term_tab, (Collection_FuncPos) Func_ShowTerm); } /***************************************************************** *** Class management Functions *** *****************************************************************/ /* find set by name */ static int CompClassName(PClassNode cn, PName name) { return !strcmp(cn->name, name); } int FindClass(PName name) { int cp; cp = Collection_FirstThat(&class_tab, (Collection_Comp) CompClassName, name); return cp; } /* find set by contents */ static int CompClassData(PClassNode cn, Set *data) { CR_ASSERT(cn != NULL); return Set_Equal(&(cn->data), data); } int FindClassWithSet(PSet data) { int cp; cp = Collection_FirstThat(&class_tab, (Collection_Comp) CompClassData, data); return cp; } /* install a set to the set table */ int NewClass(PName name, PSet set) { int cp; PClassNode cn; cp = Collection_New(&class_tab); cn = GetClassP(cp); CR_ASSERT(cn != NULL); strcpy(cn->name, name); Set_Init(&cn->data); Set_Union(&cn->data, set); return cp; } int GetClassWithName(PName name, PSet set) { int cp; PClassNode cn; Set_Clean(set); if ((cp = FindClass(name)) == UNDEF) return UNDEF; cn = GetClassP(cp); CR_ASSERT(cn != NULL); Set_Union(set, &cn->data); return cp; } /* print each set info */ static void Func_ShowClass(PClassNode cn, int cp) { CR_ASSERT(cn != NULL); if (!cp) return; fprintf(lstfile, "%3d|%s\t=\t", cp, cn->name); Set_ForEach(&cn->data, (Set_Func) PrintAscii); fprintf(lstfile, "\n"); } /* print set table */ void ShowClassTab() { fprintf(lstfile, "\nClass\n"); Collection_ForEachPos(&class_tab, (Collection_FuncPos) Func_ShowClass); } /***************************************************************** *** Symbol Sets management Functions *** *****************************************************************/ /* install a symbol set */ int NewSymSet(PSet set, byte typ) { PSymSetNode sn; int sp; sp = Collection_New(&symset_tab); sn = GetSymSetP(sp); CR_ASSERT(sn != NULL); sn->type = typ; Set_Init(&sn->set); Set_Union(&sn->set, set); if (typ == T_WT && first_weak_set == -1) first_weak_set = sp; return sp; } /* install an ANY Terminals set */ int NewANY() { return NewSymSet(&ALL_TERMS, T_ANY); } /* get symset data by index */ void GetSymSet(int sp, PSet set) { PSymSetNode sn; if (sp == NIL) return; sn = GetSymSetP(sp); Set_Union(set, &sn->set); } /* symset union by index */ void IncludeSymSet(int sp, PSet set) { PSymSetNode sn; sn = GetSymSetP(sp); CR_ASSERT(sn != NULL); Set_Union(&sn->set, set); } /* symset diference by index */ void ExcludeSymSet(int sp, PSet set) { PSymSetNode sn; sn = GetSymSetP(sp); CR_ASSERT(sn != NULL); Set_Diference(&sn->set, set); } /* show symset */ static void Func_ShowSymSet(PSymSetNode sn, int sp) { CR_ASSERT(sn != NULL); fprintf(lstfile, "%3d|", sp); switch (sn->type) { case T_WT : fprintf(lstfile, "WEAK T = \t"); break; case T_ANY : fprintf(lstfile, "ANY = \t"); break; case T_SYNC: fprintf(lstfile, "SYNC = \t"); break; } Set_ForEach(&sn->set, (Set_Func) PrintTerm); fprintf(lstfile, "\n"); } void ShowSymSetTab() { fprintf(lstfile, "\nSYMBOL SETS\n"); Collection_ForEachPos(&symset_tab, (Collection_FuncPos) Func_ShowSymSet); } /***************************************************************** *** Nonterminals management Functions *** *****************************************************************/ /* find a nonterminal by name */ static int CompNTerm(PNTermNode ntn, PName name) { return !strcmp(ntn->name, name); } int FindNTerm(PName name) { int ntp; ntp = Collection_FirstThat(&nterm_tab, (Collection_Comp) CompNTerm, name); return ntp; } /* install a nonterminal */ int NewNTerm(PName name) { int ntp; PNTermNode ntn; if ((ntp = FindNTerm(name)) == UNDEF) { ntp = Collection_New(&nterm_tab); ntn = GetNTermP(ntp); CR_ASSERT(ntn != NULL); strcpy(ntn->name, name); ntn->graph = NIL; ntn->sem = NIL; ntn->nullable = FALSE; ntn->ready = FALSE; ntn->has_attr = FALSE; ntn->reachable = FALSE; ntn->attr = NIL; Set_Init(&ntn->first); Set_Init(&ntn->follow); Set_Init(&ntn->AuxNt); } return ntp; } /* get nonterminal First Set */ static void GetNTermFirst(int ntp, Set *first) { PNTermNode ntn; ntn = GetNTermP(ntp); CR_ASSERT(ntn != NULL); Set_Union(first, &(ntn->first)); } /* get nonterminal Follow Set */ static void GetNTermFollow(int ntp, Set *follow) { PNTermNode ntn; ntn = GetNTermP(ntp); CR_ASSERT(ntn != NULL); Set_Union(follow, &(ntn->follow)); } /* get nonterminal Nullable */ static int IsNTermNullable(int ntp) { PNTermNode ntn; ntn = GetNTermP(ntp); CR_ASSERT(ntn != NULL); return ntn->nullable; } /* show nonterminal */ static void Func_ShowNTerm(PNTermNode ntn, int ntp) { if (!ntp) return; fprintf(lstfile, "%3d|%s\t:", ntp, ntn->name); if (ntn->nullable) fprintf(lstfile, " (Nullable)"); if (G_option) { fprintf(lstfile, "\n\tGraph: "); ShowGraph(ntn->graph); } if (F_option) { fprintf(lstfile, "\n\tStart With :\t"); Set_ForEach(&ntn->first, (Set_Func) PrintTerm); fprintf(lstfile, "\n\tFollow =\t"); Set_ForEach(&ntn->follow, (Set_Func) PrintTerm); } fprintf(lstfile, "\n"); } /* show nonterminal tab */ void ShowNTermTab() { fprintf(lstfile, "\nNO TERMINALS\n"); Collection_ForEachPos(&nterm_tab, (Collection_FuncPos) Func_ShowNTerm); } /* apply "fn" to each nonterminal graph */ static void ForEachNTermGraph(Graph_Func fn) { PNTermNode ntn; int c, i; c = Collection_Count(&nterm_tab); for (i = 1; i < c; i++) { /* for each nonterminal */ CurrentNt = i; ntn = GetNTermP(i); CR_ASSERT(ntn != NULL); (*fn) (ntn->graph); } } /* apply "fn" to each nonterminal graph pasing an "p" as parameter */ static void ForEachNTermGraph_Int(Graph_FuncInt fn, int p) { PNTermNode ntn; int c, i; c = Collection_Count(&nterm_tab); for (i = 1; i < c; i++) { CurrentNt = i; ntn = GetNTermP(i); CR_ASSERT(ntn != NULL); (*fn) (ntn->graph, p); } } /***************************************************************** *** First & Follow Functions *** *****************************************************************/ /* compute follow links in a graph */ void CompFollowNode(int gp, int fgp) { PGraphNode gn; int next; while (gp>NIL) { gn = GetGraphP(gp); CR_ASSERT(gn != NULL); next = (gn->next != NIL) ? gn->next : fgp; switch(gn->type) { case T_OPT: CompFollowNode(gn->INNER, next); break; case T_REP: CompFollowNode(gn->INNER, gp); break; case T_ALT: { PGraphNode gn1; int gp1 = gp; while (gp1 > NIL) { gn1 = GetGraphP(gp1); CR_ASSERT(gn1 != NULL); CompFollowNode(gn1->INNER, next); gp1 = gn1->ALT; } break; } } if (gn->next == NIL) gn->next = -fgp; gp = gn->next; } } /* compute Follow links for all graphs */ static void CompAllFollowNodes() { ForEachNTermGraph_Int((Graph_FuncInt) CompFollowNode, 0); } /* TRUE => node is Nullable */ static int IsNullableNode(int gp) { PGraphNode gn; if (gp <= NIL) return TRUE; gn = GetGraphP(gp); CR_ASSERT(gn != NULL); switch(gn->type) { case T_NT : return IsNTermNullable(gn->SYMLINK); case T_OPT: case T_REP: case T_SEM: case T_SYNC: return TRUE; case T_ALT: if (IsNullableGraph(gn->INNER)) return TRUE; if (gn->ALT) return IsNullableNode(gn->ALT); } return FALSE; /* Terminal, Weak Terminal => Not Nullable */ } /* TRUE => graph is Nullable */ int IsNullableGraph(int gp) { if (gp <= NIL) return TRUE; if (IsNullableNode(gp)) { PGraphNode gn = GetGraphP(gp); CR_ASSERT(gn != NULL); return IsNullableGraph(gn->next); } return FALSE; } /* TRUE => graph is Nullable (use follow links) */ static int IsNullableNextGraph(int gp) { if (gp <= NIL) return TRUE; if (IsNullableNode(gp)) { PGraphNode gn = GetGraphP(gp); CR_ASSERT(gn != NULL); return IsNullableNextGraph(abs(gn->next)); } return FALSE; } static void CompAllNullable() { PNTermNode ntn; int i, c, change; do { /* Loop until nothing changes */ change = FALSE; c = Collection_Count(&nterm_tab); for (i = 1; i < c; i++) { /* for each nonterminal */ ntn = GetNTermP(i); CR_ASSERT(ntn != NULL); if (!ntn->nullable) if (IsNullableNextGraph(ntn->graph)) { ntn->nullable = TRUE; ntn->ready = TRUE; change = TRUE; } } } while (change); } /* get First Terminals of a graph STRICT = TRUE ==> don't use follow links */ static void CompFirst(int gp, Set *first, int STRICT) { PGraphNode gn; while (gp > NIL && !Set_IsItem(&FirstVisited, gp)) { Set_AddItem(&FirstVisited, gp); gn = GetGraphP(gp); CR_ASSERT(gn != NULL); switch(gn->type) { case T_T : case T_WT: Set_AddItem(first, gn->SYMLINK); break; case T_NT : { PNTermNode ntn = GetNTermP(gn->SYMLINK); CR_ASSERT(ntn != NULL); if (ntn->ready) GetNTermFirst(gn->SYMLINK, first); else CompFirst(ntn->graph, first, STRICT); break; } case T_ANY: GetSymSet(gn->SETLINK1, first); break; case T_OPT: case T_REP: case T_ALT: CompFirst(gn->INNER, first, STRICT); if (gn->type == T_ALT) CompFirst(gn->ALT, first, STRICT); break; } if (!IsNullableNode(gp)) break; /* Nullable => Continue */ gp = (STRICT)? gn->next: abs(gn->next); } } /* get First Set of a graph */ void CompFirstSet(int gp, PSet first) { Set_Clean(&FirstVisited); CompFirst(gp, first, TRUE); } /* get First Set of a graph (use follow links) */ static void CompNextFirstSet(int gp, Set *first) { Set_Clean(&FirstVisited); CompFirst(gp, first, FALSE); } static void CompNTermFirstSet(PNTermNode ntn) { ntn->ready = FALSE; CompFirstSet(ntn->graph, &ntn->first); ntn->ready = TRUE; } /* compute all First Sets of a nonterminal */ static void CompAllFirstSets() { Collection_ForEach(&nterm_tab, (Collection_Func) CompNTermFirstSet); } /* compute Follow Set of each nonterminal in graph */ static void CompFollowSet(int gp) { PGraphNode gn; while (gp > NIL && !Set_IsItem(&FollowVisited, gp)) { Set_AddItem(&FollowVisited, gp); gn = GetGraphP(gp); CR_ASSERT(gn != NULL); switch(gn->type) { case T_NT: { PNTermNode ntn = GetNTermP(gn->SYMLINK); CR_ASSERT(ntn != NULL); CompNextFirstSet(abs(gn->next), &(ntn->follow)); if (IsNullableNextGraph(abs(gn->next))) Set_AddItem(&ntn->AuxNt, CurrentNt); break; } case T_OPT: case T_REP: case T_ALT: CompFollowSet(gn->INNER); if (gn->type == T_ALT) CompFollowSet(gn->ALT); break; } gp = gn->next; } } /* complete follow set by indirect nonterminal links */ static void CompleteFollow(int curr_nt) { int i, c; PNTermNode ntn, ntn1; if (Set_IsItem(&FollowVisited, curr_nt)) return; Set_AddItem(&FollowVisited, curr_nt); ntn = GetNTermP(curr_nt); CR_ASSERT(ntn != NULL); Set_GetRange(&ntn->AuxNt, &i, &c); for (; i <= c; i++) if (Set_IsItem(&ntn->AuxNt, i)) { ntn1 = GetNTermP(i); CR_ASSERT(ntn1 != NULL); CompleteFollow(i); Set_Union(&ntn->follow, &ntn1->follow); Set_DelItem(&ntn->AuxNt, i); } } static void Func_CompFollowSet(int gp) { Set_Clean(&FollowVisited); CompFollowSet(gp); } static void Func_CompleteFollowSet(int gp) { Set_Clean(&FollowVisited); CompleteFollow(CurrentNt); } /* compute Follow of all nonterminals */ static void CompAllFollowSets() { ForEachNTermGraph((Graph_Func) Func_CompFollowSet); ForEachNTermGraph((Graph_Func) Func_CompleteFollowSet); } /* return graph node index of a leading ANY in graph */ static int LeadingANY(int gp) { PGraphNode gn; int a; if (gp <= NIL) return NIL; gn = GetGraphP(gp); CR_ASSERT(gn != NULL); switch (gn->type) { case T_ANY: return gp; case T_OPT: case T_REP: return LeadingANY(gn->INNER); case T_ALT: if ((a = LeadingANY(gn->INNER)) != NIL) return a; return a = LeadingANY(gn->ALT); } if (IsNullableNode(gp)) return LeadingANY(gn->next); return NIL; } /* exclude terminals from ANY set */ static void ExcludeANY(int gp, PSet set) { PGraphNode gn; gn = GetGraphP(gp); CR_ASSERT(gn != NULL); if (gn->SETLINK1 == NIL) gn->SETLINK1 = NewANY(); ExcludeSymSet(gn->SETLINK1, set); } /* compute ANY sets in graph */ static void CompANYSet(int gp) { PGraphNode gn; Set set; Set_Init(&set); while (gp > NIL) { gn = GetGraphP(gp); CR_ASSERT(gn != NULL); switch(gn->type) { case T_OPT: case T_REP: { int a; CompANYSet(gn->INNER); if ((a = LeadingANY(gn->INNER)) != NIL) { Set_Clean(&set); CompExpected(abs(gn->next), CurrentNt, &set); ExcludeANY(a, &set); } break; } case T_ALT: { int gp1 = gp; int a; PGraphNode gn1; Set_Clean(&set); while (gp1 != NIL) { gn1 = GetGraphP(gp1); CR_ASSERT(gn1 != NULL); CompANYSet(gn1->INNER); if ((a = LeadingANY(gn1->INNER)) != NIL) { CompExpected(gn1->ALT, CurrentNt, &set); ExcludeANY(a, &set); } else CompExpected(gn1->INNER, CurrentNt, &set); gp1 = gn1->ALT; } break; } /* case */ } /* switch */ gp = gn->next; } Set_Done(&set); } static void Func_CompAnySet(int gp) { Set_Clean(&FollowVisited); CompANYSet(gp); } /* compute all ANY sets */ static void CompAllANYSets() { ForEachNTermGraph((Graph_Func) Func_CompAnySet); } /* compute SYNC sets in a graph */ static void CompSYNCSet(int gp) { PGraphNode gn; Set set; Set_Init(&set); while (gp > NIL) { gn = GetGraphP(gp); CR_ASSERT(gn != NULL); switch(gn->type) { case T_SYNC: Set_Clean(&set); CompExpected(abs(gn->next), CurrentNt, &set); Set_AddItem(&set, EOFSYM); IncludeSymSet(ALL_SYNCS, &set); gn->SETLINK1 = NewSymSet(&set, T_SYNC); break; case T_OPT: case T_REP: case T_ALT: CompSYNCSet(gn->INNER); if (gn->type == T_ALT) CompSYNCSet(gn->ALT); break; } gp = gn->next; } Set_Done(&set); } /* compute all SYNC sets */ static void CompAllSYNCSets() { ForEachNTermGraph((Graph_Func) CompSYNCSet); } /* compute WEAK Terminal sets in a graph */ static void CompWEAKSet(int gp) { PGraphNode gn, gn1; Set set; Set_Init(&set); while (gp > NIL) { gn = GetGraphP(gp); CR_ASSERT(gn != NULL); switch(gn->type) { case T_WT: Set_Clean(&set); CompExpected(abs(gn->next), CurrentNt, &set); /* Follow WEAK TERMINAL */ gn->SETLINK1 = NewSymSet(&set, T_WT); break; case T_REP: gn1 = GetGraphP(gn->INNER); CR_ASSERT(gn1 != NULL); if (gn1->type == T_WT) { Set_Clean(&set); CompExpected(abs(gn->next), CurrentNt, &set); /* Follow LOOP */ gn1->SETLINK2 = NewSymSet(&set, T_WT); } CompWEAKSet(gn->INNER); break; case T_OPT: case T_ALT: CompWEAKSet(gn->INNER); if (gn->type == T_ALT) CompWEAKSet(gn->ALT); break; } gp = gn->next; } Set_Done(&set); } /* compute all WEAK sets */ static void CompAllWEAKSets() { ForEachNTermGraph((Graph_Func) CompWEAKSet); } /* compute set of all terminals except pragmas */ static void CompALLTermsSet() { Set_Clean(&ALL_TERMS); Set_AddRange(&ALL_TERMS, 1, Collection_Count(&term_tab) - 1); } static void Func_NTermDeclared(PNTermNode ntn, int ntp) { if (ntp == 0) return; if (ntn->graph == NIL) { fprintf(lstfile, "\"%s\", Line %d, Col %d :", source_name, ntn->line_use, 0); fprintf(lstfile, "**** %s Not Declared\n", ntn->name); Errors++; } else if (!ntn->reachable) { fprintf(lstfile, "\"%s\", Line %d, Col %d :", source_name, ntn->line_dec, 0); fprintf(lstfile, "**** %s Declared but not used\n", ntn->name); Errors++; } } /* check if a nonterminal was use but not defined, or defined and not used */ static void CheckNTermDeclared() { Collection_ForEachPos(&nterm_tab, (Collection_FuncPos) Func_NTermDeclared); } static void Func_NTermNullable(PNTermNode ntn, int ntp) { if (! ntn->nullable || ntp == 0) return; fprintf(lstfile, "\"%s\", Line %d, Col %d :", source_name, S_Line, 0); fprintf(lstfile, "**** Warning : %s is nullable\n", ntn->name); } /* check if a nonterminal is nullable */ static void CheckNTermNullable() { Collection_ForEachPos(&nterm_tab, (Collection_FuncPos) Func_NTermNullable); } /* check for nonterminal circular derivations */ static int CompCircularGraph(int gp) { PGraphNode gn; int t; while (gp > NIL) { gn = GetGraphP(gp); CR_ASSERT(gn != NULL); switch(gn->type) { case T_T : case T_WT: return FALSE; case T_NT : { PNTermNode ntn = GetNTermP(gn->SYMLINK); CR_ASSERT(ntn != NULL); if (gn->SYMLINK == CurrentNt) return CurrentNt; if (Set_IsItem(&Set1, gn->SYMLINK)) return FALSE; Set_AddItem(&Set1, gn->SYMLINK); if (CompCircularGraph(ntn->graph)) return gn->SYMLINK; break; } case T_OPT: case T_REP: case T_ALT: if ((t = CompCircularGraph(gn->INNER)) != FALSE) return t; if (gn->type == T_ALT) if ((t = CompCircularGraph(gn->ALT)) != FALSE) return t; break; } if (!IsNullableNode(gp)) break; /* Nullable => Continue */ gp = gn->next; } return FALSE; } static void Func_CheckCircular(PNTermNode ntn, int ntp) { int t; Set_Clean(&Set1); CurrentNt = ntp; if ((t = CompCircularGraph(ntn->graph)) != FALSE) { PNTermNode ntn1 = GetNTermP(t); fprintf(lstfile, "**** Circular Derivation %s -> %s\n", ntn->name, ntn1->name); Errors++; } } static void CheckCircular() { Collection_ForEachPos(&nterm_tab, (Collection_FuncPos) Func_CheckCircular); } static int IsTerminalGraph(int gp) { PGraphNode gn; while (gp > NIL) { gn = GetGraphP(gp); CR_ASSERT(gn != NULL); switch(gn->type) { case T_NT: if (!Set_IsItem(&Set1, gn->SYMLINK)) return FALSE; break; case T_ALT: if (!IsTerminalGraph(gn->INNER) && ((gn->ALT == NIL) || !IsTerminalGraph(gn->ALT))) return FALSE; break; } gp = gn->next; } return TRUE; } /* check if a nonterminal can derive to terminals */ static void CheckDeriveTerminals() { PNTermNode ntn; int c, i, change; Set_Clean(&Set1); c = Collection_Count(&nterm_tab); do { change = FALSE; for (i = 1; i < c; i++) /* for each Nonterminal */ if (!Set_IsItem(&Set1, i)) { ntn = GetNTermP(i); CR_ASSERT(ntn != NULL); if (IsTerminalGraph(ntn->graph)) { Set_AddItem(&Set1, i); change = TRUE; } } } while (change); for (i = 1; i < c; i++) /* for each nonterminal */ if (!Set_IsItem(&Set1, i)) { ntn = GetNTermP(i); CR_ASSERT(ntn != NULL); fprintf(lstfile, "**** %s Can't derive to Terminals\n", ntn->name); Errors++; } } /* Generate LL(1) errors */ static void LL1Error(int c, int i) { PNTermNode ntn; PTermNode tn; ntn = GetNTermP(CurrentNt); CR_ASSERT(ntn != NULL); fprintf(lstfile, "\"%s\", Line %d, Col %d :", source_name, S_Line, 0); fprintf(lstfile, "**** LL(1) Error in %s: ", ntn->name); if (i > 0) { tn = GetTermP(i); fprintf(lstfile, "%s is the ", tn->name); } switch (c) { case 1: fprintf(lstfile, "start of several alternatives.\n"); break; case 2: fprintf(lstfile, "start & successor of nullable structures.\n"); break; case 3: fprintf(lstfile, "an ANY node matches no symbol.\n"); break; } } /* check if two sets have items in common */ static void CheckSets(int cond, Set *s1, Set *s2) { int i, c; Set_GetRange(s1, &i, &c); for (; i <= c; i++) if (Set_IsItem(s1, i) && Set_IsItem(s2, i)) LL1Error(cond, i); } /* perform LL(1) checks in graph */ static void Func_CheckLL1Graph(int gp) { PGraphNode gn; while (gp > NIL) { gn = GetGraphP(gp); CR_ASSERT(gn != NULL); switch(gn->type) { case T_ALT: { PGraphNode gn1; int gp1; gp1 = gp; Set_Clean(&Set1); while (gp1 > NIL) { gn1 = GetGraphP(gp1); CR_ASSERT(gn1 != NULL); Set_Clean(&Set2); CompExpected(gn1->INNER, CurrentNt, &Set2); CheckSets(1, &Set1, &Set2); Set_Union(&Set1, &Set2); gp1 = gn1->ALT; } gp1 = gp; while (gp1 > NIL) { gn1 = GetGraphP(gp1); CR_ASSERT(gn1 != NULL); Func_CheckLL1Graph(gn1->INNER); gp1 = gn1->ALT; } break; } case T_OPT: case T_REP: Set_Clean(&Set1); Set_Clean(&Set2); CompExpected(gn->INNER, CurrentNt, &Set1); CompExpected(abs(gn->next), CurrentNt, &Set2); CheckSets(2, &Set1, &Set2); Func_CheckLL1Graph(gn->INNER); break; case T_ANY: Set_Clean(&Set1); GetSymSet(gn->SETLINK1, &Set1); if (Set_Empty(&Set1)) LL1Error(3, 0); break; } gp = gn->next; } } static void CheckLL1() { ForEachNTermGraph((Graph_Func) Func_CheckLL1Graph); } /* compute all symbol sets needed */ void CompSymbolSets() { CheckNTermDeclared(); if (Errors) return; CheckDeriveTerminals(); if (Errors) return; CompALLTermsSet(); SetupPragmas(); CompAllFollowNodes(); CompAllNullable(); CheckNTermNullable(); CheckCircular(); if (Errors) return; CompAllFirstSets(); CompAllFollowSets(); CompAllANYSets(); CompAllFirstSets(); /* Second Time: In very few cases */ CompAllFollowSets(); /* ANY sets can add information to first */ CompAllANYSets(); /* and Follow */ CompAllSYNCSets(); CompAllWEAKSets(); CheckLL1(); } /* get expected next symbols */ void CompExpected(int gp, int nterm, Set *set) { CompNextFirstSet(gp, set); if (IsNullableNextGraph(gp)) GetNTermFollow(nterm, set); } /***************************************************************** *** General purpose Functions *** *****************************************************************/ /* add ignore sets */ void AddIgnore(Set *set) { int cp; PClassNode cn; cp = FindClass("@ignore_chars"); if (cp != UNDEF) { cn = GetClassP(cp); Set_Union(&cn->data, set); } } /* install a symbol */ int NewSym(PName name, int typ) { int sp = 0; switch (typ) { case T_T: case T_WT: sp = NewTerm(name); break; case T_P: sp = NewPragma(name); break; case T_NT: sp = NewNTerm(name); break; } return sp; } /* find symbol */ int FindSym(PName name, int *typ) { int sp; sp = FindClass(name); if (sp > UNDEF) { *typ = T_CLASS; return sp; } sp = FindTerm(name); if (sp > UNDEF) { *typ = T_T; return sp; } sp = FindPragma(name); if (sp > UNDEF) { *typ = T_P; return sp; } sp = FindNTerm(name); if (sp > UNDEF) { *typ = T_NT; return sp; } return UNDEF; } /* print ascii char */ void PrintAscii(int s) { if (s <= 32) fprintf(lstfile, " #%d ", s); else fprintf(lstfile, "%c", s); } /* print integer */ void PrintInt(int s) { fprintf(lstfile, "%d ", s); } /* print terminal */ static void PrintTerm(int tp) { PTermNode tn; tn = GetTermP(tp); fprintf(lstfile, "%s ", tn->name); } /* print nonterminal */ static void PrintNTerm(int ntp) { PNTermNode ntn; ntn = GetNTermP(ntp); CR_ASSERT(ntn != NULL); fprintf(lstfile, "%s ", ntn->name); } /* create & initialize all module variables */ void InitTab() { Collection_Init(&nterm_tab, sizeof(NTermNode), NTERM_SIZE, NTERM_EXTEND); Collection_Init(&term_tab, sizeof(TermNode), TERM_SIZE, TERM_EXTEND); Collection_Init(&nodes_tab, sizeof(GraphNode), NODES_SIZE, NODES_EXTEND); Collection_Init(&class_tab, sizeof(ClassNode), CLASS_SIZE, CLASS_EXTEND); Collection_Init(&symset_tab, sizeof(SymSetNode), SYMSET_SIZE, SYMSET_EXTEND); Collection_Init(&pragma_tab, sizeof(PragmaNode), PRAGMA_SIZE, PRAGMA_EXTEND); Collection_Init(&name_tab, sizeof(NameNode), NAME_SIZE, NAME_EXTEND); Set_Init(&ANY_SET); Set_Init(&ALL_TERMS); Set_Init(&FirstVisited); Set_Init(&FollowVisited); Set_Init(&Set1); Set_Init(&Set2); Set_Clean(&ANY_SET); (void) NewSymSet(&ANY_SET, T_SYNC); /* ALL SYNCS symset 0 */ Set_AddItem(&ANY_SET, ' '); (void) NewClass("@ignore_chars", &ANY_SET); /* IGNORE SET 0 */ (void) NewSym("EOF", T_T); /* EOFSYM term 0 */ (void) NewSym("@NTERM", T_NT); /* No Terminal 0 */ (void) MakeGraphNode(0); /* graph Node 0 */ Set_AddRange(&ANY_SET, 1, 255); /* ANY SET */ } void CleanGraphTab() { Collection_Clean(&nodes_tab); (void) MakeGraphNode(0); /* graph Node 0 */ } /* destroy all module variables */ void DoneTab() { Collection_Done(&nterm_tab); Collection_Done(&term_tab); Collection_Done(&nodes_tab); Collection_Done(&class_tab); Collection_Done(&symset_tab); Collection_Done(&pragma_tab); Collection_Done(&name_tab); Set_Done(&ANY_SET); Set_Done(&ALL_TERMS); Set_Done(&FirstVisited); Set_Done(&FollowVisited); Set_Done(&Set1); Set_Done(&Set2); } char *SetVar(char *s) { char name[200], value[200]; char *n = name, *v = value; /* Get the variable name */ while (*s && *s != '=') *n++ = *s++; *n='\0'; if (*s == '=') s++; /* Get the variable Value */ while (*s) *v++ = *s++; *v = '\0'; /* printf("Variable %s = %s \n", name, value); */ if (stricmp(name, "CRHEXT") == 0) strcpy(h_ext, value); if (stricmp(name, "CRCEXT") == 0) strcpy(c_ext, value); if (stricmp(name, "CRFRAMES") == 0) strcpy(Frames_Path, value); return s; } void SetOptions(char *s) { while (*s) { switch (*s) { case 'A' : case 'a' : L_option = TRUE; A_option = TRUE; S_option = TRUE; break; case 'C' : case 'c' : C_option = TRUE; break; case 'F' : case 'f' : L_option = TRUE; F_option = TRUE; S_option = TRUE; break; case 'G' : case 'g' : L_option = TRUE; G_option = TRUE; S_option = TRUE; break; case 'L' : case 'l' : L_option = TRUE; break; case 'O' : case 'o' : O_option = TRUE; break; case 'P' : case 'p' : P_option = TRUE; break; case 'S' : case 's' : L_option = TRUE; S_option = TRUE; break; case 'T' : case 't' : T_option = TRUE; break; case 'D' : case 'd' : if (s[1] == '\0') D_option = TRUE; else { s++; s=SetVar(s); return; } break; case 'X' : case 'x' : GenCplusplus = TRUE; strcpy(c_ext, "cpp"); strcpy(h_ext, "hpp"); break; case 'Z' : case 'z' : Z_option = TRUE; strcpy(c_ext, "cpp"); strcpy(h_ext, "hpp"); break; } s++; } }