/*
 * Bernoulli Compiler
 * Copyright (c) Cornell University
 * Department of Computer Science
 * 
 * Kamen Yotov (kamen@yotov.org)
 * Daniel Marques (marques@cs.cornell.edu)
 * 
 * $Source: C:/CVS/kyotov/kyotov/Research/BC/C/CParser.cs,v $
 * $Revision: 1.34 $
 * $Date: 2003/02/23 10:07:25 $
 */

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

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

using Machines = BC.Core.Machines;

namespace BC.C
{
	public class CParser: Pass
	{
		protected string f;
		protected Lexer l;
		protected Parser p;
		protected ICloneable cs;

		public CParser(bool v) : this(null, v)
		{
		}

		public CParser (string f, bool v)
		{
			this.f = f;

			Console.Write("Building lexer...  \r");
			l = new CLexer();
			Console.Write("Building grammar...\r");
			CGrammar g = new CGrammar(this);
			Console.Write("Building NFA...    \r");
			FA n = new FA(g);
			Console.Write("Building DFA...    \r");
			FA d = new FA(n);
			Console.Write("Building Parser... \r");
			p = new Parser(g.S, d, v);
			p.CheckSuccessSet.Add(C.N_external_declaration);
			p.CheckSuccessSet.Add(C.N_translation_unit);
		}

		public Symbols s
		{
			get
			{
				return (Symbols)cs;
			}
		}

		public override void Execute (ref Elements e, object o)
		{
			cs = new Symbols();

			if (o is string)
				f = (string)o;

			Console.Write("Parsing ({0})... ", f);
			
			e = (Elements)p.Parse(l.Execute(f), ref cs);

			Console.WriteLine(" done!");

			Console.WriteLine("  Ambiguity resolutions: {0} ({1} Syntactic + {2} Semantic)", 
				p[Statistics.Ambiguities],
				p[Statistics.SyntacticallyResolved],
				p[Statistics.SemanticallyResolved]);

		}

		static string ObjectToTerminalValue (object o)
		{
			Terminal t = (Terminal)o;

			if (t == null)
				t = C.T_identifier;

			return t.Value;
		}

		static void SetDeclaration (ref AbstractSemanticElement d, object _)
		{			
			ArrayList a = Common.ObjectToList(_);
			ArrayList s = new ArrayList();
			ArrayList t1 = new ArrayList();
			ArrayList t2 = new ArrayList();

			foreach (object i in a)
			{
				if (i is Terminal)
				{
					Terminal ti = (Terminal)i;

					if (!ti.IsA(C.T_keyword_const) &&
						!ti.IsA(C.T_keyword_volatile) &&
						!ti.IsA(C.T_keyword_restrict))
					{
						if (ti.IsA(C.T_keyword_typedef) ||
							ti.IsA(C.T_keyword_extern) ||
							ti.IsA(C.T_keyword_static) ||
							ti.IsA(C.T_keyword_auto) ||
							ti.IsA(C.T_keyword_register))
							s.Add(ti);
						else if (ti.IsA(C.T_identifier))
						{
							NamedType nt = new NamedType();

							nt.Name = ti.Value;

							t2.Add(nt);
						}
						else
							t1.Add(ti.Value);
					}
				}
				else
					t2.Add(i);
			}

			AbstractType bt1 = Definitions.ListToType(t1);
			AbstractType bt2 = t2.Count == 1 ? (AbstractType)t2[0] : null;

			if ((bt1 != null) == (bt2 != null))
				throw new BCException(ExceptionType.Semantic, CUI.Code.c99_6_7_2_2, 
					Definitions.Join(Definitions.TypeSpecifierLists, ", "));

			if (s.Count > 1)
				throw new BCException(ExceptionType.Semantic, CUI.Code.c99_6_7_1_2);

			AbstractType bt = bt1 != null ? bt1 : bt2;

			Definitions.SetQualifiers(bt, _);

			SetType(ref d.Type, bt);

			if (s.Count == 1)
			{
				Terminal t = (Terminal)s[0];

				if (t.IsA(C.T_keyword_extern))
				{
					Debug.Assert(d is AbstractLinkableElement); // ISO_ERROR

					((AbstractLinkableElement)d).Linkage = Linkage.External;

					if (d is Declaration)
						((Declaration)d).Storage = Storage.Static;
				}
				else if (t.IsA(C.T_keyword_static))
				{
					Debug.Assert(d is AbstractLinkableElement); // ISO_ERROR

					((AbstractLinkableElement)d).Linkage = Linkage.Internal;

					if (d is Declaration)
						((Declaration)d).Storage = Storage.Static;
				}
				else if (t.IsA(C.T_keyword_register))
				{
					Debug.Assert(d is Declaration); // ISO_ERROR

					if (d is Declaration)
						((Declaration)d).Storage = Storage.Register;
				}
				else if (t.IsA(C.T_keyword_typedef))
				{
					Debug.Assert(d is Declaration && 
						((Declaration)d).Value == null && 
						((Declaration)d).Linkage == Linkage.None &&
						((Declaration)d).Storage == Storage.Automatic); // ISO_ERROR

					TypeDefinition td = new TypeDefinition();

					td.Name = d.Name;
					td.Type = d.Type;

					d = td;
				}
			}
		}

		static void SetType (ref AbstractType t, AbstractType s)
		{
			if (t == null)
				t = s;
			else if (t is AbstractCompoundType)
			{
				AbstractCompoundType ct = (AbstractCompoundType)t;

				if (ct.Base == null)
					ct.Base = s;
				else
					SetType(ref ct.Base, s);
			}
			else
			{
				Debug.Assert(false, "unknown SetType argument");

				throw new Exception();
			}
		}

		static Declaration ObjectToDeclaration (object o)
		{
			if (o == null)
				return new Declaration();
			else
				return (Declaration)o;
		}

		static string CommentContent (string s)
		{
			if (s.StartsWith("/*"))
				return s.Substring(2, s.Length - 4);
			else if (s.StartsWith("//"))
				return s.Substring(2, s.Length - 3);
			else
			{
				Debug.Assert(false, "invalid comment");

				return null;
			}
		}

		public object _primary_expression_0 (object[] a)
		{
			NamedExpression e = new NamedExpression();

			e.Name = ObjectToTerminalValue(a[0]);

			if (this.s.Lookup(e.Name) == SymbolType.Type)
				throw new BCException(ExceptionType.Semantic, CUI.Code.bc_003);

			return e;
		}

		public static object _primary_expression_1 (object[] a)
		{
			Terminal t = (Terminal)a[0];

			if (t.IsA(C.T_integer))
			{
				string v = t.Value.ToLower();

				Machines.IntegerType.SignType st = 
					v.StartsWith("0") ? 
						Machines.IntegerType.SignType.stBoth :
						v.IndexOf("u") >= 0 ?
							Machines.IntegerType.SignType.stUnsigned :
							Machines.IntegerType.SignType.stSigned;

				bool ll = v.IndexOf("ll") >= 0;
				bool l = !ll && v.IndexOf("l") >= 0;

				while (v.EndsWith("u") || v.EndsWith("l"))
					v = v.Substring(0, v.Length - 1);

				Machines.IntegerType it = Machines.IntegerType.Get(v, st);

				if (it == null)
					throw new BCException(ExceptionType.Semantic, CUI.Code.bc_002);

				int p = it.Precision;

				if (ll)
					p = Definitions.IT_signed_long_long_int.Precision;
				else if (l)
					p = Definitions.IT_signed_long_int.Precision;

				it = Machines.IntegerType.Get(p, st);

				IntegerConstant e = new IntegerConstant();

				e.Precision = it.Precision;
				e.Signed = it.Signed;
				e.Value = v;

				return e;
			}
			else if (t.IsA(C.T_floating))
			{
				string v = t.Value.ToLower();

				RealConstant e = new RealConstant();

				Machines.RealType rt;

				switch (v[v.Length - 1])
				{
					case 'f': 
						rt = Definitions.RT_float;
						v = v.Substring(0, v.Length - 1);
						break;
					case 'l':
						rt = Definitions.RT_long_double;
						v = v.Substring(0, v.Length - 1);
						break;
					default:
						rt = Definitions.RT_double;
						break;
				}

				e.Value = double.Parse(v);
				e.Precision = rt.Precision;

				if (!rt.Contains(e.Value))
					throw new BCException(ExceptionType.Semantic, CUI.Code.bc_002);

				return e;
			}
			else if (t.IsA(C.T_character))
			{
				CharacterConstant e = new CharacterConstant();

				if (t.Value[0] == 'L')
				{
					e.Unicode = true;

					e.Value = t.Value.Substring(2, t.Value.Length - 3);
				}
				else
					e.Value = t.Value.Substring(1, t.Value.Length - 2);

				return e;
			}
			else if (t.IsA(C.T_string))
			{
				StringConstant e = new StringConstant();

				if (t.Value[0] == 'L')
				{
					e.Unicode = true;

					e.Value = t.Value.Substring(2, t.Value.Length - 3);
				}
				else
					e.Value = t.Value.Substring(1, t.Value.Length - 2);

				return e;
			}
			else
				throw new BCException();
		}

		public static object _postfix_expression_1 (object[] a)
		{
			ArrayExpression e = new ArrayExpression();

			e.Operand = (AbstractExpression)a[0];
			e.Index = new AbstractExpression[1];
			e.Index[0] = (AbstractExpression)a[2];

			return e;
		}

		public static object _postfix_expression_2 (object[] a)
		{
			FunctionExpression e = new FunctionExpression();

			e.Operand = (AbstractExpression)a[0];
			e.Argument = (AbstractExpression[])Common.ObjectToArray(a[2], typeof(AbstractExpression));

			return e;
		}

		public static object _postfix_expression_3 (object[] a)
		{
			FieldExpression e = new FieldExpression();

			e.Operand = (AbstractExpression)a[0];
			e.Field = ObjectToTerminalValue(a[2]);

			return e;
		}

		public static object _postfix_expression_4 (object[] a)
		{
			
			// changed by marques 2/2/03
			FieldExpression e = new FieldExpression();
			UnaryExpression ue = new UnaryExpression();
			
			ue.Operator = Operator.Dereference;
			ue.Operand = (AbstractExpression)a[0];

			e.Operand = ue;
			e.Field = ObjectToTerminalValue(a[2]);

			return e;
		}

		public static object _postfix_expression_7 (object[] a)
		{
			CompositeExpression e = new CompositeExpression();
			InitializerList l = new InitializerList();

			l.Initializer = (AbstractInitializer[])Common.ObjectToArray(a[4], typeof(AbstractInitializer));

			e.Type = (AbstractType)a[1];
			e.Operand = l;

			return e;
		}

		public static object _postfix_expression (object[] a)
		{
			UnaryExpression e = new UnaryExpression();

			e.Operand = (AbstractExpression)a[0];
			e.Operator = Definitions.TerminalToOperator(a[1]);

			return e;
		}

		public static object _unary_expression (object[] a)
		{
			UnaryExpression e = new UnaryExpression();

			e.Operator = Definitions.TerminalToUnaryOperator(a[0]);
			e.Operand = (AbstractExpression)a[1];

			return e;
		}

		public static object _sizeof_expression_0 (object[] a)
		{
			SizeOfExpression e = new SizeOfExpression();

			e.Operand = (AbstractExpression)a[1];

			return e;
		}

		public static object _sizeof_expression_1 (object[] a)
		{
			SizeOfTypeExpression e = new SizeOfTypeExpression();

			e.Operand = (AbstractType)a[2];

			return e;
		}

		public static object _cast_expression (object[] a)
		{
			CastExpression e = new CastExpression();

			e.Type = (AbstractType)a[1];
			e.Operand = (AbstractExpression)a[3];

			return e;
		}

		public static object _binary_expression (object[] a)
		{
			BinaryExpression e = new BinaryExpression();

			e.LeftOperand = (AbstractExpression)a[0];
			e.Operator = Definitions.TerminalToOperator(a[1]);


			e.RightOperand = (AbstractExpression)a[2];

			return e;
		}

		public static object _trinary_expression (object[] a)
		{
			TrinaryExpression e = new TrinaryExpression();

			e.Condition = (AbstractExpression)a[0];
			e.TrueResult = (AbstractExpression)a[2];
			e.FalseResult = (AbstractExpression)a[4];

			return e;
		}

		public object _declaration (object[] a)
		{
			ArrayList ad = new ArrayList();

			foreach (Declaration d in Common.ObjectToList(a[1]))
			{
				AbstractSemanticElement e = d;

				SetDeclaration(ref e, a[0]);

				ad.Add(e);

				if (e is TypeDefinition)
					s.Typify(e.Name);
			}

			return ad;
		}

		public static object _type_name (object[] a)
		{
			AbstractSemanticElement e = ObjectToDeclaration(a[1]);

			SetDeclaration(ref e, a[0]);

			return e.Type;
		}

		public static object _enum_specifier_0 (object[] a)
		{
			EnumerationType t = new EnumerationType();

			t.Name = ObjectToTerminalValue(a[1]);
			t.Item = (EnumerationItem[])Common.ObjectToArray(a[3], typeof(EnumerationItem));

			return t;
		}

		public static object _enum_specifier_1 (object[] a)
		{
			NamedType t = new NamedType();

			t.Type = NameTypes.Enumeration;
			t.Name = ObjectToTerminalValue(a[1]);

			return t;
		}

		public object _struct_declaration (object[] a)
		{
			ArrayList ad = Common.ObjectToList(_declaration(a));

			foreach (Declaration d in ad)
			{
				if (d.Value != null)
					if (!(d.Type is IntegerType || d.Type is BoolType))
						throw new BCException(ExceptionType.Semantic, CUI.Code.c99_6_7_2_1_4);
					else
					{
						AbstractPrimitiveType pt = (AbstractPrimitiveType)d.Type;

						pt.Precision = -1;
						pt.PrecisionExpression = ((Initializer)d.Value).Expression;

						d.Value = null;
					}
			}

			return ad;
		}

		public static object _struct_declarator (object[] a)
		{
			Declaration d = ObjectToDeclaration(a[0]);

			if (a[2] != null)
			{
				Initializer i = new Initializer();

				i.Expression = (AbstractExpression)a[2];

				d.Value = i;
			}

			return d;
		}

		public static object _enumerator_0 (object[] a)
		{
			EnumerationItem i = new EnumerationItem();

			i.Name = ObjectToTerminalValue(a[0]);

			return i;
		}

		public static object _enumerator_1 (object[] a)
		{
			EnumerationItem i = new EnumerationItem();

			i.Name = ObjectToTerminalValue(a[0]);
			i.Value = (AbstractExpression)a[2];

			return i;
		}

		public static object _declarator (object[] a)
		{
			Declaration d = ObjectToDeclaration(a[1]);

			if (a[0] != null)
				SetType(ref d.Type, (IndirectType)a[0]);

			return d;
		}

		public object _direct_declarator_0 (object[] a)
		{
			Declaration d = new Declaration();

			d.Name = ObjectToTerminalValue(a[0]);

			s.Add(d.Name);

			return d;
		}

		public static object _direct_declarator_2 (object[] a)
		{
			Debug.Assert(a[2] == null || a[4] == null);

			Declaration d = (Declaration)a[0];

			ArrayType t = new ArrayType();

			Definitions.SetQualifiers(t, a[3]);

			t.Static = a[2] != null || a[4] != null;

			if (a[5] != null)
			{
				t.Dimension = new AbstractExpression[1];
				t.Dimension[0] = (AbstractExpression)a[5];
			}

			SetType(ref d.Type, t);

			return d;
		}

		public static object _direct_declarator_5 (object[] a)
		{
			Declaration d = (Declaration)a[0];
			AbstractType t = new ArrayType();

			((ArrayType)t).Dimension = new AbstractExpression[1];

			SetType(ref t, d.Type);
			d.Type = t;

			Definitions.SetQualifiers(t, a[2]);

			return d;
		}

		public static object _direct_declarator_6 (object[] a)
		{
			Declaration d = ObjectToDeclaration(a[0]);

			FunctionType t = new FunctionType();
			t.Argument = (Declaration[])Common.ObjectToArray(a[2], typeof(Declaration));
			
			SetType(ref d.Type, t);

			return d;
		}

		public static object _direct_declarator_7 (object[] a)
		{
			Declaration d = ObjectToDeclaration(a[0]);

			ArrayList n = new ArrayList();

			foreach (Terminal i in Common.ObjectToList(a[2]))
			{
				Debug.Assert(i.IsA(C.T_identifier));

				Declaration f = new Declaration();

				f.Name = i.Value;

				n.Add(f);
			}

			FunctionType t = new FunctionType();
			t.Argument = (Declaration[])Common.ListToArray(n, typeof(Declaration));
			
			SetType(ref d.Type, t);

			return d;
		}

		public static object _parameter_type_list_1 (object[] a)
		{
			ArrayList a0 = (ArrayList)a[0];

			Declaration d = new Declaration();
			d.Type = new VarArgType();

			a0.Add(d);

			return a0;
		}

		public static object _declaration_1 (object[] a)
		{
			AbstractSemanticElement e = ObjectToDeclaration(a[1]);

			SetDeclaration(ref e, a[0]);

			return e;
		}

		public static object _pointer (object[] a)
		{
			IndirectType t = new IndirectType();

			Definitions.SetQualifiers(t, a[1]);

			t.Base = (AbstractType)a[2];

			return t;
		}

		public static object _init_declarator_0 (object[] a)
		{
			Declaration d = new Declaration();

			Declaration a0 = (Declaration)a[0];

			d.Type = a0.Type;
			d.Name = a0.Name;

			return d;
		}

		public static object _init_declarator_1 (object[] a)
		{
			Declaration d = (Declaration)_init_declarator_0(a);

			d.Value = (AbstractInitializer)a[2];

			return d;
		}

		public static object _struct_or_union_specifier_0 (object[] a)
		{
			CompositeType t = new CompositeType();

			t.Union = ((Terminal)a[0]).IsA(C.T_keyword_union);
			t.Name = ObjectToTerminalValue(a[1]);
			t.Field = (Declaration[])Common.ObjectToArray(a[3], typeof(Declaration));

			return t;
		}

		public static object _struct_or_union_specifier_1 (object[] a)
		{
			NamedType t = new NamedType();

			t.Type = ((Terminal)a[0]).IsA(C.T_keyword_union) ? NameTypes.Union : NameTypes.Structure;
			t.Name = ((Terminal)a[1]).Value;

			return t;
		}

		public object _typedef_name (object[] a)
		{
			string n = ObjectToTerminalValue(a[0]);

			if (s.Lookup(n) != SymbolType.Type)
				throw new BCException(ExceptionType.Semantic, CUI.Code.bc_001, n);

			return a[0];
		}

		public static object _initializer_0 (object[] a)
		{
			Initializer i = new Initializer();

			i.Expression = (AbstractExpression)a[0];

			return i;
		}

		public static object _initializer_1 (object[] a)
		{
			InitializerList i = new InitializerList();

			i.Initializer = (AbstractInitializer[])Common.ObjectToArray(a[1], typeof(AbstractInitializer));

			return i;
		}

		public static object _designated_initializer (object[] a)
		{
			AbstractInitializer i = (AbstractInitializer)a[1];

			i.Designator = (AbstractDesignator[])Common.ObjectToArray(a[0], typeof(AbstractDesignator));

			return i;
		}

		public static object _designator_0 (object[] a)
		{
			IndexDesignator d = new IndexDesignator();

			d.Index = (AbstractExpression)a[1];

			return d;
		}

		public static object _designator_1 (object[] a)
		{
			FieldDesignator d = new FieldDesignator();

			d.Field = ObjectToTerminalValue(a[0]);

			return d;
		}

		public static object _if_header (object[] a)
		{
			IfStatement s = new IfStatement();

			s.Expression = (AbstractExpression)a[1];

			return s;
		}

		public static object _left_recursive_header_0 (object[] a)
		{
			ForStatement s = new ForStatement();

			s.Expression = (AbstractExpression)a[4];
			s.Update = (AbstractExpression)a[6];

			return new object[] {s, a[2]};
		}

		public static object _left_recursive_header_1 (object[] a)
		{
			LoopStatement s = new LoopStatement();

			s.Expression = (AbstractExpression)a[1];

			return s;
		}

		public static object _left_recursive_header_2 (object[] a)
		{
			LabeledStatement s = new LabeledStatement();

			s.Label = ObjectToTerminalValue(a[0]);
			return s;
		}

		public static object _left_recursive_header_3 (object[] a)
		{
			LabeledStatement s = new LabeledStatement();

			s.Expression = (AbstractExpression)a[1];
			s.Case = true;

			return s;
		}

		public static object _left_recursive_header_4 (object[] a)
		{
			LabeledStatement s = new LabeledStatement();

			s.Case = true;

			return s;
		}

		public static object _left_recursive_header_5 (object[] a)
		{
			SwitchStatement s = new SwitchStatement();

			s.Expression = (AbstractExpression)a[1];

			return s;
		}

		public object _conditional_statement (object[] a)
		{
			AbstractStatement r;

			if (a[0] is object[])
			{
				object[] o = (object[])a[0];

				ForStatement s = (ForStatement)o[0];

				s.Statement = (AbstractStatement)a[1];

				if (o[1]== null || o[1] is AbstractExpression)
				{
					s.Init = (AbstractExpression)o[1];

					r = s;
				}
				else
				{
					CompoundStatement cs = new CompoundStatement();

					ArrayList l = (ArrayList)o[1];

					cs.Statement = new AbstractStatement[l.Count + 1];
					cs.Statement[l.Count] = s;

					for (int i = 0; i < l.Count; i++)
					{
						DeclarationStatement ds = new DeclarationStatement();

						ds.Declaration = (Declaration)l[i];

						cs.Statement[i] = ds;

						if (ds.Declaration.Value != null && ds.Declaration.Value is Initializer && s.Init == null)
						{
							BinaryExpression be = new BinaryExpression();
							NamedExpression ne = new NamedExpression();

							ne.Name = ds.Declaration.Name;

							be.LeftOperand = ne;
							be.Operator = Operator.Assign;
							be.RightOperand = ((Initializer)ds.Declaration.Value).Expression;

							s.Init = be;

							ds.Declaration.Value = null;
						}
					}

					r = cs;
				}

				this.s.CloseScope();
			}
			else
			{
				AbstractCombinationStatement s = (AbstractCombinationStatement)a[0];

				s.Statement = (AbstractStatement)a[1];

				if (a[3] != null)
					((IfStatement)s).ElseStatement = (AbstractStatement)a[3];

				r = s;
			}

			return r;
		}

		public static object _compound_statement (object[] a)
		{
			CompoundStatement s = new CompoundStatement();

			s.Statement = (AbstractStatement[])Common.ObjectToArray(a[1], typeof(AbstractStatement));

			return s;
		}

		public static object _declaration_statements (object[] a)
		{
			ArrayList l = new ArrayList();

			foreach (Declaration d in Common.ObjectToList(a[0]))
			{
				DeclarationStatement s = new DeclarationStatement();

				s.Declaration = d;

				l.Add(s);
			}

			return l;
		}

		public static object _comment_statement (object[] a)
		{
			CommentStatement s = new CommentStatement();

			s.Content = CommentContent(ObjectToTerminalValue(a[0]));

			return s;
		}

		public static object _expression_statement (object[] a)
		{
			ExpressionStatement s = new ExpressionStatement();

			s.Expression = (AbstractExpression)a[0];

			return s;
		}

		public static object _iteration_statement (object[] a)
		{
			LoopStatement s = new LoopStatement();
			
			s.Expression = (AbstractExpression)a[3];
			s.Statement = (AbstractStatement)a[1];
			s.PostCheck = true;

			return s;
		}

		public static object _jump_statement_0 (object[] a)
		{
			GotoStatement s = new GotoStatement();

			s.Target = ObjectToTerminalValue(a[1]);

			return s;
		}

		public static object _jump_statement_1 (object[] a)
		{
			return new ContinueStatement();
		}

		public static object _jump_statement_2 (object[] a)
		{
			return new BreakStatement();
		}

		public static object _jump_statement_3 (object[] a)
		{
			ReturnStatement s = new ReturnStatement();

			s.Expression = (AbstractExpression)a[1];

			return s;
		}

		MethodDefinition _function_declarator (IndirectType it, string n)
		{
			MethodDefinition d = new MethodDefinition();

			d.Name = n;
			d.Type = new FunctionType();

			s.Add(n);

			if (it != null)
				SetType(ref d.Type, it);

			s.OpenNewScope();

			return d;
		}

		public object _function_declarator_1 (object[] a)
		{
			MethodDefinition d = _function_declarator((IndirectType)a[0], ObjectToTerminalValue(a[1]));

			((FunctionType)d.Type).Argument = (Declaration[])Common.ObjectToArray(a[3], typeof(Declaration));

			foreach (Declaration x in ((FunctionType)d.Type).Argument)
				s.Add(x.Name);

			return d;
		}

		public object _function_declarator_2 (object[] a)
		{
			MethodDefinition d = _function_declarator((IndirectType)a[0], ObjectToTerminalValue(a[1]));

			ArrayList da = new ArrayList();

			foreach (object o in Common.ObjectToList(a[3]))
			{
				string n = ObjectToTerminalValue(o);

				Declaration pd = null;

				foreach (Declaration xd in Common.ObjectToList(a[5]))
				{
					if (xd.Name == n)
						if (pd != null)
							throw new BCException(ExceptionType.Semantic, CUI.Code.c99_6_7_3);
						else
							pd = xd;
				}

				if (pd == null)
					throw new BCException(ExceptionType.Semantic, CUI.Code.c99_6_9_1_6_s1);

				da.Add(pd);
			}

			((FunctionType)d.Type).Argument = (Declaration[])Common.ObjectToArray(da, typeof(Declaration));

			foreach (Declaration x in ((FunctionType)d.Type).Argument)
				s.Add(x.Name);

			return d;
		}

		public object _function_definition (object[] a)
		{
			AbstractSemanticElement e = (AbstractSemanticElement)a[1];

			SetDeclaration(ref e, a[0]);

			MethodDefinition d = (MethodDefinition)e;

			d.Body = (CompoundStatement)a[2];

			s.CloseScope();

			return d;
		}

		public static object _comment_element (object[] a)
		{
			CommentElement e = new CommentElement();
			
			e.Content = CommentContent(ObjectToTerminalValue(a[0]));

			return e;
		}

		public static object _start (object[] a)
		{
			Elements c = new Elements();

			c.Element = (AbstractElement[])Common.ObjectToArray(a[0], typeof(AbstractElement));

			return c;
		}

		public object _scope_open (object[] a)
		{
			s.OpenNewScope();

			return a[0];
		}

		public object _scope_close (object[] a)
		{
			s.CloseScope();

			return a[0];
		}
	}
}
