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++; 
	} 
}