public static void EmitBinaryExpression(Expression expr, SymbolTable table, ILGenerator ilGen)
        {
            System.Diagnostics.Debug.Assert(!expr.IsLeaf);

            #region +

            if (expr.OpType == OperationType.Plus)
            {
                EmitExpression(expr.LeftNode, table, ilGen);
                EmitExpression(expr.RightNode, table, ilGen);
                ilGen.Emit(OpCodes.Add);
                if (expr.LeftNode.ResultType.TypeEnum == VariableTypeEnum.Char ||
                    expr.RightNode.ResultType.TypeEnum == VariableTypeEnum.Char)
                {
                    ilGen.Emit(OpCodes.Conv_U2);
                }
            }

            #endregion

            #region -

            if (expr.OpType == OperationType.Minus)
            {
                EmitExpression(expr.LeftNode, table, ilGen);
                EmitExpression(expr.RightNode, table, ilGen);
                ilGen.Emit(OpCodes.Sub);
                if (expr.LeftNode.ResultType.TypeEnum == VariableTypeEnum.Char)
                {
                    ilGen.Emit(OpCodes.Conv_U2);
                }
            }

            #endregion

            #region **, *, /, mod

            if (expr.OpType == OperationType.Power)
            {
                EmitExpression(expr.LeftNode, table, ilGen);
                EmitExpression(expr.RightNode, table, ilGen);
                ilGen.Emit(OpCodes.Call, GetDeg());
            }

            if (expr.OpType == OperationType.Mult)
            {
                EmitExpression(expr.LeftNode, table, ilGen);
                EmitExpression(expr.RightNode, table, ilGen);
                ilGen.Emit(OpCodes.Mul);
            }

            if (expr.OpType == OperationType.Div)
            {
                EmitExpression(expr.LeftNode, table, ilGen);
                EmitExpression(expr.RightNode, table, ilGen);
                ilGen.Emit(OpCodes.Div);
            }
            if (expr.OpType == OperationType.Mod)
            {
                EmitExpression(expr.LeftNode, table, ilGen);
                EmitExpression(expr.RightNode, table, ilGen);
                ilGen.Emit(OpCodes.Rem);
            }

            #endregion

            #region unary -

            if (expr.OpType == OperationType.UMinus)
            {
                EmitExpression(expr.LeftNode, table, ilGen);
                ilGen.Emit(OpCodes.Neg);
            }

            #endregion

            #region unary not

            if (expr.OpType == OperationType.UNot)
            {
                EmitExpression(expr.LeftNode, table, ilGen);
                //ilGen.Emit(OpCodes.Not);
                ilGen.Emit(OpCodes.Ldc_I4_0);
                ilGen.Emit(OpCodes.Ceq);
            }

            #endregion

            #region and, or, xor

            if (expr.OpType == OperationType.And)
            {
                Label label = ilGen.DefineLabel();
                EmitExpression(expr.LeftNode, table, ilGen);
                ilGen.Emit(OpCodes.Dup);
                ilGen.Emit(OpCodes.Brfalse, label);
                EmitExpression(expr.RightNode, table, ilGen);
                ilGen.Emit(OpCodes.And);
                ilGen.MarkLabel(label);
            }

            if (expr.OpType == OperationType.Or)
            {
                Label label = ilGen.DefineLabel();
                EmitExpression(expr.LeftNode, table, ilGen);
                ilGen.Emit(OpCodes.Dup);
                ilGen.Emit(OpCodes.Brtrue, label);
                EmitExpression(expr.RightNode, table, ilGen);
                ilGen.Emit(OpCodes.Or);
                ilGen.MarkLabel(label);
            }

            if (expr.OpType == OperationType.Xor)
            {
                EmitExpression(expr.LeftNode, table, ilGen);
                EmitExpression(expr.RightNode, table, ilGen);
                ilGen.Emit(OpCodes.Xor);
            }

            #endregion

            #region <, >, <=, >=

            if (expr.OpType == OperationType.Le)
            {
                EmitExpression(expr.LeftNode, table, ilGen);
                EmitExpression(expr.RightNode, table, ilGen);
                ilGen.Emit(OpCodes.Clt);
            }

            if (expr.OpType == OperationType.Leeq)
            {
                EmitExpression(expr.LeftNode, table, ilGen);
                EmitExpression(expr.RightNode, table, ilGen);
                ilGen.Emit(OpCodes.Cgt);
                ilGen.Emit(OpCodes.Ldc_I4_0);
                ilGen.Emit(OpCodes.Ceq);
            }

            if (expr.OpType == OperationType.Gr)
            {
                EmitExpression(expr.LeftNode, table, ilGen);
                EmitExpression(expr.RightNode, table, ilGen);
                ilGen.Emit(OpCodes.Cgt);
            }

            if (expr.OpType == OperationType.Greq)
            {
                EmitExpression(expr.LeftNode, table, ilGen);
                EmitExpression(expr.RightNode, table, ilGen);
                ilGen.Emit(OpCodes.Clt);
                ilGen.Emit(OpCodes.Ldc_I4_0);
                ilGen.Emit(OpCodes.Ceq);
            }

            #endregion

            #region =, <>

            if (expr.OpType == OperationType.Equals)
            {
                if (expr.LeftNode.ResultType.TypeEnum == VariableTypeEnum.NULL &&
                    expr.RightNode.ResultType.TypeEnum == VariableTypeEnum.NULL)
                {
                    ilGen.Emit(OpCodes.Ldc_I4_1);
                }
                else if (expr.LeftNode.ResultType.TypeEnum == VariableTypeEnum.NULL)
                {
                    Type arrayType = GetTypeForCompilerType(expr.RightNode.ResultType);
                    EmitExpression(expr.RightNode, table, ilGen);
                    ilGen.Emit(OpCodes.Call, GetArrayNullGetter(arrayType));
                    ilGen.Emit(OpCodes.Ceq);
                }
                else if (expr.RightNode.ResultType.TypeEnum == VariableTypeEnum.NULL)
                {
                    Type arrayType = GetTypeForCompilerType(expr.LeftNode.ResultType);
                    EmitExpression(expr.LeftNode, table, ilGen);
                    ilGen.Emit(OpCodes.Call, GetArrayNullGetter(arrayType));
                    ilGen.Emit(OpCodes.Ceq);
                }
                else
                {
                    EmitExpression(expr.LeftNode, table, ilGen);
                    EmitExpression(expr.RightNode, table, ilGen);
                    ilGen.Emit(OpCodes.Ceq);
                }
            }

            if (expr.OpType == OperationType.NotEquals)
            {
                if (expr.LeftNode.ResultType.TypeEnum == VariableTypeEnum.NULL &&
                    expr.RightNode.ResultType.TypeEnum == VariableTypeEnum.NULL)
                {
                    ilGen.Emit(OpCodes.Ldc_I4_1);
                }
                else if (expr.LeftNode.ResultType.TypeEnum == VariableTypeEnum.NULL)
                {
                    Type arrayType = GetTypeForCompilerType(expr.RightNode.ResultType);
                    EmitExpression(expr.RightNode, table, ilGen);
                    ilGen.Emit(OpCodes.Call, GetArrayNullGetter(arrayType));
                    ilGen.Emit(OpCodes.Ceq);
                }
                else if (expr.RightNode.ResultType.TypeEnum == VariableTypeEnum.NULL)
                {
                    Type arrayType = GetTypeForCompilerType(expr.LeftNode.ResultType);
                    EmitExpression(expr.LeftNode, table, ilGen);
                    ilGen.Emit(OpCodes.Call, GetArrayNullGetter(arrayType));
                    ilGen.Emit(OpCodes.Ceq);
                }
                else
                {
                    EmitExpression(expr.LeftNode, table, ilGen);
                    EmitExpression(expr.RightNode, table, ilGen);
                    ilGen.Emit(OpCodes.Ceq);
                }
                ilGen.Emit(OpCodes.Ldc_I4_0);
                ilGen.Emit(OpCodes.Ceq);
            }

            #endregion

            #region []

            if (expr.OpType == OperationType.ArrayAccess)
            {
                Type arrayType = GetTypeForCompilerType(expr.LeftNode.ResultType);
                EmitExpression(expr.LeftNode, table, ilGen);
                EmitExpression(expr.RightNode, table, ilGen);
                ilGen.Emit(OpCodes.Call, GetArrayGetter(arrayType));
            }

            #endregion

            #region Assign

            if (expr.OpType == OperationType.Assign)
            {
                if (expr.LeftNode.OpType == OperationType.ArrayAccess)
                {
                    Type arrayType = GetTypeForCompilerType(expr.LeftNode.LeftNode.ResultType);
                    //Array
                    EmitExpression(expr.LeftNode.LeftNode, table, ilGen);
                    //Index
                    EmitExpression(expr.LeftNode.RightNode, table, ilGen);
                    //Value
                    EmitExpression(expr.RightNode, table, ilGen);
                    //Setter call
                    ilGen.Emit(OpCodes.Call, GetArraySetter(arrayType));
                    //Banditism: after setter call - there is specified value on the stack's top
                }
                else if (expr.LeftNode.LeafType == ExpressionLeafType.VariableAccess)
                {
                    Symbol symbol = table.FindSymbol(expr.LeftNode.Value.ToString());
                    //Reight part
                    if (expr.RightNode.ResultType.TypeEnum == VariableTypeEnum.NULL)
                    {
                        ilGen.Emit(OpCodes.Call, GetArrayNullGetter(symbol.Type));
                        ilGen.Emit(OpCodes.Dup);
                    }
                    else
                    {
                        EmitExpression(expr.RightNode, table, ilGen);
                        ilGen.Emit(OpCodes.Dup);
                    }
                    //Setter for variable
                    if (symbol.IsParameter)
                    {
                        ilGen.Emit(OpCodes.Starg, symbol.ParameterIndex);
                    }
                    else
                    {
                        ilGen.Emit(OpCodes.Stloc, symbol.LocalBuilder);
                    }
                }
                else
                {
                    System.Diagnostics.Debug.Fail("Bad compiler error: bad assign construction");
                }
            }

            #endregion
        }
        public static void EmitUnaryExpression(Expression expr, SymbolTable table, ILGenerator ilGen)
        {
            System.Diagnostics.Debug.Assert(expr.IsLeaf);

            #region Const

            if (expr.LeafType == ExpressionLeafType.Constant)
            {
                if (expr.ResultType.TypeEnum == VariableTypeEnum.Integer)
                {
                    ilGen.Emit(OpCodes.Ldc_I4, expr.IntValue);
                }
                if (expr.ResultType.TypeEnum == VariableTypeEnum.Char)
                {
                    ilGen.Emit(OpCodes.Ldc_I4, (int)expr.CharValue);
                }
                if (expr.ResultType.TypeEnum == VariableTypeEnum.Bool)
                {
                    ilGen.Emit(OpCodes.Ldc_I4, Convert.ToInt32(expr.BoolValue));
                }
                if (expr.ResultType.TypeEnum == VariableTypeEnum.Array)
                {
                    string s = expr.Value.ToString();
                    ilGen.Emit(OpCodes.Ldstr, s);
                    ilGen.Emit(OpCodes.Call, GetStrArr());
                }

                System.Diagnostics.Debug.Assert(expr.ResultType.TypeEnum != VariableTypeEnum.NULL);
                //System.Diagnostics.Debug.Assert(expr.ResultType.TypeEnum != VariableTypeEnum.Array);
            }

            #endregion

            #region Variable

            if (expr.LeafType == ExpressionLeafType.VariableAccess)
            {
                Symbol symbol = table.FindSymbol(expr.Value.ToString());
                if (symbol.IsParameter)
                {
                    ilGen.Emit(OpCodes.Ldarg, symbol.ParameterIndex);
                }
                else
                {
                    ilGen.Emit(OpCodes.Ldloc, symbol.LocalBuilder);
                }
            }

            #endregion

            #region FunctionCall

            if (expr.LeafType == ExpressionLeafType.FunctionCall)
            {
                List<VariableType> argumentTypes = new List<VariableType>();
                foreach (Expression e in expr.VAList)
                {
                    Type t = GetTypeForCompilerType(e.ResultType);
                    EmitExpression(e, table, ilGen);
                    argumentTypes.Add(e.ResultType);
                }
                MethodInfo mi = GetMethodForFunctionNameAndArgumentTypes(
                    expr.Value.ToString(),
                    argumentTypes.ToArray(),
                    expr.Location);
                ilGen.Emit(OpCodes.Call, mi);

                if (mi.ReturnType == typeof(void))
                    wasVoidFuncCalled = true;
            }

            #endregion

            #region New array

            if (expr.LeafType == ExpressionLeafType.ArrayAlloc)
            {
                Type arrayType = GetTypeForCompilerType(expr.ResultType);
                EmitExpression(expr.LeftNode, table, ilGen);
                ilGen.Emit(OpCodes.Newobj, GetArrayCtor(arrayType));
            }

            #endregion

            #region Array length

            if (expr.LeafType == ExpressionLeafType.ArrayLength)
            {
                Type arrayType = GetTypeForCompilerType(expr.LeftNode.ResultType);
                EmitExpression(expr.LeftNode, table, ilGen);
                ilGen.Emit(OpCodes.Call, GetArrayLengthGetter(arrayType));
            }

            #endregion
        }
        public static void EmitStatementList(StatementList statements, SymbolTable table, ILGenerator ilGen)
        {
            foreach (Statement statement in statements)
            {

                #region MarkLabel

                if (!String.IsNullOrEmpty(statement.Label))
                {
                    ilGen.MarkLabel(f_contextLabels[statement.Label]);
                }

                #endregion

                #region GoTo

                if (statement is GotoStatement)
                {
                    ilGen.Emit(OpCodes.Br, f_contextLabels[(statement as GotoStatement).GoTo]);
                }

                #endregion

                #region Expression

                if (statement is Expression)
                {
                    Expression expr = (Expression)statement;

                    EmitExpression(expr, table, ilGen);

                    if (!wasVoidFuncCalled)
                    {
                        ilGen.Emit(OpCodes.Pop);
                    }
                    wasVoidFuncCalled = false;
                }

                #endregion

                #region VariableDefinitionList

                if (statement is VariableDefinitionList)
                {
                    VariableDefinitionList vdList = (VariableDefinitionList)statement;

                    foreach (VariableSymbol vSymbol in vdList.Definitions)
                    {
                        EmitVariableDefinition(vSymbol, table, ilGen);
                    }
                }

                #endregion

                #region Return

                if (statement is ReturnStatement)
                {
                    ReturnStatement returnStatement = (ReturnStatement)statement;

                    EmitReturn(returnStatement, table, ilGen);
                }

                #endregion

                #region Assert

                if (statement is AssertStatement)
                {
                    AssertStatement assertStatement = (AssertStatement)statement;

                    EmitExpression(assertStatement.Expression, table, ilGen);
                    ilGen.Emit(OpCodes.Ldc_I4, assertStatement.Expression.Location.eLin);
                    ilGen.Emit(OpCodes.Call, GetAssert());
                }

                #endregion

                #region WhileDo

                if (statement is WhileDoStatement)
                {
                    WhileDoStatement wds = (WhileDoStatement)statement;
                    SymbolTable newTable = new SymbolTable(table);
                    Label condition = ilGen.DefineLabel();
                    Label endLoop = ilGen.DefineLabel();

                    ilGen.MarkLabel(condition);
                    EmitExpression(wds.Condition, table, ilGen);
                    ilGen.Emit(OpCodes.Brfalse, endLoop);
                    EmitStatementList(wds.Statements, newTable, ilGen);
                    ilGen.Emit(OpCodes.Br, condition);
                    ilGen.MarkLabel(endLoop);
                }

                #endregion

                #region DoWhile

                if (statement is DoWhileStatement)
                {
                    DoWhileStatement dws = (DoWhileStatement)statement;
                    SymbolTable newTable = new SymbolTable(table);
                    Label begin = ilGen.DefineLabel();

                    ilGen.MarkLabel(begin);
                    EmitStatementList(dws.Statements, newTable, ilGen);
                    EmitExpression(dws.Condition, table, ilGen);
                    ilGen.Emit(OpCodes.Brtrue, begin);
                }

                #endregion

                #region If

                if (statement is IfStatement)
                {
                    IfStatement ifStatement = (IfStatement)statement;
                    Label end = ilGen.DefineLabel();
                    Label elseLabel = ilGen.DefineLabel();
                    List<Label> labels = new List<Label>();
                    labels.Add(new Label());
                    for (int i = 1; i < ifStatement.Clauses.Count; ++i)
                    {
                        labels.Add(ilGen.DefineLabel());
                    }
                    labels.Add(elseLabel);

                    for (int i = 0; i < ifStatement.Clauses.Count; ++i)
                    {
                        SymbolTable newTable = new SymbolTable(table);
                        if (i != 0)
                            ilGen.MarkLabel(labels[i]);

                        EmitExpression(ifStatement.Clauses[i].Condition, table, ilGen);
                        ilGen.Emit(OpCodes.Brfalse, labels[i + 1]);
                        EmitStatementList(ifStatement.Clauses[i].Statements, newTable, ilGen);
                        ilGen.Emit(OpCodes.Br, end);
                    }
                    ilGen.MarkLabel(elseLabel);
                    if (ifStatement.AlternativeStatements != null)
                    {
                        SymbolTable newTable = new SymbolTable(table);
                        EmitStatementList(ifStatement.AlternativeStatements, newTable, ilGen);
                    }
                    ilGen.MarkLabel(end);
                }

                #endregion

                #region СycleFor

                if (statement is CycleStatement)
                {
                    CycleStatement cycle = (CycleStatement)statement;
                    SymbolTable newTable = new SymbolTable(table);

                    Symbol cycleIndex = null;

                    if (cycle.DeclareVariable != String.Empty)
                    {
                        Type localType = GetTypeForCompilerType(cycle.VariableType);
                        LocalBuilder indx = ilGen.DeclareLocal(localType);
                        newTable.AddSymbol(cycle.DeclareVariable, localType, indx);
                        cycleIndex = newTable.FindSymbol(cycle.DeclareVariable);
                    }
                    else
                    {
                        string indexName = cycle.Init.LeftNode.Value.ToString();
                        Symbol symbol = table.FindSymbol(indexName);
                        cycleIndex = symbol;
                    }

                    LocalBuilder end = ilGen.DeclareLocal(typeof(int));
                    LocalBuilder step = ilGen.DeclareLocal(typeof(int));

                    Label loopLabel = ilGen.DefineLabel();
                    Label endLabel = ilGen.DefineLabel();

                    //Save cycle step and end condition to local variables
                    EmitExpression(cycle.Step, table, ilGen);
                    ilGen.Emit(OpCodes.Stloc, step);
                    EmitExpression(cycle.EndValue, table, ilGen);
                    ilGen.Emit(OpCodes.Stloc, end);

                    //Init variable

                    if (cycle.DeclareVariable == String.Empty)
                    {
                        EmitExpression(cycle.Init, table, ilGen);
                        ilGen.Emit(OpCodes.Pop);
                    }
                    else
                    {
                        EmitExpression(cycle.Init, table, ilGen);
                        ilGen.Emit(OpCodes.Stloc, cycleIndex.LocalBuilder);
                    }

                    ilGen.MarkLabel(loopLabel);

                    //Check for cycle' condition

                    if (cycleIndex.IsParameter)
                        ilGen.Emit(OpCodes.Ldarg, cycleIndex.ParameterIndex);
                    else
                        ilGen.Emit(OpCodes.Ldloc, cycleIndex.LocalBuilder);
                    ilGen.Emit(OpCodes.Ldloc, end);
                    ilGen.Emit(OpCodes.Cgt);
                    ilGen.Emit(OpCodes.Brtrue, endLabel);

                    //Cycle body

                    EmitStatementList(cycle.Statements, newTable, ilGen);

                    //Increment

                    if (cycleIndex.IsParameter)
                        ilGen.Emit(OpCodes.Ldarg, cycleIndex.ParameterIndex);
                    else
                        ilGen.Emit(OpCodes.Ldloc, cycleIndex.LocalBuilder);
                    ilGen.Emit(OpCodes.Ldloc, step);
                    ilGen.Emit(OpCodes.Add);
                    if (cycleIndex.Type == typeof(char))
                        ilGen.Emit(OpCodes.Conv_U2);
                    if (cycleIndex.IsParameter)
                        ilGen.Emit(OpCodes.Starg, cycleIndex.ParameterIndex);
                    else
                        ilGen.Emit(OpCodes.Stloc, cycleIndex.LocalBuilder);

                    ilGen.Emit(OpCodes.Br, loopLabel);

                    ilGen.MarkLabel(endLabel);

                }

                #endregion

            }
        }