/*
 * Bernoulli Compiler
 * Copyright (c) Cornell University
 * Department of Computer Science
 * 
 * Kamen Yotov (kamen@yotov.org)
 * 
 * $Source: C:/CVS/kyotov/kyotov/Research/BC/X/BC.cs,v $
 * $Revision: 1.5 $
 * $Date: 2002/10/22 19:50:41 $
 */

using System;
using System.Collections;
using System.Xml;

using XTensions.Collections;

using BC.Core.Exceptions;
using BC.Core.Lexers;
using BC.Core.Grammars;
using BC.Core.Grammars.Symbols;
using BC.Core.Grammars.Reductions;
using BC.Core.Automatas;
using BC.Core.Parsers;

namespace BC.X
{
	sealed class ELexer: Lexer
	{
		protected override void Configure ()
		{
			this[_X.T_number] = @"[0-9]+";
			this[_X.T_variable] = @"[a-z]+";
			this[_X.TO_add] = @"\+";
			this[_X.TO_multiply] = @"\*";
			this[_X.TP_left] = @"\(";
			this[_X.TP_right] = @"\)";
			this[WhiteSpace] = @"[ \t\v\r\n]+";
		}
	}

	sealed class EGrammar: Grammar
	{
		private XmlDocument d = new XmlDocument();

		private XmlElement c (object o)
		{
			if (o is Terminal)
			{
				XmlElement e = d.CreateElement("item");
				
				e.Attributes.Append(d.CreateAttribute("value"));
				e.Attributes["value"].Value = (o as Terminal).Value;

				return e;
			}
			else
				return (XmlElement)o;
		}

		private XmlNode o (XmlElement o)
		{
			if (o.ChildNodes.Count == 1)
				return o.FirstChild;
			else
				return o;
		}

		private object _S (object[] a)
		{
			d.AppendChild(o(c(a[0])));

			return d;
		}

		private object _X1 (object[] a)
		{
			XmlElement e = c(a[0]);

			e.AppendChild(o(c(a[2])));

			return e;
		}

		private object _X2 (object[] a)
		{
			XmlElement e = d.CreateElement("add");

			e.AppendChild(o(c(a[0])));

			return e;
		}

		private object _A1 (object[] a)
		{
			XmlElement e = c(a[0]);

			e.AppendChild(c(a[2]));

			return e;
		}

		private object _A2 (object[] a)
		{
			XmlElement e = d.CreateElement("multiply");

			e.AppendChild(c(a[0]));

			return e;
		}

		private object _F1 (object[] a)
		{
			return a[0];
		}

		private object _F2 (object[] a)
		{
			return o(c(a[1]));
		}

		public EGrammar ()
		{
			this[_X.NS]
				= _X.NX + new Reduction(_S);

			this[_X.NX]
				= _X.NX + _X.TO_add + _X.NA + new Reduction(_X1)
				| _X.NA + new Reduction(_X2);

			this[_X.NA]
				= _X.NA + _X.TO_multiply + _X.NF + new Reduction(_A1)
				| _X.NF + new Reduction(_A2);

			this[_X.NF]
				= _X.T_primitive + new Reduction(_F1)
				| _X.TP_left + _X.NX + _X.TP_right + new Reduction(_F2);
		}
	}

	class BCMain
	{
		static void Main (string[] args)
		{
			Console.WriteLine(
				"Bernoulli Compiler v0.1beta\n"	+
				"Copyright (c) 2002 Cornell University\n\n"
			);

			Lexer cl = new ELexer();

			Grammar g = new EGrammar();

			FA n = new FA(g);

			FA d = new FA(n);

			Sequence s;
			Parser p;
			XmlDocument x;

			try
			{
				s = cl.Execute(@"..\..\samples\test.exp");

				p = new Parser(g.S, d);

				x = (XmlDocument)p.Parse(s);
			}
			catch (System.Exception e)
			{
				Console.WriteLine(e);

				return;
			}

			XmlTextWriter w = new XmlTextWriter(Console.Out);
			w.Formatting = Formatting.Indented;

			x.WriteTo(w);

			Console.WriteLine();
		}
	}
}