/* ------------------------------------------------------------------------
 * Tab.cs
 * Symbol table management of Coco/R
 * by H.Moessenboeck, Univ. of Linz
 * ------------------------------------------------------------------------*/
using System;
using System.IO;
using System.Collections;
namespace at.jku.ssw.Coco {
public class Position {  // position of source code stretch (e.g. semantic action, resolver expressions)
	public int beg;      // start relative to the beginning of the file
	public int len;      // length of stretch
	public int col;      // column number of start position
	
	public Position(int beg, int len, int col) {
		this.beg = beg; this.len = len; this.col = col;
	}
}
//---------------------------------------------------------------------
// Symbols
//---------------------------------------------------------------------
	
public class Symbol : IComparable {
	public static ArrayList terminals = new ArrayList();
	public static ArrayList pragmas = new ArrayList();
	public static ArrayList nonterminals = new ArrayList();
	public static Hashtable tokenNames = null;  /* AW 2003-03-25 */
	
	public const int classToken    = 0;		// token kinds
	public const int litToken      = 1;
	public const int classLitToken = 2;
	
	public int      n;           // symbol number
	public int      typ;         // t, nt, pr, unknown, rslv /* ML 29_11_2002 slv added */ /* AW slv --> rslv */
	public string   name;        // symbol name
	public Node     graph;       // nt: to first node of syntax graph
	public int      tokenKind;   // t:  token kind (literal, class, ...)
	public bool     deletable;   // nt: true if nonterminal is deletable
	public bool     firstReady;  // nt: true if terminal start symbols have already been computed
	public BitArray first;       // nt: terminal start symbols
	public BitArray follow;      // nt: terminal followers
	public BitArray nts;         // nt: nonterminals whose followers have to be added to this sym
	public int      line;        // source text line number of item in this node
	public Position attrPos;     // nt: position of attributes in source text (or null)
	public Position semPos;      // pr: pos of semantic action in source text (or null)
	                             // nt: pos of local declarations in source text (or null)
	public override string ToString()
	{
		return String.Format("[Symbol:Name={0}, n={1}]", name, n);
	}
	public Symbol(int typ, string name, int line) {
		if (name.Length == 2 && name[0] == '"') {
			Parser.SemErr("empty token not allowed"); name = "???";
		}
		if (name.IndexOf(' ') >= 0) Parser.SemErr("tokens must not contain blanks");
		this.typ = typ; this.name = name; this.line = line;
		switch (typ) {
			case Node.t:  n = terminals.Count; terminals.Add(this); break;
			case Node.pr: pragmas.Add(this); break;
			case Node.nt: n = nonterminals.Count; nonterminals.Add(this); break;
		}
	}
	
	public static Symbol Find(string name) {
		foreach (Symbol s in terminals)
			if (s.name == name) return s;
		foreach (Symbol s in nonterminals)
			if (s.name == name) return s;
		return null;
	}
	
	public int CompareTo(object x) {
		return name.CompareTo(((Symbol)x).name);
	}
	
}
//---------------------------------------------------------------------
// Syntax graph (class Node, class Graph)
//---------------------------------------------------------------------
public class Node {
	public static ArrayList nodes = new ArrayList();
	public static string[] nTyp =
		{"    ", "t   ", "pr  ", "nt  ", "clas", "chr ", "wt  ", "any ", "eps ",  /* AW 03-01-14 nTyp[0]: " " --> "    " */
		 "sync", "sem ", "alt ", "iter", "opt ", "rslv"};
	
	// constants for node kinds
	public const int t    =  1;  // terminal symbol
	public const int pr   =  2;  // pragma
	public const int nt   =  3;  // nonterminal symbol
	public const int clas =  4;  // character class
	public const int chr  =  5;  // character
	public const int wt   =  6;  // weak terminal symbol
	public const int any  =  7;  // 
	public const int eps  =  8;  // empty
	public const int sync =  9;  // synchronization symbol
	public const int sem  = 10;  // semantic action: (. .)
	public const int alt  = 11;  // alternative: |
	public const int iter = 12;  // iteration: { }
	public const int opt  = 13;  // option: [ ]
	public const int rslv = 14;  // resolver expr  /* ML */ /* AW 03-01-13 renamed slv --> rslv */
	
	public const int normalTrans  = 0;		// transition codes
	public const int contextTrans = 1;
	
	public int      n;			// node number
	public int      typ;		// t, nt, wt, chr, clas, any, eps, sem, sync, alt, iter, opt, rslv
	public Node     next;		// to successor node
	public Node     down;		// alt: to next alternative
	public Node     sub;		// alt, iter, opt: to first node of substructure
	public bool     up;			// true: "next" leads to successor in enclosing structure
	public Symbol   sym;		// nt, t, wt: symbol represented by this node
	public int      val;		// chr:  ordinal character value
													// clas: index of character class
	public int      code;		// chr, clas: transition code
	public BitArray set;		// any, sync: the set represented by this node
	public Position pos;		// nt, t, wt: pos of actual attributes
													// sem:       pos of semantic action in source text
	public int      line;		// source text line number of item in this node
	public State    state;	// DFA state corresponding to this node
													// (only used in DFA.ConvertToStates)
	public Node(int typ, Symbol sym, int line) {
		this.typ = typ; this.sym = sym; this.line = line;
		n = nodes.Count;
		nodes.Add(this);
	}
	
	public Node(int typ, Node sub): this(typ, null, 0) {
		this.sub = sub;
	}
	
	public Node(int typ, int val, int line): this(typ, null, line) {
		this.val = val;
	}
	
	public static bool DelGraph(Node p) {
		return p == null || DelNode(p) && DelGraph(p.next);
	}
	
	public static bool DelAlt(Node p) {
		return p == null || DelNode(p) && (p.up || DelAlt(p.next));
	}
	
	public static bool DelNode(Node p) {
		if (p.typ == nt) return p.sym.deletable;
		else if (p.typ == alt) return DelAlt(p.sub) || p.down != null && DelAlt(p.down);
		else return p.typ == eps || p.typ == iter || p.typ == opt || p.typ == sem || p.typ == sync;
	}
	
	//----------------- for printing ----------------------
	
	static int Ptr(Node p, bool up) {
		if (p == null) return 0; 
		else if (up) return -p.n;
		else return p.n;
	}
	
	static string Pos(Position pos) {
		if (pos == null) return "     "; else return String.Format("{0,5}", pos.beg);
	}
	
	public static string Name(string name) {
		return (name + "           ").Substring(0, 12);
		/* isn't this better (less string allocations, easier to understand): *
		 * return (name.Length > 12) ? name.Substring(0,12) : name;           */
	}
	
	public static void PrintNodes() {
		Trace.WriteLine("Graph nodes:");
		Trace.WriteLine("----------------------------------------------------");
		Trace.WriteLine("   n type name          next  down   sub   pos  line");
		Trace.WriteLine("                               val  code");
		Trace.WriteLine("----------------------------------------------------");
		foreach (Node p in nodes) {
			Trace.Write("{0,4} {1} ", p.n, nTyp[p.typ]);
			if (p.sym != null)
				Trace.Write("{0,12} ", Name(p.sym.name));
			else if (p.typ == Node.clas) {
				CharClass c = (CharClass)CharClass.classes[p.val];
				Trace.Write("{0,12} ", Name(c.name));
			} else Trace.Write("             ");
			Trace.Write("{0,5} ", Ptr(p.next, p.up));
			switch (p.typ) {
				case t: case nt: case wt:
					Trace.Write("             {0,5}", Pos(p.pos)); break;
				case chr:
					Trace.Write("{0,5} {1,5}       ", p.val, p.code); break;
				case clas:
					Trace.Write("      {0,5}       ", p.code); break;
				case alt: case iter: case opt:
					Trace.Write("{0,5} {1,5}       ", Ptr(p.down, false), Ptr(p.sub, false)); break;
				case sem:
					Trace.Write("             {0,5}", Pos(p.pos)); break;
				case eps: case any: case sync:
					Trace.Write("                  "); break;
			}
			Trace.WriteLine("{0,5}", p.line);
		}
		Trace.WriteLine();
	}
	
}
public class Graph {
	static Node dummyNode = new Node(Node.eps, null, 0);
	
	public Node l;	// left end of graph = head
	public Node r;	// right end of graph = list of nodes to be linked to successor graph
	
	public Graph() {
		l = null; r = null;
	}
	
	public Graph(Node left, Node right) {
		l = left; r = right;
	}
	
	public Graph(Node p) {
		l = p; r = p;
	}
	public static void MakeFirstAlt(Graph g) {
		g.l = new Node(Node.alt, g.l); g.l.line = g.l.sub.line; /* AW 2002-03-07 make line available for error handling */
		g.l.next = g.r;
		g.r = g.l;
	}
	
	public static void MakeAlternative(Graph g1, Graph g2) {
		g2.l = new Node(Node.alt, g2.l); g2.l.line = g2.l.sub.line;
		Node p = g1.l; while (p.down != null) p = p.down;
		p.down = g2.l;
		p = g1.r; while (p.next != null) p = p.next;
		p.next = g2.r;
	}
	
	public static void MakeSequence(Graph g1, Graph g2) {
		Node p = g1.r.next; g1.r.next = g2.l; // link head node
		while (p != null) {  // link substructure
			Node q = p.next; p.next = g2.l; p.up = true;
			p = q;
		}
		g1.r = g2.r;
	}
	
	public static void MakeIteration(Graph g) {
		g.l = new Node(Node.iter, g.l);
		Node p = g.r;
		g.r = g.l;
		while (p != null) {
			Node q = p.next; p.next = g.l; p.up = true;
			p = q;
		}
	}
	
	public static void MakeOption(Graph g) {
		g.l = new Node(Node.opt, g.l);
		g.l.next = g.r;
		g.r = g.l;
	}
	
	public static void Finish(Graph g) {
		Node p = g.r;
		while (p != null) {
			Node q = p.next; p.next = null; p = q;
		}
	}
	
  public static void SetContextTrans(Node p) { // set transition code in the graph rooted at p
    DFA.hasCtxMoves = true;
    while (p != null) {
      if (p.typ == Node.chr || p.typ == Node.clas) {
        p.code = Node.contextTrans;
      } else if (p.typ == Node.opt || p.typ == Node.iter) {
        SetContextTrans(p.sub);
      } else if (p.typ == Node.alt) {
        SetContextTrans(p.sub); SetContextTrans(p.down);
      }
      if (p.up) break;
      p = p.next;
    }
  }
	
	public static void DeleteNodes() {
		Node.nodes = new ArrayList();
		dummyNode = new Node(Node.eps, null, 0);
	}
	
	public static Graph StrToGraph(string str) {
		string s = DFA.Unescape(str.Substring(1, str.Length-2));
		if (s.IndexOf('\0') >= 0) Parser.SemErr("\\0 not allowed here. Used as eof character");
		if (s.Length == 0) Parser.SemErr("empty token not allowed");
		Graph g = new Graph();
		g.r = dummyNode;
		for (int i = 0; i < s.Length; i++) {
			Node p = new Node(Node.chr, (int)s[i], 0);
			g.r.next = p; g.r = p;
		}
		g.l = dummyNode.next; dummyNode.next = null;
		return g;
	}
	
}
//----------------------------------------------------------------
// Bit sets 
//----------------------------------------------------------------
public class Sets {
	
	public static int First(BitArray s) {
		int max = s.Count;
		for (int i=0; i<max; i++)
			if (s[i]) return i;
		return -1;
	}
	
	public static int Elements(BitArray s) {
		int max = s.Count;
		int n = 0;
		for (int i=0; i<max; i++)
			if (s[i]) n++;
		return n;
	}
	
	public static bool Equals(BitArray a, BitArray b) {
		int max = a.Count;
		for (int i=0; i<max; i++)
			if (a[i] != b[i]) return false;
		return true;
	}
	
	public static bool Includes(BitArray a, BitArray b) {	// a > b ?
		int max = a.Count;
		for (int i=0; i<max; i++)
			if (b[i] && ! a[i]) return false;
		return true;
	}
	
	public static bool Intersect(BitArray a, BitArray b) { // a * b != {}
		int max = a.Count;
		for (int i=0; i<max; i++)
			if (a[i] && b[i]) return true;
		return false;
	}
	
	public static void Subtract(BitArray a, BitArray b) { // a = a - b
		BitArray c = (BitArray) b.Clone();
		a.And(c.Not());
	}
	
	public static void PrintSet(BitArray s, int indent) {
		int col, len;
		col = indent;
		foreach (Symbol sym in Symbol.terminals) {
			if (s[sym.n]) {
				len = sym.name.Length;
				if (col + len >= 80) {
					Trace.WriteLine();
					for (col = 1; col < indent; col++) Trace.Write(" ");
				}
				Trace.Write("{0} ", sym.name);
				col += len + 1;
			}
		}
		if (col == indent) Trace.Write("-- empty set --");
		Trace.WriteLine();
	}
	
}
//---------------------------------------------------------------------
// Character class management
//---------------------------------------------------------------------
public class CharClass {
	public static ArrayList classes = new ArrayList();
	public static int dummyName = 'A';
	
	public const int charSetSize = 256;  // must be a multiple of 16
	
	public int n;       	// class number
	public string name;		// class name
	public BitArray set;	// set representing the class
	public CharClass(string name, BitArray s) {
		if (name == "#") name = "#" + (char)dummyName++;
		this.n = classes.Count; this.name = name; this.set = s;
		classes.Add(this);
	}
	
	public static CharClass Find(string name) {
		foreach (CharClass c in classes)
			if (c.name == name) return c;
		return null;
	}
	
	public static CharClass Find(BitArray s) {
		foreach (CharClass c in classes)
			if (Sets.Equals(s, c.set)) return c;
		return null;
	}
	
	public static BitArray Set(int i) {
		return ((CharClass)classes[i]).set;
	}
	
	static string Ch(int ch) {
		if (ch < ' ' || ch >= 127 || ch == '\'' || ch == '\\') return ch.ToString();
		else return String.Format("'{0}'", (char)ch);
	}
	
	static void WriteCharSet(BitArray s) {
			int i = 0, len = s.Count;
			while (i < len) {
				while (i < len && !s[i]) i++;
				if (i == len) break;
				int j = i;
				while (i < len && s[i]) i++;
				if (j < i-1) Trace.Write("{0}..{1} ", Ch(j), Ch(i-1)); 
				else Trace.Write("{0} ", Ch(j));
			}
	}
	
	public static void WriteClasses () {
		foreach (CharClass c in classes) {
			Trace.Write("{0,-10}: ", c.name);
			WriteCharSet(c.set);
			Trace.WriteLine();
		}
		Trace.WriteLine();
	}
}
//-----------------------------------------------------------
// Symbol table management routines
//-----------------------------------------------------------
public class Tab {
	public static Position semDeclPos;	// position of global semantic declarations
	public static BitArray ignored;			// characters ignored by the scanner
	public static bool[] ddt = new bool[10];	// debug and test switches
	public static Symbol gramSy;				// root nonterminal; filled by ATG
	public static Symbol eofSy;					// end of file symbol
	public static Symbol noSym;					// used in case of an error
	public static BitArray allSyncSets;	// union of all synchronisation sets
	public static string nsName;        // namespace for generated files
	
	static BitArray visited;						// mark list for graph traversals
	static Symbol curSy;								// current symbol in computation of sets
	
	//---------------------------------------------------------------------
	//  Symbol set computations
	//---------------------------------------------------------------------
	/* Computes the first set for the given Node. */
	static BitArray First0(Node p, BitArray mark) {
		BitArray fs = new BitArray(Symbol.terminals.Count);
		while (p != null && !mark[p.n]) {
			mark[p.n] = true;
			switch (p.typ) {
				case Node.nt: {
					if (p.sym.firstReady) fs.Or(p.sym.first);
					else fs.Or(First0(p.sym.graph, mark));
					break;
				}
				case Node.t: case Node.wt: {
					fs[p.sym.n] = true; break;
				}
				case Node.any: {
					fs.Or(p.set); break;
				}
				case Node.alt: {
					fs.Or(First0(p.sub, mark));
					fs.Or(First0(p.down, mark));
					break;
				}
				case Node.iter: case Node.opt: {
					fs.Or(First0(p.sub, mark));
					break;
				}
			}
			if (!Node.DelNode(p)) break;
			p = p.next;
		}
		return fs;
	}
	
	/// <returns>
	/// BitArray which contains the first tokens.
	/// </returns>
	public static BitArray First(Node p) {
		BitArray fs = First0(p, new BitArray(Node.nodes.Count));
		if (ddt[3]) {
			Trace.WriteLine(); 
			if (p != null) Trace.WriteLine("First: node = {0}", p.n);
			else Trace.WriteLine("First: node = null");
			Sets.PrintSet(fs, 0);
		}
		return fs;
	}
	
	static void CompFirstSets() {
		foreach (Symbol sym in Symbol.nonterminals) {
			sym.first = new BitArray(Symbol.terminals.Count);
			sym.firstReady = false;
		}
		foreach (Symbol sym in Symbol.nonterminals) {
			sym.first = First(sym.graph);
			sym.firstReady = true;
		}
	}
	
	static void CompFollow(Node p) {
		while (p != null && !visited[p.n]) {
			visited[p.n] = true;
			if (p.typ == Node.nt) {
				BitArray s = First(p.next);
				p.sym.follow.Or(s);
				if (Node.DelGraph(p.next))
					p.sym.nts[curSy.n] = true;
			} else if (p.typ == Node.opt || p.typ == Node.iter) {
				CompFollow(p.sub);
			} else if (p.typ == Node.alt) {
				CompFollow(p.sub); CompFollow(p.down);
			}
			p = p.next;
		}
	}
	
	static void Complete(Symbol sym) {
		if (!visited[sym.n]) {
			visited[sym.n] = true;
			foreach (Symbol s in Symbol.nonterminals) {
				if (sym.nts[s.n]) {
					Complete(s);
					sym.follow.Or(s.follow);
					if (sym == curSy) sym.nts[s.n] = false;
				}
			}
		}
	}
	
	static void CompFollowSets() {
		foreach (Symbol sym in Symbol.nonterminals) {
			sym.follow = new BitArray(Symbol.terminals.Count);
			sym.nts = new BitArray(Symbol.nonterminals.Count);
		}
		visited = new BitArray(Node.nodes.Count);
		foreach (Symbol sym in Symbol.nonterminals) { // get direct successors of nonterminals
			curSy = sym;
			CompFollow(sym.graph);
		}
		foreach (Symbol sym in Symbol.nonterminals) { // add indirect successors to followers
			visited = new BitArray(Symbol.nonterminals.Count);
			curSy = sym;
			Complete(sym);
		}
	}
	
	static Node LeadingAny(Node p) {
		if (p == null) return null;
		Node a = null;
		if (p.typ == Node.any) a = p;
		else if (p.typ == Node.alt) {
			a = LeadingAny(p.sub);


Answer: 			if (a == null) a = LeadingAny(p.down);