Click here to Skip to main content
15,886,199 members
Articles / Programming Languages / C#

Script.NET a language for embedding scripting functionality into CLR Applications

Rate me:
Please Sign up or sign in to vote.
4.90/5 (50 votes)
16 Dec 2008CPOL6 min read 223.5K   2.8K   196  
Scripting language for .NET Framework 2.0. Supports native .NET Types, Dynamic casting, Meta programming.
// Malcolm Crowe 1995, 2000
// a yacc-style implementation

using System;
using System.Collections;
using System.IO;
using System.Text;

namespace Tools 
{
	internal class  YyParser
	{
		public ErrorHandler erh = new ErrorHandler(true); // should get overwritten by Parser constructor
		public YyParser() { }
		// symbols
		public Hashtable symbols = new Hashtable(); // string -> CSymbol
		public Hashtable literals = new Hashtable(); // string -> Literal
		// support for parsing
		public Hashtable symbolInfo = new Hashtable();  // yynum -> ParsingInfo
		public bool m_concrete; // whether to build the concrete syntax tree
		public Hashtable m_states = new Hashtable(); // int->ParseState
		public CSymbol EOFSymbol;
		public CSymbol Special;
		public CSymbol m_startSymbol;
		public string StartSymbol
		{
			get { return (m_startSymbol!=null)?m_startSymbol.yytext:"<null>"; }
			set 
			{
				CSymbol s = (CSymbol)symbols[value];
				if (s==null)
					erh.Error(new CSToolsException(25,"No such symbol <"+value+">"));
				m_startSymbol = s;
			}
		}
#if (GENTIME)
		public ParsingInfo GetSymbolInfo(string name,int num)
		{
			ParsingInfo pi = (ParsingInfo)symbolInfo[num];
			if (pi==null) 			
				symbolInfo[num] = pi = new ParsingInfo(name,num);
			return pi;
		}
		public void ClassInit(SymbolsGen yyp)   
		{
			Special = new CSymbol(yyp); Special.yytext="S'"; 
			EOFSymbol = new EOF(yyp).Resolve();
		}
		public void Transitions(Builder b)
		{
			foreach (ParseState ps in m_states.Values)
				foreach (Transition t in ps.m_transitions.Values)
					b(t);
		}
		public void PrintTransitions(Func f,string s)
		{
			foreach (ParseState ps in m_states.Values)
				foreach (Transition t in ps.m_transitions.Values)
					t.Print(f(t),s);
		}
#endif
		public ParseState m_accept;
		// support for actions
		public virtual object Action(Parser yyp,SYMBOL yysym, int yyact) { return null; } // will be generated for the generated parser
		public Hashtable types = new Hashtable(); // string->SCreator
		// support for serialization
		public int[] arr; // defined in generated subclass
	
		public void GetEOF(Lexer yyl)
		{
			EOFSymbol = (EOF)symbols["EOF"];
			if (EOFSymbol==null)
				EOFSymbol = new EOF(yyl);
		}
#if (GENTIME)
		public void Emit(TextWriter m_outFile)
		{
			Serialiser b = new Serialiser(m_outFile);
			b.VersionCheck();
			Console.WriteLine("Serialising the parser");
			b.Serialise(m_startSymbol);
			b.Serialise(m_accept);
			b.Serialise(m_states);
			b.Serialise(literals);
			b.Serialise(symbolInfo);
			b.Serialise(m_concrete);
			m_outFile.WriteLine("0};");
		}
#endif
		public void GetParser(Lexer m_lexer)
		{
			Serialiser b = new Serialiser(arr);
			b.VersionCheck();
			m_startSymbol = (CSymbol)b.Deserialise();
			m_startSymbol.kids = new ObjectList(); // 4.2a
			m_accept = (ParseState)b.Deserialise();
			m_states = (Hashtable)b.Deserialise();
			literals = (Hashtable)b.Deserialise();
			symbolInfo = (Hashtable)b.Deserialise();
			m_concrete = (bool)b.Deserialise();
			GetEOF(m_lexer);
		}
	}

#if (GENTIME)
	// Context free Grammar is a quadruple G=<T,N,S,P>
	// where T is a finite set of terminal symbols
	// [namely, the instances of TOKEN]
	// N is a finite set of nonterminal symbols 
	// [namely, the instances of SYMBOL for which IsTerminal() is false]
	// such that T intersect N = emptyset.
	// S [= m_symbols.m_startSymbol] is the start symbol
	// P is a finite subset of N x V* where V = T union N
	// [i.e. V is the set of instances of SYMBOL]
	// and each member (A,w) of P is called a production
	// [i.e. an instance p of Production] written A->w .
	// A is called the left part [p.m_lhs] 
	// and w the right part [the ObjectList p.m_rhs]
	public abstract class SymbolsGen : GenBase
	{
		protected SymbolsGen(ErrorHandler eh):base(eh) {}
		public bool m_lalrParser = true;
		public Lexer m_lexer;
		public YyParser m_symbols = new YyParser();
		// Productions
		public int pno = 0;
		public ObjectList prods = new ObjectList(); // Production
		public int m_trans = 0; // #Transitions
		// support for actions
		public int action = 0;
		internal ObjectList actions = new ObjectList();  // ParserAction
		internal int action_num = 0; // for old actions
		public SymbolType stypes = null; // the list of grammar symbols
		internal int state=0; // for parsestates
		public SymbolSet lahead = null; // support for lookahead sets
		public bool Find(CSymbol sym) 
		{
			if (sym.yytext.Equals("Null")) // special case
				return true;
			if (sym.yytext[0]=='\'')
				return true;
			if (stypes==null)
				return false;
			return stypes._Find(sym.yytext)!=null;
		}	
		public abstract void ParserDirective();
		public abstract void Declare();
		public abstract void SetNamespace();
		public abstract void SetStartSymbol();
		public abstract void ClassDefinition(string s);
		public abstract void AssocType(Precedence.PrecType pt,int n);
		public abstract void CopySegment();
		public abstract void SimpleAction(ParserSimpleAction a);
		public abstract void OldAction(ParserOldAction a);
	}

	internal class  SymbolType
	{
		string m_name;
		SymbolType m_next;
		public SymbolType(SymbolsGen yyp,string name) : this(yyp,name,false)	{}
		public SymbolType(SymbolsGen yyp,string name,bool defined) 
		{ 
			Lexer yyl = yyp.m_lexer;
			int p = name.IndexOf("+");
			int num = 0;
			if (p>0)
			{
				num = int.Parse(name.Substring(p+1));
				if (num> yyp.LastSymbol)
					yyp.LastSymbol = num;
				name = name.Substring(0,p);
			}
			yyl.yytext = name;
			CSymbol s = new CSymbol(yyp);
			if (num>0)
				s.m_yynum = num;
			s = s.Resolve();
			if (defined) 
				s.m_defined = true;
			m_name = name; m_next=yyp.stypes; yyp.stypes=this;
		}
		public SymbolType _Find(string name) 
		{
			if (name.Equals(m_name))
				return this;
			if (m_next==null)
				return null;
			return m_next._Find(name);
		}
	}
#endif
	internal class  ParserAction : CSymbol 
	{
		public virtual SYMBOL Action(Parser yyp) 
		{
			SYMBOL s = (SYMBOL)Sfactory.create(m_sym.yytext,yyp);
			if (s.yyname==m_sym.yytext) 
			{  // provide for the default $$ = $1 action if possible
				SYMBOL t = yyp.StackAt(m_len-1).m_value;
				s.m_dollar = (m_len==0 || t==null)? null : t.m_dollar;
			}
			return s;
		}
		public override void Print() { Console.Write(m_sym.yytext); }
		public CSymbol m_sym;
		public int m_len;
		public override Boolean IsAction() { return true; }
		public virtual int ActNum() { return 0; }
#if (GENTIME)
		public ParserAction(SymbolsGen yyp) : base(yyp) {}
#endif
		protected ParserAction() {}
		public new static object Serialise(object o,Serialiser s)
		{
			ParserAction p = (ParserAction)o;
			if (s.Encode)
			{
				CSymbol.Serialise(p,s);
				s.Serialise(p.m_sym);
				s.Serialise(p.m_len);
				return null;
			}
			CSymbol.Serialise(p,s);
			p.m_sym = (CSymbol)s.Deserialise();
			p.m_len = (int)s.Deserialise();
			return p;
		}
	}

	internal class  ParserOldAction : ParserAction
	{
		public int m_action;
		public override SYMBOL Action(Parser yyp) 
		{
			SYMBOL s = base.Action(yyp);
			object ob = yyp.m_symbols.Action(yyp,s,m_action);
			if (ob!=null)
				s.m_dollar = ob;
			return s;
		}
		public override int ActNum() { return m_action; }
#if (GENTIME)
		public ParserOldAction(SymbolsGen yyp) : base(yyp) {
			m_action =  yyp.action_num++;
			yyp.actions.Add(this); m_sym = null;
			m_symtype = CSymbol.SymType.oldaction;
			yyp.OldAction(this);
		}
#endif
		ParserOldAction() {}
		public new static object Serialise(object o,Serialiser s)
		{
			if (s==null)
				return new ParserOldAction();
			ParserOldAction p = (ParserOldAction)o;
			if (s.Encode) 
			{
				ParserAction.Serialise(p,s);
				s.Serialise(p.m_action);
				return null;
			}
			ParserAction.Serialise(p,s);
			p.m_action = (int)s.Deserialise();
			return p;
		}
	}

	internal class  ParserSimpleAction : ParserAction 
	{
#if (GENTIME)
		public override string TypeStr() { return m_sym.yytext; }
		public override void Print() 
		{
			Console.Write(" %{0}", m_sym.yytext);
		}
		public ParserSimpleAction(SymbolsGen yyp) : base(yyp) {
			yyp.actions.Add(this);
			m_symtype = CSymbol.SymType.simpleaction;
			yyp.SimpleAction(this);
		}
#endif
		ParserSimpleAction() {}
		public new static object Serialise(object o,Serialiser s)
		{
			if (s==null)
				return new ParserSimpleAction();
			if (s.Encode)
			{
				ParserAction.Serialise(o,s);
				return null;
			}
			return ParserAction.Serialise(o,s);
		}
	}

	internal abstract class ParserEntry
	{
		public ParserAction m_action;
		public int m_priority = 0;
		public ParserEntry() { m_action = null; }
		public ParserEntry(ParserAction action) { m_action=action; }
		public virtual void Pass(ref ParseStackEntry top) {}
		public virtual bool IsReduce() { return false; }
		public virtual string str { get { return ""; }}
		public static object Serialise(object o, Serialiser s)
		{
			ParserEntry p = (ParserEntry)o;
			if (s.Encode) 
			{
				s.Serialise(p.m_action);
				return null;
			}
			p.m_action = (ParserAction)s.Deserialise();
			return p;
		}
	}

	internal class  ParserShift : ParserEntry
	{
		public ParseState m_next;
		public ParserShift() {}
		public ParserShift(ParserAction action,ParseState next) : base(action) { m_next=next; }
		public override void Pass(ref ParseStackEntry top) 
		{
			Parser yyp = top.yyps;
			if(m_action==null) 
			{
				yyp.Push(top);
				top = new ParseStackEntry(yyp,m_next.m_state,yyp.NextSym());
			} 
			else 
			{
				yyp.Push(new ParseStackEntry(yyp,top.m_state,m_action.Action(yyp)));
				top.m_state = m_next.m_state;
			}
		}
		public override string str 
		{
			get 
			{	
				if (m_next==null)
					return "?? null shift";
				return string.Format("shift {0}",m_next.m_state); }
		}
		public new static object Serialise(object o,Serialiser s)
		{
			if (s==null)
				return new ParserShift();
			ParserShift p = (ParserShift)o;
			if (s.Encode) 
			{
				ParserEntry.Serialise(p,s);
				s.Serialise(p.m_next);
				return null;
			}
			ParserEntry.Serialise(p,s);
			p.m_next = (ParseState)s.Deserialise();
			return p;
		}
	}

	internal class  ParserReduce : ParserEntry
	{
		public int m_depth;
		public Production m_prod;
		public ParserReduce(ParserAction action,int depth,Production prod) : base(action) {m_depth=depth; m_prod = prod; }
		ParserReduce() {}
#if (GENTIME)
		public SymbolSet m_lookAhead = null;
		public void BuildLookback(Transition a)
		{
			SymbolsGen sg = a.m_ps.m_sgen;
			if (m_lookAhead!=null)
				return;
			m_lookAhead = new SymbolSet(sg);
			foreach (ParseState p in sg.m_symbols.m_states.Values) 
			{
				Transition b = (Transition)p.m_transitions[m_prod.m_lhs.yytext];
				if (b==null)
					continue;
				Path pa = new Path(p,m_prod.Prefix(m_prod.m_rhs.Count));
				if (pa.valid && pa.Top == a.m_ps)
					b.m_lookbackOf[this] = true;
			}
		}
#endif
		public override void Pass(ref ParseStackEntry top) 
		{
			Parser yyp = top.yyps;
			SYMBOL ns = m_action.Action(yyp); // before we change the stack
			yyp.m_ungot = top.m_value;
			if (yyp.m_debug)
				Console.WriteLine("about to pop {0} count is {1}",m_depth,yyp.m_stack.Count);
			yyp.Pop(ref top,m_depth,ns);
			if (ns.pos==0)
				ns.pos = top.m_value.pos;  // Guess symbol position
			top.m_value = ns;
		}
		public override bool IsReduce() { return true; }
		public override string str 
		{
			get 
			{ 	
				if (m_prod==null)
					return "?? null reduce";
				return string.Format("reduce {0}",m_prod.m_pno); 
			}
		}
		public new static object Serialise(object o,Serialiser s)
		{
			if (s==null)
				return new ParserReduce();
			ParserReduce p = (ParserReduce)o;
			if (s.Encode) 
			{
				ParserEntry.Serialise(p,s);
				s.Serialise(p.m_depth);
				s.Serialise(p.m_prod);
				return null;
			}
			ParserEntry.Serialise(p,s);
			p.m_depth = (int)s.Deserialise();
			p.m_prod = (Production)s.Deserialise();
			return p;
		}
	}
#if (GENTIME)
	public delegate Hashtable Relation(Transition a); // Transition->bool
	public delegate SymbolSet Func(Transition a);
	public delegate void AddToFunc(Transition a,SymbolSet s);
	public delegate void Builder(Transition t);
	internal class  Transition
	{
		public int m_tno;
		public ParseState m_ps;
		public CSymbol m_A;
		public Transition(ParseState p,CSymbol a) 
		{ 
			m_ps = p; m_A = a; 
			m_tno = p.m_sgen.m_trans++;
			p.m_transitions[a.yytext] = this;
		}
		private ParsingInfo ParsingInfo
		{
			get 
			{
				YyParser syms = m_ps.m_sgen.m_symbols;
				return syms.GetSymbolInfo(m_A.yytext,m_A.m_yynum);
			}
		}
		public ParserShift m_next = null;
		public Hashtable m_reduce = new Hashtable(); // Production->ParserReduce
		Hashtable m_reads = new Hashtable(); // Transition->bool
		Hashtable m_includes = new Hashtable(); // Transition->bool
		internal Hashtable m_lookbackOf = new Hashtable(); // ParserReduce->bool
		public static Hashtable reads(Transition a) { return a.m_reads; }
		public static Hashtable includes(Transition a) { return a.m_includes; }
		public static SymbolSet DR(Transition a) { return a.m_DR; }
		public static SymbolSet Read(Transition a) { return a.m_Read; }
		public static SymbolSet Follow(Transition a) { return a.m_Follow; }
		public static void AddToRead(Transition a,SymbolSet s) { a.m_Read.Add(s); }
		public static void AddToFollow(Transition a, SymbolSet s) { a.m_Follow.Add(s); }
		SymbolSet m_DR; // built by BuildDR, called from parserGenerator
		SymbolSet m_Read; // built using Digraph Compute called from ParserGenerator
		SymbolSet m_Follow; // ditto
		public static void BuildDR(Transition t)
		{
			SymbolsGen sg = t.m_ps.m_sgen;
			t.m_DR = new SymbolSet(sg);
			if (t.m_next==null)
				return;
			foreach (Transition u in t.m_next.m_next.m_transitions.Values)
				if (u.m_next!=null)
					if (u.m_A.m_symtype==CSymbol.SymType.terminal || u.m_A.m_symtype==CSymbol.SymType.eofsymbol)
						t.m_DR.AddIn(u.m_A);
		}
		public static void Final(Transition t)
		{
			t.m_DR.AddIn(t.m_ps.m_sgen.m_symbols.EOFSymbol);
		}
		public static void BuildReads(Transition t)
		{
			t.m_Read = new SymbolSet(t.m_ps.m_sgen);
			ParseState ps = t.m_A.Next(t.m_ps);
			if (ps==null)
				return;
			foreach (Transition b in ps.m_transitions.Values)
				if (b.m_A.IsNullable())
					t.m_reads[b] = true;
		}
	    public static void BuildIncludes( Transition t) // code improved by Wayne Kelly
        {
            t.m_Follow = new SymbolSet (t.m_ps.m_sgen);
            foreach (Production p in t.m_A.m_prods)
            {
                for ( int i = p.m_rhs.Count - 1; i >= 0; i--)
                {
                    CSymbol s = ( CSymbol)p.m_rhs[i];
                    if (s.m_symtype == CSymbol. SymType .nonterminal)
                    {
                        ParseState ps;
                        if (i > 0)
                            ps = new Path(t.m_ps, p.Prefix(i)).Top;
                        else
                            ps = t.m_ps;

                        Transition b = ( Transition) ps.m_transitions[s.yytext];
                        b.m_includes[t] = true;
                    }
                    if (!s.IsNullable())
                        break;
                }
            }
        }
		public static void BuildLookback(Transition t)
		{
			foreach (ParserReduce pr in t.m_reduce.Values)
				pr.BuildLookback(t);
		}
		public static void BuildLA(Transition t)
		{
			foreach (ParserReduce pr in t.m_lookbackOf.Keys)
				pr.m_lookAhead.Add(t.m_Follow);
		}
		public static void BuildParseTable(Transition t)
		{
			YyParser syms = t.m_ps.m_sgen.m_symbols;
			ParsingInfo pi = t.ParsingInfo;
			ParserReduce red = null;
			foreach (ParserReduce pr in t.m_reduce.Values)
			{
					if (t.m_ps.m_sgen.m_lalrParser?
						pr.m_lookAhead.Contains(t.m_A):
						pr.m_prod.m_lhs.m_follow.Contains(t.m_A)) 
					{
						if (red!=null)
							syms.erh.Error(new CSToolsException(12,string.Format("reduce/reduce conflict {0} vs {1}",red.m_prod.m_pno,pr.m_prod.m_pno)+
								string.Format(" state {0} on {1}",t.m_ps.m_state,t.m_A.yytext)));
						red = pr;
					} 
				//	else 
				//		t.Print(pr.m_lookAhead,"discarding reduce ("+pr.m_prod.m_pno+") LA ");
			}
			if (t.m_next!=null && t.m_A!=syms.EOFSymbol)
			{
				if (red==null) 
					pi.m_parsetable[t.m_ps.m_state] = t.m_next;
				else 
					switch (t.m_A.ShiftPrecedence(red.m_prod,t.m_ps))			// 4.5h
					{		
						case Precedence.PrecType.left :
							pi.m_parsetable[t.m_ps.m_state] = t.m_next; break;
						case Precedence.PrecType.right :
							pi.m_parsetable[t.m_ps.m_state] = red; break;
					}
			} 
			else if (red!=null)
				pi.m_parsetable[t.m_ps.m_state] = red;
		}
		public void Print0()
		{
			Console.Write("    "+m_A.yytext);
			if (m_next!=null)
				Console.Write("  shift "+m_next.m_next.m_state);
			foreach (Production p in m_reduce.Keys)
				Console.Write("  reduce ("+p.m_pno+")");
			Console.WriteLine();
		}
		public void Print(SymbolSet x,string s)
		{
			Console.Write("Transition ("+m_ps.m_state+","+m_A.yytext+") "+s+" ");
			x.Print();
		}
	}
	// The Closure and AddActions functions represent the heart of the ParserGenerator
#endif

	internal class  ParseState
	{
		public int m_state;
		public CSymbol m_accessingSymbol;
		bool m_changed = true;
#if (GENTIME)
		public SymbolsGen m_sgen;
		internal ProdItemList m_items; // ProdItem, in ProdItem order
		public Hashtable m_transitions = new Hashtable(); // string -> Transition
		public Transition GetTransition(CSymbol s)
		{
			Transition t = (Transition)m_transitions[s.yytext];
			if (t!=null)
				return t;
			return new Transition(this,s);
		}
		public bool Accessor(CSymbol[] x) { return new Path(x).Top == this; }
		public bool Lookback(Production pr,ParseState p) { return new Path(this,pr.Prefix(pr.m_rhs.Count)).Top==this; }
		public void MaybeAdd(ProdItem item) 
		{ // called by CSymbol.AddStartItems
			if (!m_items.Add(item))
				return;
			m_changed = true;
		}
		public void Closure() 
		{
			while (m_changed) 
			{
				m_changed = false;
				for (ProdItemList pi = m_items; pi.m_pi!=null; pi = pi.m_next)
					CheckClosure(pi.m_pi);
			}
		}
		public void CheckClosure(ProdItem item) 
		{
			CSymbol ss = item.Next();
			if (ss!=null) 
			{
				ss.AddStartItems(this,item.FirstOfRest(ss.m_parser));
				if (item.IsReducingAction())
					MaybeAdd(new ProdItem(item.m_prod, item.m_pos+1));
			}
		}
		public void AddEntries() 
		{
			ProdItemList pil;
			for (pil=m_items; pil.m_pi!=null; pil=pil.m_next) 
			{
				ProdItem item = pil.m_pi;
				if (item.m_done)
					continue;
				CSymbol s = item.Next();
				if (s==null || item.IsReducingAction())
					continue;
				// shift/goto action
				// Build a new parse state as target: we will check later to see if we need it
				ParseState p = new ParseState(m_sgen,s);
				// the new state should have at least the successor of this item
				p.MaybeAdd(new ProdItem(item.m_prod, item.m_pos+1));

				// check the rest of the items in this ParseState (leads to m_done for them)
				// looking for other items that allow this CSymbol to pass
				for (ProdItemList pil1=pil.m_next; pil1!=null && pil1.m_pi!=null; pil1=pil1.m_next) 
				{
					ProdItem another = pil1.m_pi;
					if (s==another.Next())
					{
						p.MaybeAdd(new ProdItem(another.m_prod, another.m_pos+1));
						another.m_done = true;
					}
				}

				if (!m_items.AtEnd) 
				{
					if (s.IsAction()) 
					{
						p = p.CheckExists();
						foreach (CSymbol f in s.m_follow.Keys)
							if (f!=m_sgen.m_symbols.EOFSymbol) 
							{
								Transition t = GetTransition(f);
//								if (t.m_next!=null)
//									m_sgen.Error(15,s.pos,String.Format("Action/Action or Action/Shift conflict on {0}",f.yytext));
								t.m_next = new ParserShift((ParserAction)s,p);
							}
					} 
					else 
					{ // we guarantee to make a nonzero entry in the parsetable
						GetTransition(s).m_next = new ParserShift(null, p.CheckExists());
					}
				}
			}
		}
		public void ReduceStates() 
		{
			ProdItemList pil;
			for (pil=m_items; pil.m_pi!=null; pil=pil.m_next) 
			{
				ProdItem item = pil.m_pi;
				CSymbol s = item.Next();
				if (s==null) 
				{ // item is a reducing item
					Production rp = item.m_prod;
					if (rp.m_pno==0) // except for production 0: S'->S-|
						continue;
					// reduce item: deal with it 
					int n = rp.m_rhs.Count;
					CSymbol a;
					ParserReduce pr;
					if (n>0 && (a=(CSymbol)rp.m_rhs[n-1])!=null && a.IsAction()) 
					{
						ParserAction pa = (ParserAction)a;
						pa.m_len = n;
						pr = new ParserReduce(pa,n-1,rp);
					} 
					else 
					{
						m_sgen.m_lexer.yytext = "%"+rp.m_lhs.yytext;
						m_sgen.m_prod = rp;
						ParserSimpleAction sa = new ParserSimpleAction(m_sgen);
						sa.m_sym = (CSymbol)rp.m_lhs;
						sa.m_len = n;
						pr = new ParserReduce(sa,n,rp);
					}
					foreach (CSymbol ss in item.m_prod.m_lhs.m_follow.Keys)
						GetTransition(ss).m_reduce[rp]=pr;
				}
			}
		}
		public bool SameAs(ParseState p) 
		{
			if (m_accessingSymbol!=p.m_accessingSymbol)
				return false;
			ProdItemList pos1 = m_items;
			ProdItemList pos2 = p.m_items;
			while (!pos1.AtEnd && !pos2.AtEnd && pos1.m_pi.m_prod==pos2.m_pi.m_prod && pos1.m_pi.m_pos==pos2.m_pi.m_pos) 
			{
				pos1 = pos1.m_next;
				pos2 = pos2.m_next;
			}
			return pos1.AtEnd && pos2.AtEnd;
		}
		public ParseState CheckExists() 
		{
			Closure();
			foreach (ParseState p in m_sgen.m_symbols.m_states.Values)
				if (SameAs(p)) 
					return p;
			m_sgen.m_symbols.m_states[m_state]=this;
			AddEntries();
			return this;
		}
		~ParseState() 
		{ 
			if (m_sgen!=null && m_state==m_sgen.state-1) 
				m_sgen.state--; 
		}
		public ParseState(SymbolsGen syms,CSymbol acc) 
		{ 
			m_sgen = syms;
			m_state=syms.state++; 
			m_accessingSymbol=acc;
			m_items = new ProdItemList();
		}
		public void Print()
		{
			Console.WriteLine();
			if (m_state==0)
				Console.WriteLine("state 0");
			else
				Console.WriteLine("state {0} accessed by {1}",m_state,m_accessingSymbol.yytext);
			// first about the state itself
			if (m_items!=null)
				for (ProdItemList pil=m_items; pil.m_pi!=null; pil=pil.m_next)
				{
					pil.m_pi.Print();
					pil.m_pi.m_prod.m_lhs.m_follow.Print();
				}
			foreach (Transition t in m_transitions.Values)
				t.Print0();
		}
		public void Print0() 
		{
			Console.WriteLine();
			if (m_state==0)
				Console.WriteLine("state 0");
			else
				Console.WriteLine("state {0} accessed by {1}",m_state,m_accessingSymbol.yytext);
			// first about the state itself
			if (m_items!=null)
				for (ProdItemList pil=m_items; pil.m_pi!=null; pil=pil.m_next) 
				{
					pil.m_pi.Print();
					Console.WriteLine();
				}
			// next about the transitions
			Console.WriteLine();
			foreach (ParsingInfo pi in m_sgen.m_symbols.symbolInfo.Values)
				PrintTransition(pi);
		}
		void PrintTransition(ParsingInfo pi)
		{
			ParserEntry pe = (ParserEntry)pi.m_parsetable[m_state];
			if (pe!=null) 
			{
				Console.Write("        {0}  {1}  ", pi.m_name,pe.str);
				if (pe.m_action!=null)
					pe.m_action.Print();
				Console.WriteLine();
			}
		}
#endif
		ParseState() {}
		public static object Serialise(object o, Serialiser s)
		{
			if (s==null)
				return new ParseState();
			ParseState p = (ParseState)o;
			if (s.Encode)
			{
				s.Serialise(p.m_state);
				s.Serialise(p.m_accessingSymbol);
				s.Serialise(p.m_changed);
				return true;
			}
			p.m_state = (int)s.Deserialise();
			p.m_accessingSymbol = (CSymbol)s.Deserialise();
			p.m_changed = (bool)s.Deserialise();
			return p;
		}
	}

	internal class  ParseStackEntry
	{
		public Parser yyps;
		public int m_state;
		public SYMBOL m_value;
		public ParseStackEntry(Parser yyp) {yyps = yyp; }
		public ParseStackEntry(Parser yyp,int state,SYMBOL value) 
		{
			yyps = yyp; m_state = state; m_value = value;
		}
	}

	internal class  ParsingInfo
	{
		public string m_name;
		public int m_yynum;   // 
		public Hashtable m_parsetable = new Hashtable(); // state:int -> ParserEntry
		public ParsingInfo(string name,int num) 
		{ 
			m_name = name;
			m_yynum = num; 
		}
		ParsingInfo() {}
		public static object Serialise(object o,Serialiser s)
		{
			if (s==null)
				return new ParsingInfo();
			ParsingInfo p = (ParsingInfo)o;
			if (s.Encode) 
			{
				s.Serialise(p.m_name);
				s.Serialise(p.m_yynum);
				s.Serialise(p.m_parsetable);
				return null;
			}
			p.m_name = (string)s.Deserialise();
			p.m_yynum = (int)s.Deserialise();
			p.m_parsetable = (Hashtable)s.Deserialise();
			return p;
		}
	}

#if (GENTIME)
	internal class  SymbolSet
	{
		public SymbolsGen m_symbols;
		public SymbolSet m_next;
		Hashtable m_set = new Hashtable(); // CSymbol -> bool
		public SymbolSet(SymbolsGen syms) { m_symbols = syms; }
		public SymbolSet(SymbolSet s):this(s.m_symbols) { Add(s); }
		public bool Contains(CSymbol a) { return m_set.Contains(a); }
		public ICollection Keys { get { return m_set.Keys; } }
		public IDictionaryEnumerator GetEnumerator() { return m_set.GetEnumerator(); }
		public int Count { get { return m_set.Count; }}
		public bool CheckIn(CSymbol a) 
		{
			if (Contains(a))
				return false;
			AddIn(a);
			return true;
		}
		public SymbolSet Resolve() 
		{
			return find(m_symbols.lahead);
		}
		SymbolSet find(SymbolSet h) 
		{
			if (h==null) 
			{
				m_next = m_symbols.lahead;
				m_symbols.lahead = this;
				return this;
			}
			if (Equals(h,this))
				return h;
			return find(h.m_next);
		}
		static bool Equals(SymbolSet s,SymbolSet t) 
		{
			if (s.m_set.Count!=t.m_set.Count)
				return false;
			IDictionaryEnumerator de = s.GetEnumerator();
			IDictionaryEnumerator ee = t.GetEnumerator();
			for (int pos=0; pos<s.Count; pos++) 
			{
				de.MoveNext(); ee.MoveNext();
				if (de.Key != ee.Key)
					return false;
			}
			return true;
		}
		public void AddIn (CSymbol t) 
		{
			m_set[t] = true;
		}
		public void Add (SymbolSet s) 
		{
			if (s==this)
				return;
			foreach (CSymbol k in s.Keys)
				AddIn(k);
		}
		public static SymbolSet operator+ (SymbolSet s,SymbolSet t) 
		{
			SymbolSet r = new SymbolSet(s);
			r.Add(t);
			return r.Resolve();
		}
		public void Print() 
		{
			string pr = "[";
			int pos = 0;
			foreach (CSymbol s in Keys)
			{
				pos++;
				if (s.yytext.Equals("\n"))
					pr += "\\n";
				else
					pr += s.yytext;
				if (pos<Count)
					pr += ",";
			}
			pr += "]";
			Console.WriteLine(pr);
		}
	}

	internal class  Path 
	{
		public bool valid = true;
		ParseState[] m_states;
		public Path(ParseState[] s) { m_states = s; }
		public Path(ParseState q,CSymbol[] x) 
		{
			m_states = new ParseState[x.Length+1];
			ParseState c;
			c = m_states[0] = q;
			for (int j=0;j<x.Length;j++)
			{
				int k;
				for (k=j;k<x.Length;k++)
					if (!x[k].IsAction())
						break;
				if (k>=x.Length)
				{
					m_states[j+1] = c;
					continue;
				}
				Transition t = (Transition)c.m_transitions[x[k].yytext];
				if (t==null || t.m_next==null)
				{
					valid = false;
					break;
				}
				c = m_states[j+1] = t.m_next.m_next;
			}
		}
		public Path(CSymbol[] x) : this((ParseState)(x[0].m_parser.m_symbols.m_states[0]),x) {}
		public CSymbol[] Spelling 
		{
			get 
			{
				CSymbol[] r = new CSymbol[m_states.Length-1];
				for (int j=0;j<r.Length;j++)
					r[j] = m_states[j].m_accessingSymbol;
				return r;
			}
		}
		public ParseState Top 
		{
			get 
			{
				return m_states[m_states.Length-1];
			}
		}
	}

	internal class  Precedence
	{
		public enum PrecType { left, right, nonassoc, before, after };
		public PrecType m_type;
		public int m_prec;
		public Precedence m_next;
		public Precedence(PrecType t,int p,Precedence next) 
		{
			if (CheckType(next,t,0)!=0)
				Console.WriteLine("redeclaration of precedence");
			m_next = next; m_type = t; m_prec = p;
		}
		static int CheckType(Precedence p,PrecType t, int d) 
		{
			if (p==null) 
				return 0;
			if (p.m_type==t || (p.m_type<=PrecType.nonassoc && t<=PrecType.nonassoc))
				return p.m_prec;
			return Check(p.m_next,t, d+1);
		}
		public static int Check(Precedence p,PrecType t,int d) 
		{
			if (p==null)
				return 0;
			if (p.m_type==t)
				return p.m_prec;
			return Check(p.m_next,t,d+1);
		}
		public static int Check(CSymbol s, Production p, int d) 
		{
			if (s.m_prec==null)
				return 0;
			int a = CheckType(s.m_prec, PrecType.after,d+1);
			int b = CheckType(s.m_prec, PrecType.left,d+1);
			if (a>b)
				return a - p.m_prec;
			else
				return b - p.m_prec;
		}
		public static void Check(Production p) 
		{
			int efflen = p.m_rhs.Count;
			while (efflen>1 && ((CSymbol)p.m_rhs[efflen-1]).IsAction())
				efflen--;
			if (efflen==3) 
			{
				CSymbol op = (CSymbol)p.m_rhs[1];
				int b = CheckType(op.m_prec, PrecType.left, 0);
				if (b!=0 && ((CSymbol)p.m_rhs[2])==p.m_lhs) 
				 // allow operators such as E : V = E here
					p.m_prec = b;
			} 
			else if (efflen==2) 
			{
				if ((CSymbol)p.m_rhs[0]==p.m_lhs) 
				{
					int aft = Check(((CSymbol)p.m_rhs[1]).m_prec, PrecType.after,0);
					if (aft!=0)
						p.m_prec = aft;
				} 
				else if ((CSymbol)p.m_rhs[1]==p.m_lhs) 
				{
					int bef = Check(((CSymbol)p.m_rhs[0]).m_prec, PrecType.before,0);
					if (bef!=0)
						p.m_prec = bef;
				}
			}
		}
	}
#endif
	internal class  CSymbol : TOKEN // may be terminal (symbolic or literal), non-terminal or ParserAction
	{
		// because of forward declarations etc, a named symbol can appear in the rhs of a production
		// without us knowing if it is a terminal or a nonterminal
		// if something is a node, or an OldAction, we will know at once
		public enum SymType { unknown, terminal, nonterminal, nodesymbol, oldaction, simpleaction, eofsymbol }
		public SymType m_symtype;
		public override bool IsTerminal() 
		{ 
			return m_symtype==SymType.terminal; 
		}
		public CSymbol(Lexer yyl):base(yyl) {}
		public int m_yynum = -1;
#if (GENTIME)
		public SymbolsGen m_parser;
		// this list accumulates information about classes defined in the parser script
		// so that the relevant parts of the generated file can be written out afterwards
		public virtual CSymbol Resolve() 
		{
			if (yytext=="EOF")
				m_yynum = 2;
			CSymbol s = (CSymbol)m_parser.m_symbols.symbols[yytext];
			if (s!=null)
				return s;
			if (m_yynum<0)
				m_yynum = ++m_parser.LastSymbol;
			m_parser.m_symbols.symbols[yytext] = this;
			return this;
		}
		public CSymbol(SymbolsGen yyp) : base(yyp.m_lexer) 
		{ 
			m_parser = yyp;
			m_symtype = SymType.unknown; 
			m_prec = null;
			m_prod = null; 
			m_refSymbol = null;
			m_first = new SymbolSet(yyp);
			m_follow = new SymbolSet(yyp);
		}
		public override bool Matches(string s) { return false; }

		internal ParseState Next(ParseState p) 
		{
			if (!p.m_transitions.Contains(yytext))
				return null;
			ParserShift ps = ((Transition)p.m_transitions[yytext]).m_next;
			if (ps==null)
				return null;
			return ps.m_next;
		}
		internal Hashtable Reduce(ParseState p) // Objectlist of ParserReduce to distinct productions
		{
			if (!p.m_transitions.Contains(yytext))
				return null;
			return ((Transition)p.m_transitions[yytext]).m_reduce;
		}
		// for adding typecasts to $n
		public virtual string TypeStr() { return yytext; }

		// for terminals
		public Precedence m_prec;
		public Precedence.PrecType ShiftPrecedence(Production prod,ParseState ps) // 4.5h
		{
			if (prod==null) // no reduce available
				return Precedence.PrecType.left; // shift // 4.5h
			if (!((SymbolSet)prod.m_lhs.m_follow).Contains(this)) // if this is not a follow symbol of the prod's lhs, there is no conflict
				return Precedence.PrecType.left; // shift  // 4.5h
			if (m_prec==null) 
			{ // no precedence information
				Console.WriteLine("Shift/Reduce conflict {0} on reduction {1} in state {2}", yytext, prod.m_pno,ps.m_state);
				return Precedence.PrecType.left; // shift anyway // 4.5h
			}
			if (m_prec.m_type==Precedence.PrecType.nonassoc) // 4.5h
				return Precedence.PrecType.nonassoc; // 4.5h
			int p = Precedence.Check(this,prod,0);
			if (p==0) 
			{
				if (Precedence.Check(m_prec,Precedence.PrecType.right,0)!=0) 
				{ // equal precedence but right associative: shift
					return Precedence.PrecType.left; // 4.5h
				}
				return Precedence.PrecType.right; // don't shift // 4.5h
			}
			return (p>0)?Precedence.PrecType.left:Precedence.PrecType.right; // shift if symbol has higher precedence than production, else reduce // 4.5h
		}
		// for non-terminals
		public SymbolSet m_first; 
		public SymbolSet m_follow; // for LR(0) phase: allow EOFSymbol
		public bool AddFollow(SymbolSet map) 
		{ // CSymbol->bool : add contents of map to m_follow
			bool r = false;
			foreach(CSymbol a in map.Keys)
				r |= m_follow.CheckIn(a);
			return r;
		}
		public ObjectList m_prods = new ObjectList(); // Production:  productions with this symbol as left side
		public void AddStartItems(ParseState pstate,SymbolSet follows) 
		{ 
			for (int pos=0;pos<m_prods.Count;pos++)	
			{
				Production p = (Production)m_prods[pos];
				pstate.MaybeAdd(new ProdItem(p, 0));
			}
		}
		object isNullable = null; // used to cache the value of IsNullable
		public bool IsNullable() // suggested by Wayne Kelly
		{
			if (isNullable == null) // if not already computed
				switch (m_symtype)
				{
					case CSymbol.SymType.simpleaction: isNullable = true; break;
					case CSymbol.SymType.oldaction: isNullable = true; break;
					case CSymbol.SymType.terminal: isNullable = false; break;
					case CSymbol.SymType.eofsymbol: isNullable = false; break;
					case CSymbol.SymType.nonterminal: 
						isNullable = false; 
						foreach ( Production p in m_prods)
						{
							bool nullable = true;
							foreach ( CSymbol rhs in p.m_rhs)
								if (!rhs.IsNullable())
								{
									nullable = false;
									break;
								}
							if (nullable)
							{
								isNullable = true;
								break;
							}
						}
						break;
					default: throw new Exception( "unexpected symbol type");
				}
		    return ( bool) isNullable;
		}
		// for nodesymbols
		public CSymbol m_refSymbol;  // maybe null

		// class definition info
		public string m_initialisation=""; // may be empty
		public bool m_defined = false;
		public bool m_emitted = false;  
		public Production m_prod;  // production where this initialisation occurs: maybe null
#endif
		protected CSymbol() {}
		public static object Serialise(object o,Serialiser s)
		{
			if (s==null)
				return new CSymbol();
			CSymbol c = (CSymbol)o;
			if (s.Encode)
			{
				s.Serialise(c.yytext);
				s.Serialise(c.m_yynum);
				s.Serialise((int)c.m_symtype);
				return null;
			}
			c.yytext = (string)s.Deserialise();
			c.m_yynum = (int)s.Deserialise();
			c.m_symtype = (SymType)s.Deserialise();
			return c;
		}

	}

	// [Serializable] 
	internal class  Literal : CSymbol  // used for %TOKEN in LexerGenerator script and quoted strings
	{
#if (GENTIME)
		public Literal(SymbolsGen yyp) : base(yyp) { m_symtype=SymType.terminal; }
		public override CSymbol Resolve() 
		{ // to the first occurrence
			int n = yytext.Length;
			string ns ="";
			for (int p=1;p+1<n;p++) // fix \ escapes
				if (yytext[p] == '\\') 
				{
					if (p+1<n)
						p++;
					if (yytext[p]>='0' && yytext[p]<='7') 
					{
						int v;
						for (v = yytext[p++]-'0';p<n && yytext[p]>='0' && yytext[p]<='7';p++)
							v=v*8+yytext[p]-'0';
						ns += (char)v;
					} 
					else
						switch(yytext[p]) 
						{
							case 'n' : ns += '\n'; break;
							case 't' : ns += '\t'; break;
							case 'r' : ns += '\r'; break;
							default:   ns += yytext[p]; break;
						}
				} 
				else
					ns += yytext[p];
			yytext = ns;
			CSymbol ob = (CSymbol)m_parser.m_symbols.literals[yytext];
			if (ob!=null)
				return ob;
			m_yynum = ++m_parser.LastSymbol;
			m_parser.m_symbols.literals[yytext] = this;
			m_parser.m_symbols.symbolInfo[m_yynum] = new ParsingInfo(yytext,m_yynum);
			return this;
		}
		public bool CouldStart(CSymbol nonterm) { return false; }
		public override string TypeStr() { return "TOKEN"; }
#endif
		Literal() {}
		public new static object Serialise(object o,Serialiser s)
		{
			if (s==null)
				return new Literal();
			return CSymbol.Serialise(o,s);
		}
	}

	internal class  Production
	{
		public int m_pno;
#if (GENTIME)
		public CSymbol m_lhs;
		public bool m_actionsOnly;
		public int m_prec; 
		public Production(SymbolsGen syms) 
		{
			m_lhs=null; 
			m_prec=0; 
			m_pno=syms.pno++; 
			m_actionsOnly = true; 
			syms.prods.Add(this);
		}
		public Production(SymbolsGen syms,CSymbol lhs) 
		{
			m_lhs=lhs; 
			m_prec=0;  
			m_pno=syms.pno++;
			m_actionsOnly=true;
			syms.prods.Add(this);
			lhs.m_prods.Add(this);
		}
		public ObjectList m_rhs = new ObjectList(); // CSymbol
		public Hashtable m_alias = new Hashtable(); // string->int
		public void AddToRhs(CSymbol s) 
		{
			m_rhs.Add(s);
			m_actionsOnly = m_actionsOnly && s.IsAction();
		}
		public void AddFirst(CSymbol s, int j) 
		{ 
			for (;j<m_rhs.Count;j++) 
			{
				CSymbol r = (CSymbol)m_rhs[j];
				s.AddFollow(r.m_first);
				if (!r.IsNullable())
					return;
			}
		}
		public bool CouldBeEmpty(int j) 
		{
			for (;j<m_rhs.Count;j++) 
			{
				CSymbol r = (CSymbol)m_rhs[j];
				if (!r.IsNullable())
					return false;
			}
			return true;
		}
		public CSymbol[] Prefix(int i)
		{
			CSymbol[] r = new CSymbol[i];
			for (int j=0;j<i;j++)
				r[j] = (CSymbol)m_rhs[j];
			return r;
		}

		// inside ACTIONs, $N translates to ((SomeSymbol *)(parser.StackAt(K-N-1).m_value))
		// where K is the position of the action in the production

		public void StackRef(ref string str,int ch, int ix) 
		{
			int ln = m_rhs.Count+1;
			CSymbol ts = (CSymbol)m_rhs[ix-1];
			str += String.Format("\n\t(({0})(yyq.StackAt({1}).m_value))\n\t",ts.TypeStr(),ln-ix-1);
		}
#endif
		Production() {}
		public static object Serialise(object o,Serialiser s)
		{
			if (s==null)
				return new Production();
			Production p = (Production)o;
			if (s.Encode) 
			{
				s.Serialise(p.m_pno);
				return null;
			}
			p.m_pno = (int)s.Deserialise();
			return p;
		}
	}
#if (GENTIME)
	internal class  ProdItem
	{
		public ProdItem(Production prod, int pos) 
		{
			m_prod=prod; 
			m_pos=pos; 
			m_done=false; 
		}
		public ProdItem() 
		{ 
			m_prod = null; 
			m_pos = 0; 
			m_done=false; 
		}
		public Production m_prod;
		public int m_pos;
		public bool m_done;
		public CSymbol Next() 
		{
			if (m_pos<m_prod.m_rhs.Count)
				return (CSymbol)m_prod.m_rhs[m_pos];
			return null;

		}
		public bool IsReducingAction() 
		{ 
			return (m_pos==m_prod.m_rhs.Count-1) && Next().IsAction();
		}
		SymbolSet follow = null;
		public SymbolSet FirstOfRest(SymbolsGen syms) 
		{
			if (follow!=null)
				return follow;
			follow = new SymbolSet(syms); 
			bool broke=false;
			int n = m_prod.m_rhs.Count;
			for (int j=m_pos+1;j<n;j++) 
			{
				CSymbol s = (CSymbol)m_prod.m_rhs[j];
				foreach (CSymbol a in s.m_first.Keys)
						follow.CheckIn(a);
				if (!s.IsNullable()) 
				{
					broke = true;
					break;
				}
			}
			if (!broke) 
				follow.Add(m_prod.m_lhs.m_follow);
			follow = follow.Resolve();
			return follow;
		}
		public void Print() 
		{
			int j;
			string str,s;

			if (m_prod.m_lhs!=null)
				str = m_prod.m_lhs.yytext;
			else
				str = "$start";
			Console.Write("   {0}    {1} : ", m_prod.m_pno, str);
			for (j = 0;j<m_prod.m_rhs.Count;j++) 
			{
				if (j == m_pos)
					Console.Write("_");
				else
					Console.Write(" ");
				s =((CSymbol)m_prod.m_rhs[j]).yytext;
				if (s.Equals("\n"))
					s = "\\n";
				Console.Write(s);
			}
			if (j==m_pos)
				Console.Write("_");
			Console.Write("  ");
		}
	}

	internal class  ProdItemList
	{
		public ProdItem m_pi;
		public ProdItemList m_next;
		public ProdItemList (ProdItem pi,ProdItemList n) { m_pi=pi; m_next=n; }
		public ProdItemList() { m_pi=null; m_next=null; } // sentinel only
		public bool Add(ProdItem pi) 
		{
			if (m_pi==null) 
			{  // m_pi==null iff m_next==null
				m_next = new ProdItemList();
				m_pi = pi; 
			} 
			else if (m_pi.m_prod.m_pno < pi.m_prod.m_pno ||
				(m_pi.m_prod.m_pno==pi.m_prod.m_pno && m_pi.m_pos<pi.m_pos)) 
			{
				m_next = new ProdItemList(m_pi,m_next);
				m_pi = pi;
			} 
			else if (m_pi.m_prod.m_pno == pi.m_prod.m_pno && m_pi.m_pos==pi.m_pos) 
				return false;
			else
				return m_next.Add(pi);
			return true; // was added
		}
		public bool AtEnd { get { return m_pi==null; } }

	}
#endif
	internal class  Parser
	{
		public YyParser m_symbols;
		public bool m_debug;
		public bool m_stkdebug=false;
		public Parser(YyParser syms,Lexer lexer) 
		{
			m_lexer = lexer;
			m_symbols = syms;
			m_symbols.erh = m_lexer.tokens.erh;
		}
		public Lexer m_lexer;
		internal ObjectList m_stack = new ObjectList(); // ParseStackEntry
		internal SYMBOL m_ungot;

		void Create() 
		{
			m_symbols.GetParser(m_lexer);
		}

		protected bool Error(ref ParseStackEntry top, string str) 
		{
			SYMBOL er = (SYMBOL)new error(this,top);  // 4.4c
			if (m_debug)
				Console.WriteLine("Error encountered: "+str);
			er.pos = top.m_value.pos;
			ParserEntry pe;
			if (m_symbols.symbolInfo[0]!=null && m_symbols.erh.counter<1000) // 4.4c
			// first pop the stack until we find an item that can pass error
			for (;top!=null && m_stack.Count>0; Pop(ref top,1,er)) 
			{
				if (m_debug)
					Console.WriteLine("Error recovery uncovers state {0}",top.m_state);
				if (er.Pass(m_symbols,top.m_state, out pe)) 
				{
					SYMBOL oldtop = top.m_value; 
					top.m_value = er;  
					pe.Pass(ref top); // pass the error symbol
					// now discard tokens until we find one we can pass
					while (top.m_value!=m_symbols.EOFSymbol && !top.m_value.Pass(m_symbols,top.m_state, out pe)) 
					{
						SYMBOL newtop;
						if (pe!=null && pe.IsReduce()) 
						{
							newtop = null;
							if (pe.m_action!=null)
								newtop = pe.m_action.Action(this); // before we change the stack
							m_ungot = top.m_value;
							Pop(ref top,((ParserReduce)pe).m_depth,er);
							newtop.pos = top.m_value.pos;
							top.m_value = newtop;
						} 
						else 
						{ // discard it
							string cnm = top.m_value.yyname;
							if (m_debug) 
							{
								if (cnm=="TOKEN")
									Console.WriteLine("Error recovery discards literal {0}",(string)((TOKEN)top.m_value).yytext);
								else
									Console.WriteLine("Error recovery discards token {0}",cnm);
							}
							top.m_value = NextSym();
						}
					}
					if (m_debug)
						Console.WriteLine("Recovery complete");
					m_symbols.erh.counter++;
					return true;
				}
			}
			m_symbols.erh.Error(new CSToolsException(13,m_lexer,er.pos,"syntax error",str)); 
			top.m_value = er;
			return false;
		}

		public SYMBOL Parse(StreamReader input) 
		{
			m_lexer.Start(input);
			return Parse();
		}
		public SYMBOL Parse(CsReader inFile) 
		{
			m_lexer.Start(inFile);
			return Parse();
		}
		public SYMBOL Parse(string buf) 
		{ 
			m_lexer.Start(buf);
			return Parse();
		}
		// The Parsing Algorithm
		SYMBOL Parse() 
		{
			ParserEntry pe;
			SYMBOL newtop;
			Create();
			ParseStackEntry top = new ParseStackEntry(this,0,NextSym()); 
			try 
			{
				for (;;) 
				{
					string cnm = top.m_value.yyname; 
					if (m_debug) 
					{
						if (cnm.Equals("TOKEN"))
							Console.WriteLine(String.Format("State {0} with {1} \"{2}\"", top.m_state, cnm,((TOKEN)top.m_value).yytext));
						else
							Console.WriteLine(String.Format("State {0} with {1}", top.m_state, cnm));
					}
					if (top.m_value!=null && top.m_value.Pass(m_symbols,top.m_state, out pe))
						pe.Pass(ref top);
					else if (top.m_value==m_symbols.EOFSymbol) 
					{
						if (top.m_state==m_symbols.m_accept.m_state) 
						{ // successful parse
							Pop(ref top,1,m_symbols.m_startSymbol);
							if (m_symbols.erh.counter>0)
								return new recoveredError(this,top);
							newtop = top.m_value; // extract the return value
							top.m_value = null;
							return newtop;
						}
						if (!Error(ref top,"Unexpected EOF")) // unrecovered error
							return top.m_value;
					} 
					else if (!Error(ref top,"syntax error")) // unrecovered error
						return top.m_value;
					if (m_debug) 
					{
						object ob = null;
						if (top.m_value!=null) 
						{
							ob = top.m_value.m_dollar;
							Console.WriteLine("In state {0} top {1} value {2}",top.m_state,top.m_value.yyname,(ob==null)?"null":ob.GetType().Name);
							if (ob!=null && ob.GetType().Name.Equals("Int32"))
								Console.WriteLine((int)ob);
							else 
								((SYMBOL)(top.m_value)).Print();
						} 
						else 
							Console.WriteLine("In state {0} top NULL",top.m_state);
					}
				}
				// not reached
			} 
			catch(CSToolsStopException ex) // stop parsing
			{
				if (m_symbols.erh.throwExceptions)
					throw ex;						// 4.5b
				m_symbols.erh.Report(ex);			// 4.5b
			}
			return null;
		}
		internal void Push(ParseStackEntry elt) 
		{
			m_stack.Push(elt);
		}
		internal void Pop(ref ParseStackEntry elt, int depth, SYMBOL ns) 
		{
			for (;m_stack.Count>0 && depth>0;depth--) 
			{
				elt = (ParseStackEntry)m_stack.Pop();
				if (m_symbols.m_concrete) // building the concrete syntax tree
					ns.kids.Push(elt.m_value); // else will be garbage collected
			}
			if (depth!=0) 
				m_symbols.erh.Error(new CSToolsException(14,m_lexer,"Pop failed"));
		}
		public ParseStackEntry StackAt(int ix) 
		{
			int n = m_stack.Count;
			if (m_stkdebug)
				Console.WriteLine("StackAt({0}),count {1}",ix,n);
			ParseStackEntry pe =(ParseStackEntry)m_stack[ix];
			if (pe == null)
				return new ParseStackEntry(this,0,m_symbols.Special);
			if (pe.m_value is Null)
				return new ParseStackEntry(this,pe.m_state,null);
			if (m_stkdebug)
				Console.WriteLine(pe.m_value.yyname);
			return pe;
		}
		public SYMBOL NextSym() 
		{ // like lexer.Next but allows a one-token pushback for reduce
			SYMBOL ret = m_ungot;
			if (ret != null) 
			{
				m_ungot = null;
				return ret;
			}
			ret = (SYMBOL)m_lexer.Next();
			if (ret==null) 
				ret = m_symbols.EOFSymbol;
			return ret;
		}
		public void Error(int n,SYMBOL sym, string s) 
		{
			if (sym!=null)
				m_symbols.erh.Error(new CSToolsException(n,sym.yylx,sym.pos,"",s)); // 4.5b
			else
				m_symbols.erh.Error(new CSToolsException(n,s));
		}
	}

	internal class  error : SYMBOL
	{
		public int state = 0; 
		public SYMBOL sym = null; 
		public error(Parser yyp,ParseStackEntry s):base(yyp) { state=s.m_state; sym=s.m_value; } //4.4c
		public error(Parser yyp):base(yyp) {}
		public override string yyname { get { return "error"; }}
		public override string ToString() 
		{
			string r = "syntax error occurred in state "+state;
			if (sym==null)
				return r;
			if (sym is TOKEN) 
			{
				TOKEN t = (TOKEN)sym;
				return  r+" on input token "+t.yytext;
			}
			return r+" on symbol "+sym.yyname;
		}
	}

	internal class  recoveredError : error
	{
		public recoveredError(Parser yyp,ParseStackEntry s):base(yyp,s) {}
		public override string ToString() 
		{
			return "Parse contained "+yyps.m_symbols.erh.counter+" errors";
		}
		public override void ConcreteSyntaxTree()
		{
			Console.WriteLine(ToString());
			if (sym!=null)
				sym.ConcreteSyntaxTree();
		}
		public override void Print()
		{
			Console.WriteLine(ToString());
			if (sym!=null)
				sym.Print();
		}
	}

	internal class  EOF : CSymbol
	{
#if (GENTIME)
		public EOF(SymbolsGen yyp):base(yyp) { yytext = "EOF"; m_yynum = 2; m_symtype = SymType.eofsymbol; }
#endif
		public EOF(Lexer yyl):base(yyl) { 
			yytext = "EOF"; 
			pos = yyl.m_LineManager.end; // 4.5b
			m_symtype = SymType.eofsymbol; 
		}
		EOF() {}
		public override string yyname { get { return "EOF"; }}
		public override int yynum { get { return 2; }}
		public new static object Serialise(object o,Serialiser s)
		{
			if (s==null)
				return new EOF();
			return CSymbol.Serialise(o,s);
		}
	}

	internal class  Null : TOKEN  // fake up something that will evaluate to null but have the right yyname
	{
		public Null(Lexer yyl,string proxy):base(yyl) { yytext=proxy; }
		public Null(Parser yyp,string proxy):base(yyp) { yytext=proxy; }
		public override string yyname { get { return yytext; }}
	}
	// Support for runtime object creation

	internal delegate object SCreator(Parser yyp);

	internal class  Sfactory
	{
		public static object create(string cls_name,Parser yyp) 
		{
			SCreator cr = (SCreator)yyp.m_symbols.types[cls_name];
			// Console.WriteLine("TCreating {0} <{1}>",cls_name,yyl.yytext);
			if (cr==null) 
				yyp.m_symbols.erh.Error(new CSToolsException(16,yyp.m_lexer,"no factory for {"+cls_name+")"));
			try 
			{
				return cr(yyp);
			}
			catch (CSToolsException e)
			{
				yyp.m_symbols.erh.Error(e);
			}
			catch (Exception e) 
			{
				yyp.m_symbols.erh.Error(new CSToolsException(17,yyp.m_lexer,string.Format("Create of {0} failed ({1})",cls_name,e.Message)));
			}
			int j = cls_name.LastIndexOf('_');
			if (j>0) 
			{
				cr = (SCreator)yyp.m_symbols.types[cls_name.Substring(0,j)];
				if (cr!=null) 
				{
					SYMBOL s = (SYMBOL)cr(yyp);
					s.m_dollar = 0;
					return s;
				}
			}
			return null;
		}
		public Sfactory(YyParser syms,string cls_name,SCreator cr) 
		{
			syms.types[cls_name] = cr;
		}
	}

}



By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Architect
Netherlands Netherlands
Please visit my website for more articles

I'm software developer & Ph.D. student

Comments and Discussions