Skip to content
Snippets Groups Projects
GenCodeVisitor.cs 6.37 KiB
Newer Older
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ProgramTree;
using System.Reflection.Emit;

namespace SimpleLang.Visitors
{
    {
        private Dictionary<string, LocalBuilder> vars = new Dictionary<string, LocalBuilder>();
        private GenCodeCreator genc;

        public GenCodeVisitor()
        {
            genc = new GenCodeCreator();
        }
        public override void VisitIdNode(IdNode id) 
        {
            // Этот Visit не вызывается если переменная стоит слева от оператора присваивания !
            // Т.е. он вызывается только если id находится в выражении, а значит, мы просто кладем его значение на стек!
            genc.Emit(OpCodes.Ldloc, vars[id.Name]);
        }
        public override void VisitIntNumNode(IntNumNode num) 
        {
            genc.Emit(OpCodes.Ldc_I4, num.Num);
        }
        public override void VisitBinOpNode(BinOpNode binop) 
        {
            binop.Left.Visit(this);
            binop.Right.Visit(this);
            switch (binop.Op)
            {
                case '+':
                    genc.Emit(OpCodes.Add);
                    break;
                case '-':
                    genc.Emit(OpCodes.Sub);
                    break;
                case '*':
                    genc.Emit(OpCodes.Mul);
                    break;
                case '/':
                    genc.Emit(OpCodes.Div);
                    break;
Acer's avatar
Acer committed
                case '%':
                    genc.Emit(OpCodes.Rem);
                    break;
            }
        }
        public override void VisitAssignNode(AssignNode a) 
        {
            a.Expr.Visit(this);
            genc.Emit(OpCodes.Stloc, vars[a.Id.Name]);
        }
        public override void VisitCycleNode(CycleNode c) 
        {
            var i = genc.DeclareLocal(typeof(int)); // переменная цикла cycle
            c.Expr.Visit(this); // сгенерировать команды, связанные с вычислением количества итераций цикла
            genc.Emit(OpCodes.Stloc, i); // i := кво итераций

            Label startLoop = genc.DefineLabel();
            Label endLoop = genc.DefineLabel();
            
            genc.MarkLabel(startLoop);

            genc.Emit(OpCodes.Ldloc, i); 
            genc.Emit(OpCodes.Ldc_I4_0);
            genc.Emit(OpCodes.Ble, endLoop); // if i<=0 then goto endLoop

            c.Stat.Visit(this); // выполнить тело цикла

            genc.Emit(OpCodes.Ldloc, i); // положить i на стек
            genc.Emit(OpCodes.Ldc_I4_1); // положить 1 на стек
            genc.Emit(OpCodes.Sub);
            genc.Emit(OpCodes.Stloc, i); // i := i - 1;

            genc.Emit(OpCodes.Br, startLoop);

            genc.MarkLabel(endLoop);
        }
        public override void VisitBlockNode(BlockNode bl) 
        {
            foreach (var st in bl.StList)
                st.Visit(this);
        }
        public override void VisitWriteNode(WriteNode w) 
        {
            w.Expr.Visit(this);
            genc.EmitWriteLine();
        }

        public override void VisitVarDefNode(VarDefNode w) 
        {
            foreach (var v in w.vars)
                vars[v.Name] = genc.DeclareLocal(typeof(int));
        }

Acer's avatar
Acer committed
        public override void VisitIfNode(IfNode i)
        {
            //var x = genc.DeclareLocal(typeof(int)); //переменная условного выражения 
Acer's avatar
Acer committed
            i.expr.Visit(this);
            //genc.Emit(OpCodes.Stloc, x); // x := значение условного выражения
Acer's avatar
Acer committed

            Label jmp = genc.DefineLabel();

            //genc.Emit(OpCodes.Ldloc, x);
Acer's avatar
Acer committed
            genc.Emit(OpCodes.Ldc_I4_0);
            genc.Emit(OpCodes.Ble, jmp); // if x<=0 then goto jmp

            i.ifTrue.Visit(this); // выполнить тело true условного оператора

            genc.MarkLabel(jmp);

            if(i.ifFalse!=null)
                i.ifFalse.Visit(this); // выполнить тело false условного оператора, если оно есть
        }

        public override void VisitWhileNode(WhileNode wh)
        {
            //wh.Expr.Visit(this);
            //genc.Emit(OpCodes.Stloc, x); // x := значение условного выражения в цикле 
Acer's avatar
Acer committed

            Label stop = genc.DefineLabel();
            Label back = genc.DefineLabel();

            genc.MarkLabel(back);

            wh.Expr.Visit(this);
Acer's avatar
Acer committed
            genc.Emit(OpCodes.Ldc_I4_0);
            genc.Emit(OpCodes.Beq, stop); // if x == 0 then goto stop
Acer's avatar
Acer committed

            wh.Stat.Visit(this);

            /*genc.Emit(OpCodes.Ldloc, x); // положить x на стек
Acer's avatar
Acer committed
            genc.Emit(OpCodes.Ldc_I4_1); // положить 1 на стек
            genc.Emit(OpCodes.Sub);
            genc.Emit(OpCodes.Stloc, x); // x := x - 1;*/
Acer's avatar
Acer committed

            genc.Emit(OpCodes.Br, back);

            genc.MarkLabel(stop);
        }

        public override void VisitRepeatNode(RepeatNode rp)
        {
            //var x = genc.DeclareLocal(typeof(int)); //переменная цикла с постусловием
Acer's avatar
Acer committed

            Label stop = genc.DefineLabel();
            Label back = genc.DefineLabel();

            genc.MarkLabel(back);

            foreach (var st in rp.StList)
                st.Visit(this);

            rp.Expr.Visit(this);
            //genc.Emit(OpCodes.Stloc, x);
            //genc.Emit(OpCodes.Ldloc, x);
Acer's avatar
Acer committed
            genc.Emit(OpCodes.Ldc_I4_0);
            genc.Emit(OpCodes.Beq, stop); // if x == 0 then goto stop
            /*genc.Emit(OpCodes.Ldloc, x); // положить x на стек
Acer's avatar
Acer committed
            genc.Emit(OpCodes.Ldc_I4_1); // положить 1 на стек
            genc.Emit(OpCodes.Sub);
            genc.Emit(OpCodes.Stloc, x); // x := x - 1;*/
Acer's avatar
Acer committed


            genc.Emit(OpCodes.Br, back);

            genc.MarkLabel(stop);

        }

        public void EndProgram()
        {
            genc.EndProgram();
        }

        public void RunProgram()
        {
            genc.RunProgram();
        }

        public void PrintCommands()
        {
            foreach (var s in genc.commands)
                Console.WriteLine(s);
        }
    }
}