/**********************************************************
**   PARSER_C.FRM
**   Coco/R C Support Frames.
**   Author: Frankie Arzu <farzu@uvg.edu.gt>
**
**   Jun 12, 1996   Version 1.06
**      Many fixes and suggestions thanks to
**      Pat Terry <p.terry@ru.ac.za>
**********************************************************/

#include "crs.h"
#include "crp.h"

#include "crt.h"
#include "crf.h"
#include "cra.h"
#include "crp.h"
#include "crs.h"
#include <string.h>
#include <stdlib.h>

static void FixString(char *name)
{
  int i, j, len, spaces, start;
  len = strlen(name);
  if (len == 2) { SemError(129); return; }
  if (ignore_case) upcase(name);
  spaces = FALSE; start = name[0];
  for (i = 1; i <= len-2; i++) {
    if (name[i] > 0 && name[i] <= ' ') spaces = TRUE;
    if (name[i] == '\\') {
      if (name[i+1] == '\\' || name[i+1] == '\'' || name[i+1] == '\"') {
        for (j = i; j < len; j++) name[j] = name[j+1]; len--;
      }
    }
  }
  if (spaces) SemError(124);
}

static void MatchLiteral (int sp)
/* store string either as token or as literal */
{
  PTermNode sn, sn1;
  int matched_sp;

  sn = GetTermP(sp);
  matched_sp = MatchDFA((unsigned char *) sn->name, sp);
  if (matched_sp != 0) {
    sn1 = GetTermP(matched_sp);
    sn1->type = T_CLASSLITTOKEN;
    sn->type  = T_LITTOKEN;
  } else sn->type= T_CLASSTOKEN;
}

static void SetCtx (int gp)
/* set transition code to contextTrans */
{
  PGraphNode gn;
  while (gp > 0) {
    gn = GetGraphP(gp);
    if (gn->type == T_CHAR || gn->type == T_CLASS)
      gn->CONTEXT = T_CONTEXT;
    else
      if (gn->type == T_OPT || gn->type == T_REP)
      SetCtx(gn->INNER);
      else
      if (gn->type == T_ALT) {
      SetCtx(gn->INNER); SetCtx(gn->ALT);
      }
    gp = gn->next;
  }
}

static void StringClass(char *s, Set *items)
{
  s[strlen(s)-1]=0;  s++;  /* Ignore First and Last character */
  while (*s) Set_AddItem(items, *s++);
}

/**************************************************************************/



Error_Func Custom_Error = 0L;

static int Sym;
static int errors = 0;                /*number of detected errors*/
static int ErrDist = MinErrDist;

#define MAXSYM		3


/* Production prototypes */

static void CR(void);
static void Ident(char *s);
static void Declaration(int *startedDFA);
static void Attribs(int *n);
static void SemText(int *n);
static void Expression(int *n);
static void SetDecl(void);
static void TokenDecl(int sec_type);
static void NameDecl(void);
static void TokenExpr(int *n);
static void CompSet(PSet items);
static void SimSet(PSet items);
static void String(char *s);
static void ChrSet(int *n);
static void Term(int *n);
static void Factor(int *n);
static void Symbol(char *name);
static void TokenTerm(int *n);
static void TokenFactor(int *n);


#define NSETBITS        16

static unsigned short int SymSet[][MAXSYM] = {
  /*EOF_Sym identSym stringSym PRODUCTIONSSym EqualSym ENDSym CHARACTERSSym TOKENSSym NAMESSym PRAGMASSym COMMENTSSym IGNORESym LparenPointSym */
  {0x7EC7,0x4,0x80},
  /*identSym stringSym PointSym ANYSym LparenSym BarSym WEAKSym LbrackSym LbraceSym SYNCSym LparenPointSym */
  {0x106,0xBA80,0x82},
  /*identSym ENDSym */
  {0x202,0x0,0x0},
  /*PointSym RparenSym RbrackSym RbraceSym */
  {0x100,0x4400,0x1},
  /*identSym stringSym PointSym ANYSym LparenSym RparenSym BarSym WEAKSym LbrackSym RbrackSym LbraceSym RbraceSym SYNCSym LparenPointSym */
  {0x106,0xFE80,0x83},
  /*PRODUCTIONSSym PointSym CHARACTERSSym TOKENSSym NAMESSym PRAGMASSym COMMENTSSym TOSym NESTEDSym IGNORESym RparenSym RbrackSym RbraceSym */
  {0x7D40,0x4407,0x1},
  /*identSym stringSym LparenSym LbrackSym LbraceSym */
  {0x6,0xA200,0x0},
  {0x0}
};

void GenError(int errno)
{ if (ErrDist >= MinErrDist) {
    if (Custom_Error != 0L)
      (*Custom_Error) (errno, S_NextLine, S_NextCol, S_NextPos);
    errors++;
  }
  ErrDist = 0;
}

void SynError(int errno)
{ if (errno <= MAXERROR) errno = MAXERROR;
  if (ErrDist >= MinErrDist) {
    if (Custom_Error != 0L)
      (*Custom_Error) (errno, S_NextLine, S_NextCol, S_NextPos);
    errors++;
  }
  ErrDist = 0;
}

void SemError(int errno)
{ if (errno <= MAXERROR) errno = MAXERROR;
  if (ErrDist >= MinErrDist) {
    if (Custom_Error != 0L)
      (*Custom_Error) (errno, S_Line, S_Col, S_Pos);
    errors++;
  }
  ErrDist = 0;
}

static void Get(void)
{ do {
    Sym = S_Get();
    if (Sym <= MAXT) ErrDist ++;
    else {
      if (Sym == OptionsSym) { /*42*/
      	char s[100];
      	  LookAheadString(s, sizeof(s)-1);
      	  SetOptions(s);
      } else
      /* Empty Stmt */ ;
      S_NextPos  = S_Pos;  S_NextCol = S_Col;
      S_NextLine = S_Line; S_NextLen = S_Len;
    }
  } while (Sym > MAXT);
}

static int In (unsigned short int *SymbolSet, int i)
{ return SymbolSet[i / NSETBITS] & (1 << (i % NSETBITS)); }

static void Expect (int n)
{ if (Sym == n) Get(); else GenError(n); }

static void ExpectWeak (int n, int follow)
{ if (Sym == n) Get();
  else {
    GenError(n);
    while (!(In(SymSet[follow], Sym) || In(SymSet[0], Sym))) Get();
  }
}

static int WeakSeparator (int n, int syFol, int repFol)
{ unsigned short int s[MAXSYM];
  int i;

  if (Sym == n) { Get(); return 1; }
  if (In(SymSet[repFol], Sym)) return 0;
  for (i = 0; i < MAXSYM; i++)
    s[i] = SymSet[0][i] | SymSet[syFol][i] | SymSet[repFol][i];
  GenError(n);
  while (!In(s, Sym)) Get();
  return In(SymSet[syFol], Sym);
}

int Successful(void)
{ return errors == 0; }

/* Productions */

static void CR(void)
{
	Name name1;
	int  attr, sem, exp, is_new, sp, type;
	int startedDFA = FALSE;
	PNTermNode sn;
	Expect(COMPILERSym);
	Ident(compiler_name);
	global_defs.pos  = S_NextPos;
	global_defs.line = S_NextLine;
	while (Sym >= identSym && Sym <= COMPILERSym ||
	       Sym >= EqualSym && Sym <= ENDSym ||
	       Sym >= FROMSym && Sym <= NESTEDSym ||
	       Sym >= CASESym && Sym <= No_Sym) {
		Get();
	}
	global_defs.len  =
	  (int) (S_NextPos-global_defs.pos);
	while (Sym >= CHARACTERSSym && Sym <= COMMENTSSym ||
	       Sym == IGNORESym) {
		Declaration(&startedDFA);
	}
	while (!(Sym == EOF_Sym ||
	         Sym == PRODUCTIONSSym)) { GenError(43); Get(); }
	if (Successful()) { /* No Errors so far */
	  if (!MakeDeterministic()) SemError(127);
	};
	Expect(PRODUCTIONSSym);
	while (Sym == identSym) {
		attr = NIL; sem = NIL;
		Ident(name1);
		if ((sp = FindSym(name1, &type)) != UNDEF) {
		  is_new = FALSE;
		  if (type != T_NT) { SemError(108); return; }
		  else {
		    sn = GetNTermP(sp);
		    if (sn->graph) SemError(107);
		    sn->line_dec = S_Line;
		  }
		} else {
		  sp = NewSym(name1, T_NT);
		  sn = GetNTermP(sp); is_new = TRUE;
		  sn->line_dec = S_Line;
		};
		if (Sym == LessSym ||
		    Sym == LessPointSym) {
			Attribs(&attr);
		}
		if (!is_new) {
		  if (sn->has_attr && !attr) SemError(105);
		  if (!sn->has_attr && attr) SemError(105);
		}
		if (attr) {
		  sn->attr = attr; sn->has_attr = TRUE;
		};
		ExpectWeak(EqualSym,1);
		if (Sym == LparenPointSym) {
			SemText(&sem);
		}
		Expression(&exp);
		if (sem) {
		  (void) LinkGraph(sem, exp); exp = sem;
		};
		ExpectWeak(PointSym,2);
		sn = GetNTermP(sp); /* reload */
		sn->graph = exp;
		while (!(Sym >= EOF_Sym && Sym <= identSym ||
		         Sym == ENDSym)) { GenError(44); Get(); }
	}
	Expect(ENDSym);
	Ident(name1);
	if (strcmp(name1, compiler_name)) SemError(117);
	if((sp = FindSym(compiler_name, &type)) != UNDEF) {
	  if (type!=T_NT) SemError(108);
	  else {
	    sn = GetNTermP(sp);
	    if (sn->has_attr) SemError(112);
	    sn->reachable=TRUE;
	  }
	} else SemError(111);
	no_sym = NewSym("not", T_T);
	Expect(PointSym);
	if (dirty_DFA && !MakeDeterministic()) SemError(127);
}

static void Ident(char *s)
{
	Expect(identSym);
	LexString(s, MAX_ID_LEN-1);
}

static void Declaration(int *startedDFA)
{
	Set ignore;
	int n1, n2, nested = FALSE;
	switch (Sym) {
		case CHARACTERSSym:  
			Get();
			while (Sym == identSym) {
				SetDecl();
			}
			break;
		case TOKENSSym:  
			Get();
			while (Sym >= identSym && Sym <= stringSym) {
				TokenDecl(T_T);
			}
			break;
		case NAMESSym:  
			Get();
			while (Sym == identSym) {
				NameDecl();
			}
			break;
		case PRAGMASSym:  
			Get();
			while (Sym >= identSym && Sym <= stringSym) {
				TokenDecl(T_P);
			}
			break;
		case COMMENTSSym:  
			Get();
			Expect(FROMSym);
			TokenExpr(&n1);
			Expect(TOSym);
			TokenExpr(&n2);
			if (Sym == NESTEDSym) {
				Get();
				nested = TRUE;
			}
			if (n1 * n2) NewComment(n1, n2, nested);
			break;
		case IGNORESym:  
			Get();
			if (Sym == CASESym) {
				Get();
				if (*startedDFA) SemError(130);
				ignore_case = TRUE;
			} else if (Sym >= identSym && Sym <= stringSym ||
			           Sym >= ANYSym && Sym <= CHRSym) {
				Set_Init(&ignore);
				CompSet(&ignore);
				AddIgnore(&ignore);
				if (Set_IsItem(&ignore,0)) SemError(119);
				Set_Done(&ignore);
			} else GenError(45);
			break;
		default :GenError(46); break;
	}
	*startedDFA = TRUE;
}

static void Attribs(int *n)
{
	long P;
	int Len, Line, Col;
	if (Sym == LessSym) {
		Get();
		P = S_Pos+1; Line = S_Line; Col = S_Col;
		while (Sym >= identSym && Sym <= LessSym ||
		       Sym >= LessPointSym && Sym <= No_Sym) {
			if (Sym >= identSym && Sym <= stringSym ||
			    Sym >= numberSym && Sym <= LessSym ||
			    Sym >= LessPointSym && Sym <= No_Sym) {
				Get();
			} else if (Sym == badstringSym) {
				Get();
				SemError(102);
			} else GenError(47);
		}
		Expect(GreaterSym);
		Len = (int) (S_Pos - P);
		*n = MakeSemGraph(T_ATTR, P, Len, Line, Col);
	} else if (Sym == LessPointSym) {
		Get();
		P = S_Pos+2; Line = S_Line; Col = S_Col;
		while (Sym >= identSym && Sym <= LessPointSym ||
		       Sym >= LparenPointSym && Sym <= No_Sym) {
			if (Sym >= identSym && Sym <= stringSym ||
			    Sym >= numberSym && Sym <= LessPointSym ||
			    Sym >= LparenPointSym && Sym <= No_Sym) {
				Get();
			} else if (Sym == badstringSym) {
				Get();
				SemError(102);
			} else GenError(48);
		}
		Expect(PointGreaterSym);
		Len = (int) (S_Pos - P);
		*n = MakeSemGraph(T_ATTR, P, Len, Line, Col);
	} else GenError(49);
}

static void SemText(int *n)
{
	long P;
	int Len, Line, Col;
	Expect(LparenPointSym);
	P = S_Pos+2; Line = S_Line; Col = S_Col;
	while (Sym >= identSym && Sym <= LparenPointSym ||
	       Sym == No_Sym) {
		if (Sym >= identSym && Sym <= stringSym ||
		    Sym >= numberSym && Sym <= PointGreaterSym ||
		    Sym == No_Sym) {
			Get();
		} else if (Sym == badstringSym) {
			Get();
			SemError(102);
		} else if (Sym == LparenPointSym) {
			Get();
			SemError(109);
		} else GenError(50);
	}
	Expect(PointRparenSym);
	Len = (int) (S_Pos - P);
	*n = MakeSemGraph(T_SEM, P, Len, Line, Col);
}

static void Expression(int *n)
{
	int n0 = NIL, n1, n2, SX_Line;
	Term(&n1);
	while (WeakSeparator(BarSym,4,3)) {
		if (n0 == NIL)
		  n0 = n1 = MakeGraph(T_ALT, n1);
		SX_Line = S_Line;
		Term(&n2);
		n2 = MakeGraph(T_ALT, n2);
		SetGraphLine(n2,SX_Line);
		n1 = LinkAltGraph(n1, n2);
	}
	*n = (n0 ? n0 : n1);
}

static void SetDecl(void)
{
	Name name;
	Set  items;
	Set_Init(&items);
	Ident(name);
	if (FindClass(name) != UNDEF) SemError(107);
	Expect(EqualSym);
	CompSet(&items);
	Expect(PointSym);
	if (Set_Empty(&items)) SemError(101);
	(void) NewClass(name, &items);
	Set_Done(&items);
}

static void TokenDecl(int sec_type)
{
	char name[MAX_STR_LEN];
	int p = 0, sp, type;
	if (Sym == identSym) {
		Ident(name);
		if ((sp = FindSym(name, &type)) != UNDEF) SemError(107);
		else sp = NewSym(name, sec_type);
		while (!(Sym >= EOF_Sym && Sym <= stringSym ||
		         Sym >= PRODUCTIONSSym && Sym <= EqualSym ||
		         Sym >= CHARACTERSSym && Sym <= COMMENTSSym ||
		         Sym == IGNORESym ||
		         Sym == LparenPointSym)) { GenError(51); Get(); }
		if (Sym == EqualSym) {
			Get();
			TokenExpr(&p);
			if (sec_type == T_T) ConvertToStates(p, sp);
			else  ConvertToStates(p, sp+FIRST_PRAGMA);
			Expect(PointSym);
		} else if (Sym >= identSym && Sym <= stringSym ||
		           Sym == PRODUCTIONSSym ||
		           Sym >= CHARACTERSSym && Sym <= COMMENTSSym ||
		           Sym == IGNORESym ||
		           Sym == LparenPointSym) {
			P_option = TRUE;
		} else GenError(52);
	} else if (Sym == stringSym) {
		String(name);
		P_option = TRUE;
		if ((sp = FindSym(name, &type)) != UNDEF) SemError(107);
		else sp = NewSym(name, sec_type);
	} else GenError(53);
	if (Sym == LparenPointSym) {
		SemText(&p);
		if (sec_type == T_T) SemError(114);
		else SetPragmaText(sp, p);
	}
}

static void NameDecl(void)
{
	Name username, name;
	Ident(username);
	Expect(EqualSym);
	if (Sym == identSym) {
		Ident(name);
	} else if (Sym == stringSym) {
		String(name);
	} else GenError(54);
	Expect(PointSym);
	NewName(name, username);
}

static void TokenExpr(int *n)
{
	int n0 = NIL, n1, n2;
	TokenTerm(&n1);
	while (WeakSeparator(BarSym,6,5)) {
		if (n0 == NIL)
		n0 = n1 = MakeGraph(T_ALT, n1);
		TokenTerm(&n2);
		n2 = MakeGraph(T_ALT, n2);
		n1 = LinkAltGraph(n1, n2);
	}
	*n = (n0 ? n0 : n1);
}

static void CompSet(PSet items)
{
	Set set1, set2;
	Set_Init(&set1); Set_Init(&set2);
	SimSet(&set1);
	while (Sym >= PlusSym && Sym <= MinusSym) {
		if (Sym == PlusSym) {
			Get();
			SimSet(&set2);
			Set_Union(&set1, &set2);
		} else if (Sym == MinusSym) {
			Get();
			SimSet(&set2);
			Set_Diference(&set1, &set2);
		} else GenError(55);
		Set_Clean(&set2);
	}
	Set_Union(items, &set1);
	Set_Done(&set1); Set_Done(&set2);
}

static void SimSet(PSet items)
{
	Name name;
	char str[MAX_STR_LEN];
	int n1, n2;
	switch (Sym) {
		case identSym:  
			Ident(name);
			if (FindClass(name) == UNDEF) SemError(115);
			GetClassWithName(name, items);
			break;
		case stringSym:  
			String(str);
			StringClass(str, items);
			break;
		case CHRSym:  
			ChrSet(&n1);
			if (Sym == Range) {
				Get();
				ChrSet(&n2);
				Set_AddRange(items, n1, n2);
			} else if (Sym == PRODUCTIONSSym ||
			           Sym == PointSym ||
			           Sym >= CHARACTERSSym && Sym <= COMMENTSSym ||
			           Sym == IGNORESym ||
			           Sym >= PlusSym && Sym <= MinusSym) {
				Set_AddItem(items, n1);
			} else GenError(56);
			break;
		case ANYSym:  
			Get();
			Set_Union(items, &ANY_SET);
			break;
		default :GenError(57); break;
	}
}

static void String(char *s)
{
	Expect(stringSym);
	LexString(s, MAX_STR_LEN-1);
	FixString(s);
}

static void ChrSet(int *n)
{
	char str[5]; int x;
	Expect(CHRSym);
	Expect(LparenSym);
	if (Sym == numberSym) {
		Get();
		LexString(str, sizeof(str)-1);
		x = atoi(str);
		if (x > 255) { SemError(118); x = 0; }
		*n = x;
	} else if (Sym == stringSym) {
		Get();
		LexString(str, sizeof(str)-1);
		if (strlen(str) != 3) SemError(118);
		*n = str[1];
	} else GenError(58);
	Expect(RparenSym);
}

static void Term(int *n)
{
	int n0 = NIL, n1, n2;
	if (Sym >= identSym && Sym <= stringSym ||
	    Sym == ANYSym ||
	    Sym == LparenSym ||
	    Sym >= WEAKSym && Sym <= LbrackSym ||
	    Sym == LbraceSym ||
	    Sym == SYNCSym ||
	    Sym == LparenPointSym) {
		Factor(&n1);
		n0 = n1;
		while (Sym >= identSym && Sym <= stringSym ||
		       Sym == ANYSym ||
		       Sym == LparenSym ||
		       Sym >= WEAKSym && Sym <= LbrackSym ||
		       Sym == LbraceSym ||
		       Sym == SYNCSym ||
		       Sym == LparenPointSym) {
			Factor(&n2);
			n1 = LinkGraph(n1, n2);
		}
	} else if (Sym == PointSym ||
	           Sym >= RparenSym && Sym <= BarSym ||
	           Sym == RbrackSym ||
	           Sym == RbraceSym) {
		n0 = MakeSemGraph(T_SEM, -1, 0, S_Line, S_Col);
	}
	*n = n0;
}

static void Factor(int *n)
{
	char name1[MAX_STR_LEN];
	int weak = 0, SX_Line;
	int n1, n2 = NIL;
	int sp, is_new, type;
	PNTermNode snt;
	switch (Sym) {
		case identSym: 
		case stringSym: 
		case WEAKSym:  
			if (Sym == WEAKSym) {
				Get();
				weak = 1;
			}
			Symbol(name1);
			sp = FindSym(name1, &type);
			if (type == T_CLASS) SemError(104);
			if (weak && type == T_T) type = T_WT;
			if (weak && type == T_NT) SemError(123);
			n1 = MakeGraph(type, sp);
			if (type == T_NT) {
			  snt = GetNTermP(sp);
			  is_new = snt->graph == 0;
			  snt->line_use = S_Line;
			  snt->reachable = TRUE;
			};
			if (Sym == LessSym ||
			    Sym == LessPointSym) {
				Attribs(&n2);
				(void) LinkAltGraph(n1, n2);
				if (type != T_NT) SemError(103);
				else {
				  if(!is_new && !snt->has_attr) SemError(105);
				  if (is_new) snt->has_attr = TRUE;
				};
			} else if (Sym >= identSym && Sym <= stringSym ||
			           Sym == PointSym ||
			           Sym == ANYSym ||
			           Sym >= LparenSym && Sym <= SYNCSym ||
			           Sym == LparenPointSym) {
				if (type == T_NT)
				if (!is_new && snt->has_attr) SemError(105);
			} else GenError(59);
			break;
		case LparenSym:  
			Get();
			Expression(&n1);
			Expect(RparenSym);
			break;
		case LbrackSym:  
			Get();
			SX_Line = S_Line;
			Expression(&n1);
			Expect(RbrackSym);
			n1 = MakeGraph(T_OPT, n1);
			SetGraphLine(n1,SX_Line);
			break;
		case LbraceSym:  
			Get();
			SX_Line = S_Line;
			Expression(&n1);
			Expect(RbraceSym);
			n1 = MakeGraph(T_REP, n1);
			SetGraphLine(n1,SX_Line);
			break;
		case LparenPointSym:  
			SemText(&n1);
			break;
		case ANYSym:  
			Get();
			n1 = MakeGraph(T_ANY, 0);
			break;
		case SYNCSym:  
			Get();
			n1 = MakeGraph(T_SYNC, 0);
			break;
		default :GenError(60); break;
	}
	*n = n1;
}

static void Symbol(char *name)
{
	int sp, type;
	if (Sym == identSym) {
		Ident(name);
		sp = FindSym(name, &type);
		if (sp == UNDEF) sp = NewSym(name, T_NT);
	} else if (Sym == stringSym) {
		String(name);
		sp = FindSym(name, &type);
		if (sp == UNDEF) {
		  sp = NewSym(name, T_T);
		  MatchLiteral(sp);
		};
	} else GenError(61);
}

static void TokenTerm(int *n)
{
	int n0 = NIL, n1, n2;
	TokenFactor(&n1);
	n0 = n1;
	while (Sym >= identSym && Sym <= stringSym ||
	       Sym == LparenSym ||
	       Sym == LbrackSym ||
	       Sym == LbraceSym) {
		TokenFactor(&n2);
		n1 = LinkGraph(n1, n2);
	}
	if (Sym == CONTEXTSym) {
		Get();
		Expect(LparenSym);
		TokenExpr(&n2);
		Expect(RparenSym);
		SetCtx(n2); n1 = LinkGraph(n1, n2);
	}
	*n = n0;
}

static void TokenFactor(int *n)
{
	char name[MAX_STR_LEN];
	int p = 0;
	switch (Sym) {
		case identSym:  
			Ident(name);
			if ((p = FindClass(name)) == UNDEF) {
			  /* Just Create a valid node */
			  p = MakeGraph(T_CHAR, 0);
			  SemError(115);
			} else p = MakeGraph(T_CLASS, p);
			break;
		case stringSym:  
			String(name);
			p = StrToGraph((unsigned char *) name);
			break;
		case LparenSym:  
			Get();
			TokenExpr(&p);
			Expect(RparenSym);
			break;
		case LbrackSym:  
			Get();
			TokenExpr(&p);
			Expect(RbrackSym);
			p = MakeGraphOp(T_OPT, p);
			break;
		case LbraceSym:  
			Get();
			TokenExpr(&p);
			Expect(RbraceSym);
			p = MakeGraphOp(T_REP, p);
			break;
		default :GenError(62); break;
	}
	*n = p;
}



void Parse(void)
{ S_Reset(); Get();
  CR();
}




syntax highlighted by Code2HTML, v. 0.9.1