/*
 * Bernoulli Compiler
 * Copyright (c) Cornell University
 * Department of Computer Science
 * 
 * Kamen Yotov (kamen@yotov.org)
 * 
 * $Source: C:/CVS/kyotov/kyotov/Research/BC/Core/Grammars/Grammar.cs,v $
 * $Revision: 1.6 $
 * $Date: 2002/12/05 03:07:54 $
 */

using System;
using System.Collections;
using System.Diagnostics;

using XTensions.Collections;

namespace BC.Core
{
	namespace Grammars
	{
		using Symbols;
		using Reductions;

		public class Grammar
		{
			protected Hashtable p;
			protected NonTerminal x;

			public Grammar()
			{
				p = new Hashtable();
				x = N("S");
			}

			public ICollection NonTerminals
			{
				get
				{
					return p.Keys;
				}
			}

			public NonTerminal S
			{
				get
				{
					return x;
				}
				set
				{
					x = value;
				}
			}

			protected void ProcessAlternatives (Sequence a, Reduction ar, int i, Sequence c, int ci, int[] x, ref Alternatives r)
			{
				if (a.Count == 0)
				{
					if (ar != null)
						r |= c + X(ar, (int[])x.Clone());
					else
						r |= c;
				}
				else
				{
					if (a[0] is PhysicalSymbol)
					{
						x[i] = ci;

						ProcessAlternatives(a.Tail(1), ar, i + 1, c + a[0], ci + 1, x, ref r);
					}
					else
					{
						Debug.Assert(a[0] is VirtualSymbol);

						Sequence q = ((VirtualSymbol)a[0]).Sequence;

						ProcessAlternatives(q + a.Tail(1), ar, i, c, ci, x, ref r);

						for (int l = 0; l < q.Count; l++)
							x[i + l] = -1;

						ProcessAlternatives(a.Tail(1), ar, i + q.Count, c, ci, x, ref r);
					}
				}
			}

			public Alternatives this [NonTerminal s]
			{
				get
				{
					return (Alternatives)p[s];
				}
				set
				{
					Alternatives r = new Alternatives();

					foreach (Alternative a in value)
					{
						if (a.Reduction == null)
							//Console.WriteLine("Warning: Production {0} has no associated reduction!", new Production(s, a));
							Console.WriteLine("Warning: A production for {0} has no associated reduction!", s);

						ProcessAlternatives(a.Sequence, a.Reduction, 0, new Sequence(), 0, new int[a.Sequence.DeepCount], ref r);
					}

					p[s] = r;
				}
			}

			public void MakeList(NonTerminal s, NonTerminal e)
			{
				this[s]
					= e + Common.RCreateList
					| s + e + Common.RAddToList;
			}

			public Hashtable NonTerminalDictionary
			{
				get
				{
					Hashtable m = new Hashtable();

					int i = 0;

					foreach (NonTerminal n in NonTerminals)
						m[n] = i++;

					return m;
				}
			}

			public static Terminal T (string s)
			{
				return new Terminal(s);
			}

			public static NonTerminal N (string s)
			{
				return new NonTerminal(s);
			}

			protected static Alternative e = new Alternative();
			protected static EndOfFile eof = new EndOfFile();

			public static Alternative E
			{
				get
				{
					return e;
				}
			}

			public static EndOfFile EOF
			{
				get
				{
					return eof;
				}
			}

			public static Reduction X (Reduction r, params int[] x)
			{
				Translation t = new Translation(r, x);

				return new Reduction(t.Execute);
			}

			public static VirtualSymbol O (Sequence s)
			{
				return new VirtualSymbol(s);
			}
		}
	}
}