context: /*---------------------------------------------------------------------------*\
  Tab.cs -- Symbol Table Management
  
      Compiler Generator Coco/R,
      Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
      extended by M. Loeberbauer & A. Woess, Univ. of Linz
      with improvements by Pat Terry, Rhodes University
  -------------------------------------------------------------------------------
  License
      This file is part of Compiler Generator Coco/R
  
      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.
  
      As an exception, it is allowed to write an extension of Coco/R that is
      used as a plugin in non-free software.
  
      If not otherwise stated, any source code generated by Coco/R (other than
      Coco/R itself) does not fall under the GNU General Public License.
  \*---------------------------------------------------------------------------*/
  using System;
  using System.IO;
  using System.Text;
  using System.Collections;
  
  namespace at.jku.ssw.Coco {
  
  //=====================================================================
  // Position
  //=====================================================================
  //! position of source code stretch (e.g. semantic action, resolver expressions)
  public class Position
  {
  	public int beg;    //!< start relative to the beginning of the file
  	public int end;    //!< end of stretch
  	public int col;    //!< column number of start position
  
  	public Position(int beg, int end, int col) {
  		this.beg = beg; this.end = end; this.col = col;
  	}
  }
  
  
  //=====================================================================
  // Symbol
  //=====================================================================
  //! Grammar Symbol
  public class Symbol
  {
  	// token kinds
  	public const int fixedToken    = 0; //!< e.g. 'a' ('b' | 'c') (structure of literals)
  	public const int classToken    = 1; //!< e.g. digit {digit}   (at least one char class)
  	public const int litToken      = 2; //!< e.g. "while"
  	public const int classLitToken = 3; //!< e.g. letter {letter} but without literals that have the same structure
  
  	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 (fixedToken, classToken, ...)
  	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 Symbol(int typ, string name, int line) {
  		this.typ = typ; this.name = name; this.line = line;
  	}
  }
  
  
  //=====================================================================
  // Node
  //=====================================================================
  public class Node
  {
  	// 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
  
  	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 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 int      line;    //!< source text line number of item in this node
  
  	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
  	                         //!< rslv: pos of resolver in source text
  	public State    state;   //!< DFA state corresponding to this node
  	                         //!< (only used in DFA.ConvertToStates)
  
  	public bool     up;      //!< true: "next" leads to successor in enclosing structure
  	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 Node(int typ, Symbol sym, int line) {
  		this.typ = typ; this.sym = sym; this.line = line;
  	}
  }
  
  
  //=====================================================================
  // Graph
  //=====================================================================
  //! A connection of nodes
  public class Graph
  {
  	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;
  	}
  }
  
  
  //=====================================================================
  // Sets
  //=====================================================================
  //! Functions for BitArray operations
  public class Sets
  {
  	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 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());
  	}
  
  }
  
  
  //=====================================================================
  // CharClass
  //=====================================================================
  //! names character classes
  public class CharClass
  {
  	public int n;           //!< class number
  	public string name;     //!< class name
  	public CharSet set;     //!< set representing the class
  
  	public CharClass(string name, CharSet s) {
  		this.name = name; this.set = s;
  	}
  }
  
  
  //=====================================================================
  // Tab
  //=====================================================================
  //! Symbol Table Management
  public class Tab
  {
  	const char CR  = '\r';
  	const char LF  = '\n';
  
  	public bool explicitEOF = false;  //!< user must explicitly add EOF in grammar
  	public bool makeBackup  = false;  //!< create .bak files for generated parser/scanner
  	public bool[] ddt = new bool[10]; //!< debug and test switches
  
  	public Position copyPos = null;   //!< position of verbatim copy (eg, copyright headers) in atg
  
  	public CharSet ignored;           //!< characters ignored by the scanner
  	public Symbol gramSy;             //!< root nonterminal; filled by ATG
  	public Symbol eofSy;              //!< end of file symbol
  	public Symbol noSym;              //!< used in case of an error
  	public BitArray allSyncSets;      //!< union of all synchronisation sets
  	public Hashtable literals;        //!< symbols that are used as literals
  
  	public string srcName;            //!< name of the atg file (including path)
  	public string srcDir;             //!< directory path of the atg file
  	public string nsName = null;      //!< namespace for generated files
  	public string prefixName = null;  //!< prefix for generated files
  	public string frameDir;           //!< directory containing the frame files
  	public string outDir;             //!< directory for generated files
  
  	BitArray visited;                 //!< mark list for graph traversals
  	Symbol curSy;                     //!< current symbol in computation of sets
  
  	Parser parser;                    // other Coco objects
  	Errors errors;
  	public Buffer buffer;
  
  	public TextWriter trace = Console.Error;
  
  	public Tab(Parser parser) {
  		this.parser = parser;
  		errors = parser.errors;
  		buffer = parser.scanner.buffer;
  		eofSy = NewSym(Node.t, "EOF", 0);
  		dummyNode = NewNode(Node.eps, null, 0);
  		ignored  = new CharSet();
  		literals = new Hashtable();
  	}
  
  	//---------------------------------------------------------------------
  	//  Symbol list management
  	//---------------------------------------------------------------------
  
  	public ArrayList terminals = new ArrayList();
  	public ArrayList pragmas = new ArrayList();
  	public ArrayList nonterminals = new ArrayList();
  
  	string[] tKind = {"fixedToken", "classToken", "litToken", "classLitToken"};
  
  	public Symbol NewSym(int typ, string name, int line) {
  		if (name.Length == 2 && name[0] == '"') {
  			parser.SemErr("empty token not allowed"); name = "???";
  		}
  		Symbol sym = new Symbol(typ, name, line);
  		switch (typ) {
  			case Node.t:  sym.n = terminals.Count; terminals.Add(sym); break;
  			case Node.pr: pragmas.Add(sym); break;
  			case Node.nt: sym.n = nonterminals.Count; nonterminals.Add(sym); break;
  		}
  		return sym;
  	}
  
  	public Symbol FindSym(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;
  	}
  
  	int Num(Node p) {
  		if (p == null) return 0; else return p.n;
  	}
  
  	void PrintSym(Symbol sym) {
  		trace.Write("{0,3} {1,-14} {2}", sym.n, Name(sym.name), nTyp[sym.typ]);
  		if (sym.attrPos==null) trace.Write(" false "); else trace.Write(" true  ");
  		if (sym.typ == Node.nt) {
  			trace.Write("{0,5}", Num(sym.graph));
  			if (sym.deletable) trace.Write(" true  "); else trace.Write(" false ");
  		} else
  			trace.Write("            ");
  		trace.WriteLine("{0,5} {1}", sym.line, tKind[sym.tokenKind]);
  	}
  
  	public void PrintSymbolTable() {
  		trace.WriteLine("Symbol Table:");
  		trace.WriteLine("------------"); trace.WriteLine();
  		trace.WriteLine(" nr name          typ  hasAt graph  del    line tokenKind");
  		foreach (Symbol sym in terminals) PrintSym(sym);
  		foreach (Symbol sym in pragmas) PrintSym(sym);
  		foreach (Symbol sym in nonterminals) PrintSym(sym);
  		trace.WriteLine();
  		trace.WriteLine("Literal Tokens:");
  		trace.WriteLine("--------------");
  		foreach (DictionaryEntry e in literals) {
  			trace.WriteLine("_" + ((Symbol)e.Value).name + " = " + e.Key + ".");
  		}
  		trace.WriteLine();
  	}
  
  	public void PrintSet(BitArray s, int indent) {
  		int col, len;
  		col = indent;
  		foreach (Symbol sym in 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();
  	}
  
  	//---------------------------------------------------------------------
  	//  Syntax graph management
  	//---------------------------------------------------------------------
  
  	public ArrayList nodes = new ArrayList();
  	public string[] nTyp =
  		{"    ", "t   ", "pr  ", "nt  ", "clas", "chr ", "wt  ", "any ", "eps ",
  		 "sync", "sem ", "alt ", "iter", "opt ", "rslv"};
  	Node dummyNode;
  
  	public Node NewNode(int typ, Symbol sym, int line) {
  		Node node = new Node(typ, sym, line);
  		node.n = nodes.Count;
  		nodes.Add(node);
  		return node;
  	}
  
  	public Node NewNode(int typ, Node sub) {
  		Node node = NewNode(typ, null, 0);
  		node.sub = sub;
  		return node;
  	}
  
  	public Node NewNode(int typ, int val, int line) {
  		Node node = NewNode(typ, null, line);
  		node.val = val;
  		return node;
  	}
  
  	public void MakeFirstAlt(Graph g) {
  		g.l = NewNode(Node.alt, g.l); g.l.line = g.l.sub.line;
  		g.r.up = true;
  		g.l.next = g.r;
  		g.r = g.l;
  	}
  
  	// The result will be in g1
  	public void MakeAlternative(Graph g1, Graph g2) {
  		g2.l = NewNode(Node.alt, g2.l); g2.l.line = g2.l.sub.line;
  		g2.l.up = true;
  		g2.r.up = true;
  		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;
  		// append alternative to g1 end list
  		p.next = g2.l;
  		// append g2 end list to g1 end list
  		g2.l.next = g2.r;
  	}
  
  	// The result will be in g1
  	public 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 = q;
  		}
  		g1.r = g2.r;
  	}
  
  	public void MakeIteration(Graph g) {
  		g.l = NewNode(Node.iter, g.l);
  		g.r.up = true;
  		Node p = g.r;
  		g.r = g.l;
  		while (p != null) {
  			Node q = p.next; p.next = g.l;
  			p = q;
  		}
  	}
  
  	public void MakeOption(Graph g) {
  		g.l = NewNode(Node.opt, g.l);
  		g.r.up = true;
  		g.l.next = g.r;
  		g.r = g.l;
  	}
  
  	public void Finish(Graph g) {
  		Node p = g.r;
  		while (p != null) {
  			Node q = p.next; p.next = null;
  			p = q;
  		}
  	}
  
  	public void DeleteNodes() {
  		nodes = new ArrayList();
  		dummyNode = NewNode(Node.eps, null, 0);
  	}
  
  	public Graph StrToGraph(string str) {
  		string s = Unescape(str.Substring(1, str.Length-2));
  		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 = NewNode(Node.chr, (int)s[i], 0);
  			g.r.next = p; g.r = p;
  		}
  		g.l = dummyNode.next; dummyNode.next = null;
  		return g;
  	}
  
  	public void SetContextTrans(Node p) { // set transition code in the graph rooted at p
  		while (p != null) {
  			switch (p.typ) {
  				case Node.chr:
  				case Node.clas:
  					p.code = Node.contextTrans;
  					break;
  				case Node.opt:
  				case Node.iter:
  					SetContextTrans(p.sub);
  					break;
  				case Node.alt:
  					SetContextTrans(p.sub); SetContextTrans(p.down);
  					break;
  			}
  			if (p.up) break;
  			p = p.next;
  		}
  	}
  
  	//------------ graph deletability check -----------------
  
  	public static bool DelGraph(Node p) {
  		return p == null || DelNode(p) && DelGraph(p.next);
  	}
  
  	public static bool DelSubGraph(Node p) {
  		return p == null || DelNode(p) && (p.up || DelSubGraph(p.next));
  	}
  
  	public static bool DelNode(Node p) {
  		if (p.typ == Node.nt) return p.sym.deletable;
  		else if (p.typ == Node.alt) return DelSubGraph(p.sub) || p.down != null && DelSubGraph(p.down);
  		else return p.typ == Node.iter || p.typ == Node.opt || p.typ == Node.sem
  			|| p.typ == Node.eps || p.typ == Node.rslv || p.typ == Node.sync;
  	}
  
  	//----------------- graph printing ----------------------
  
  	string Ptr(Node p, bool up) {
  		string ptr = (p == null) ? "0" : p.n.ToString();
  		return (up) ? ("-" + ptr) : ptr;
  	}
  
  	string Pos(Position pos) {
  		if (pos == null) return "     "; else return String.Format("{0,5}", pos.beg);
  	}
  
  	public string Name(string name) {
  		return (name + "           ").Substring(0, 12);
  		// found no simpler way to get the first 12 characters of the name
  		// padded with blanks on the right
  	}
  
  	public 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)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 Node.t: case Node.nt: case Node.wt:
  					trace.Write("             {0,5}", Pos(p.pos)); break;
  				case Node.chr:
  					trace.Write("{0,5} {1,5}       ", p.val, p.code); break;
  				case Node.clas:
  					trace.Write("      {0,5}       ", p.code); break;
  				case Node.alt: case Node.iter: case Node.opt:
  					trace.Write("{0,5} {1,5}       ", Ptr(p.down, false), Ptr(p.sub, false)); break;
  				case Node.sem:
  					trace.Write("             {0,5}", Pos(p.pos)); break;
  				case Node.eps: case Node.any: case Node.sync:
  					trace.Write("                  "); break;
  			}
  			trace.WriteLine("{0,5}", p.line);
  		}
  		trace.WriteLine();
  	}
  
  
  	//---------------------------------------------------------------------
  	//  Character class management
  	//---------------------------------------------------------------------
  
  	public ArrayList classes = new ArrayList();
  	public int dummyName = 'A';
  
  	public CharClass NewCharClass(string name, CharSet s) {
  		if (name == "#") name = "#" + (char)dummyName++;
  		CharClass c = new CharClass(name, s);
  		c.n = classes.Count;
  		classes.Add(c);
  		return c;
  	}
  
  	public CharClass FindCharClass(string name) {
  		foreach (CharClass c in classes)
  			if (c.name == name) return c;
  		return null;
  	}
  
  	public CharClass FindCharClass(CharSet s) {
  		foreach (CharClass c in classes)
  			if (s.Equals(c.set)) return c;
  		return null;
  	}
  
  	public CharSet CharClassSet(int i) {
  		return ((CharClass)classes[i]).set;
  	}
  
  	//----------- character class printing
  
  	string Ch(int ch) {
  		if (ch < ' ' || ch >= 127 || ch == '\'' || ch == '\\') return ch.ToString();
  		else return String.Format("'{0}'", (char)ch);
  	}
  
  	void WriteCharSet(CharSet s) {
  		for (CharSet.Range r = s.head; r != null; r = r.next)
  			if (r.from < r.to) { trace.Write(Ch(r.from) + ".." + Ch(r.to) + " "); }
  			else { trace.Write(Ch(r.from) + " "); }
  	}
  
  	public void WriteCharClasses () {
  		foreach (CharClass c in classes) {
  			trace.Write("{0,-10}: ", c.name);
  			WriteCharSet(c.set);
  			trace.WriteLine();
  		}
  		trace.WriteLine();
  	}
  
  
  	//---------------------------------------------------------------------
  	//  Symbol set computations
  	//---------------------------------------------------------------------
  
  	/* Computes the first set for the graph rooted at p */
  	BitArray First0(Node p, BitArray mark) {
  		BitArray fs = new BitArray(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 (!DelNode(p)) break;
  			p = p.next;
  		}
  		return fs;
  	}
  
  	public BitArray First(Node p) {
  		BitArray fs = First0(p, new BitArray(nodes.Count));
  		if (ddt[3]) {
  			trace.WriteLine();
  			if (p != null) trace.WriteLine("First: node = {0}", p.n);
  			else trace.WriteLine("First: node = null");
  			PrintSet(fs, 0);
  		}
  		return fs;
  	}
  
  	void CompFirstSets() {
  		foreach (Symbol sym in nonterminals) {
  			sym.first = new BitArray(terminals.Count);
  			sym.firstReady = false;
  		}
  		foreach (Symbol sym in nonterminals) {
  			sym.first = First(sym.graph);
  			sym.firstReady = true;
  		}
  	}
  
  	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 (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;
  		}
  	}
  
  	void Complete(Symbol sym) {
  		if (!visited[sym.n]) {
  			visited[sym.n] = true;
  			foreach (Symbol s in nonterminals) {
  				if (sym.nts[s.n]) {
  					Complete(s);
  					sym.follow.Or(s.follow);
  					if (sym == curSy) sym.nts[s.n] = false;
  				}
  			}
  		}
  	}
  
  	void CompFollowSets() {
  		foreach (Symbol sym in nonterminals) {
  			sym.follow = new BitArray(terminals.Count);
  			sym.nts = new BitArray(nonterminals.Count);
  		}
  		gramSy.follow[eofSy.n] = true;
  		visited = new BitArray(nodes.Count);
  		foreach (Symbol sym in nonterminals) { // get direct successors of nonterminals
  			curSy = sym;
  			CompFollow(sym.graph);
  		}
  		foreach (Symbol sym in nonterminals) { // add indirect successors to followers
  			visited = new BitArray(nonterminals.Count);
  			curSy = sym;
  			Complete(sym);
  		}
  	}
  
  	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);
  			if (a == null) a = LeadingAny(p.down);
  		}
  		else if (p.typ == Node.opt || p.typ == Node.iter) a = LeadingAny(p.sub);
  		if (a == null && DelNode(p) && !p.up) a = LeadingAny(p.next);
  		return a;
  	}
  
  	void FindAS(Node p) { // find ANY sets
  		Node a;
  		while (p != null) {
  			if (p.typ == Node.opt || p.typ == Node.iter) {
  				FindAS(p.sub);
  				a = LeadingAny(p.sub);
  				if (a != null) Sets.Subtract(a.set, First(p.next));
  			} else if (p.typ == Node.alt) {
  				BitArray s1 = new BitArray(terminals.Count);
  				Node q = p;
  				while (q != null) {
  					FindAS(q.sub);
  
gt: 					a = LeadingAny(q.sub);