/*-------------------------------------------------------------------------
EBNF Visualizer
Copyright (c) 2005 Stefan Schoergenhumer, Markus Dopler
supported by Hanspeter Moessenboeck, University of Linz

This program is free software; you can redistribute it and/or modify it 
under the terms of the GNU General Public License as published by the 
Free Software Foundation; either version 2, or (at your option) any 
later version.

This program is distributed in the hope that it will be useful, but 
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License 
for more details.

You should have received a copy of the GNU General Public License along 
with this program; if not, write to the Free Software Foundation, Inc., 
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.



This class has been generated by the Compiler Generator Coco/R.
See: http://www.ssw.uni-linz.ac.at/Research/Projects/Coco/
-------------------------------------------------------------------------*/

using System;



public class Parser {
	const int _EOF = 0;
	const int _ident = 1;
	const int _terminal = 2;
	const int _wrap = 3;
	const int maxT = 13;

	const bool T = true;
	const bool x = false;
	const int minErrDist = 2;

	public static Token t;    // last recognized token
	public static Token la;   // lookahead token
	static int errDist = minErrDist;



	static void SynErr (int n) {
		if (errDist >= minErrDist) Errors.SynErr(la.line, la.col, n);
		errDist = 0;
	}

	public static void SemErr (string msg) {
		if (errDist >= minErrDist) Errors.Error(t.line, t.col, msg);
		errDist = 0;
	}
	
	static void Get () {
		for (;;) {
			t = la;
			la = Scanner.Scan();
			if (la.kind <= maxT) { ++errDist; break; }

			la = t;
		}
	}
	
	static void Expect (int n) {
		if (la.kind==n) Get(); else { SynErr(n); }
	}
	
	static bool StartOf (int s) {
		return set[s, la.kind];
	}
	
	static void ExpectWeak (int n, int follow) {
		if (la.kind == n) Get();
		else {
			SynErr(n);
			while (!StartOf(follow)) Get();
		}
	}
	
	static bool WeakSeparator (int n, int syFol, int repFol) {
		bool[] s = new bool[maxT+1];
		if (la.kind == n) { Get(); return true; }
		else if (StartOf(repFol)) return false;
		else {
			for (int i=0; i <= maxT; i++) {
				s[i] = set[syFol, i] || set[repFol, i] || set[0, i];
			}
			SynErr(n);
			while (!s[la.kind]) Get();
			return StartOf(syFol);
		}
	}
	
	static void EBNF() {
		Rule();
		while (la.kind == 1) {
			Rule();
		}
	}

	static void Rule() {
		Expect(1);
		Node n;
		Symbol s=Symbol.Find(t.val);	//look if already known
		
						if(s==null) n=new Node(new Symbol(Node.nt,t.val));
						else {
							if(s.typ==Node.nt) {
								String message="ERROR: Nonterminal symbol "+t.val+" has been defined multiple times.";
								EbnfForm.WriteLine(message);
								n=new Node(new Symbol(0,"BUG"));
							} else { //if only considered as terminal symbol until now
								s.typ=Node.nt;
								Symbol.terminalToNt(s.name);
								Symbol.terminalToNt(s.name);
								Node.terminalToNt(s.name);
								n=Node.Find(s.name);	
							}
						}
					 
		Expect(4);
		Expr(out n.sym.graph);
		Expect(5);
		Graph.Finish(n.sym.graph); 
	}

	static void Expr(out Graph g) {
		Graph g1; 
		Alt(out g);
		bool first = true; 	
		while (la.kind == 6) {
			Get();
			Alt(out g1);
			if (first) { Graph.MakeFirstAlt(g); first = false; }
			Graph.MakeAlternative(g, g1); 
			 
		}
	}

	static void Alt(out Graph g) {
		Graph g1; g=new Graph();  
		while (StartOf(1)) {
			Sym(out g1);
			Graph.MakeSequence(g, g1); 	
		}
		if(g.l==null && g.r==null)
		g=new Graph(new Node(Node.eps,null));
		
	}

	static void Sym(out Graph g) {
		Graph g1;g=new Graph();	 
		switch (la.kind) {
		case 1: {
			Get();
			Symbol s=Symbol.Find(t.val);
			Node n;
			if(s!=null)	n= new Node(s);
			else n=new Node(new Symbol(Node.t,t.val)); //type could be nt, but not known yet
			g=new Graph(n);				
			
			break;
		}
		case 2: {
			Get();
			char[] trim=new char[1];
			trim[0]=t.val[0];
			String temp=t.val.Trim(trim);
			
			Node n =new Node(new Symbol(Node.t,temp));
			g=new Graph(n);				
			
			break;
		}
		case 3: {
			Get();
			Node n =new Node(Node.wrap,null);
			g=new Graph(n);
			
			break;
		}
		case 7: {
			Get();
			Expr(out g1);
			Expect(8);
			g=g1;  
			break;
		}
		case 9: {
			Get();
			Expr(out g1);
			Expect(10);
			Graph.MakeOption(g1);
			g=g1;
			
			break;
		}
		case 11: {
			Get();
			Expr(out g1);
			Expect(12);
			Graph.MakeIteration(g1);
			g=g1;
			
			break;
		}
		default: SynErr(14); break;
		}
	}



	public static void Parse() {
		la = new Token();
		la.val = "";		
		Get();
		EBNF();

    Expect(0);
	}

	static bool[,] set = {
		{T,x,x,x, x,x,x,x, x,x,x,x, x,x,x},
		{x,T,T,T, x,x,x,T, x,T,x,T, x,x,x}

	};
} // end Parser


public class Errors {
	public static int count = 0;                                    // number of errors detected
  public static string errMsgFormat = "-- line {0} col {1}: {2}"; // 0=line, 1=column, 2=text
	
	public static void SynErr (int line, int col, int n) {
		string s;
		switch (n) {
			case 0: s = "EOF expected"; break;
			case 1: s = "ident expected"; break;
			case 2: s = "terminal expected"; break;
			case 3: s = "wrap expected"; break;
			case 4: s = "\"=\" expected"; break;
			case 5: s = "\".\" expected"; break;
			case 6: s = "\"|\" expected"; break;
			case 7: s = "\"(\" expected"; break;
			case 8: s = "\")\" expected"; break;
			case 9: s = "\"[\" expected"; break;
			case 10: s = "\"]\" expected"; break;
			case 11: s = "\"{\" expected"; break;
			case 12: s = "\"}\" expected"; break;
			case 13: s = "??? expected"; break;
			case 14: s = "invalid Sym"; break;

			default: s = "error " + n; break;
		}
		Console.WriteLine(Errors.errMsgFormat, line, col, s);
		EbnfForm.WriteLine("ERROR: Line: "+line+" Col: "+ col+": "+ s);
		count++;
	}

	public static void SemErr (int line, int col, int n) {
		Console.WriteLine(errMsgFormat, line, col, ("error " + n));
		count++;
	}

	public static void Error (int line, int col, string s) {
		Console.WriteLine(errMsgFormat, line, col, s);
		count++;
	}

	public static void Exception (string s) {
		Console.WriteLine(s); 
		System.Environment.Exit(1);
	}
} // Errors

