コード例 #1
0
        public override void VisitAssignNode(AssignNode a)
        {
            var assign = new TACNodes.Assign
            {
                Left      = null,
                Right     = RecAssign(a.Expr),
                Result    = GetVarByName(a.Id.Name),
                Operation = OpCode.Copy
            };

            code.AddNode(assign);
        }
コード例 #2
0
        /// <summary>
        /// Рекурсивный разбор выражений и генерация их кода
        /// </summary>
        private TACExpr.Var RecAssign(ExprNode ex)
        {
            var assign = new TACNodes.Assign();
            var result = new TACExpr.Var();

            assign.Result = result;

            // Обход продолжается до тех пор, пока выражение не окажется переменной или константой
            switch (ex)
            {
            case IdNode tmp1:
                assign.Left      = null;
                assign.Right     = GetVarByName(tmp1.Name);
                assign.Operation = OpCode.Copy;
                break;

            case IntNumNode tmp2:
                assign.Left      = null;
                assign.Right     = GetConst(tmp2.Num);
                assign.Operation = OpCode.Copy;
                break;

            case BinaryNode tmp3:
                assign.Left      = RecAssign(tmp3.Left);
                assign.Right     = RecAssign(tmp3.Right);
                assign.Operation = ConvertOp(tmp3.Operation);
                break;

            case UnaryNode tmp4:
                assign.Left      = null;
                assign.Right     = RecAssign(tmp4.Num);
                assign.Operation = ConvertOp(tmp4.Operation);
                break;
            }

            code.AddNode(assign);
            return(result);
        }
コード例 #3
0
        public override void VisitForNode(ForNode f)
        {
            // Значение счетчика цикла и инкремента при инициализации
            var counter = GetVarByName(f.Assign.Id.Name);
            var inc     = RecAssign(f.Inc);

            var init = new TACNodes.Assign()
            {
                Result    = counter,
                Left      = null,
                Right     = RecAssign(f.Assign.Expr),
                Operation = OpCode.Copy
            };

            code.AddNode(init);

            // Метка начала цикла
            var cycle = GetEmptyLabeledNode();

            // Условие выбора направления цикла
            var dirCond = new TACNodes.Assign()
            {
                Result    = new TACExpr.Var(),
                Left      = inc,
                Right     = new TACExpr.IntConst(0),
                Operation = OpCode.GreaterEq
            };

            code.AddNode(dirCond);

            // Выбор направления
            var dirIfGoto = new TACNodes.IfGoto();

            dirIfGoto.Condition = dirCond.Result;
            code.AddNode(dirIfGoto);

            // Для обратного направления счетчик сравнивается с границей на меньше равно - это условие выхода
            var initialBackwardCondition = new TACNodes.Assign
            {
                Result    = new TACExpr.Var(),
                Left      = counter,
                Right     = RecAssign(f.Border),
                Operation = OpCode.LessEq
            };

            code.AddNode(initialBackwardCondition);

            // Добавляем переход за конец цикла при выполнении условия выхода
            var ifGotoBackw = new TACNodes.IfGoto();
            var cond        = initialBackwardCondition.Result;

            ifGotoBackw.Condition = cond;
            code.AddNode(ifGotoBackw);

            // Пропускаем ветку прямого направления
            var forwSkipGoto = new TACNodes.Goto();

            code.AddNode(forwSkipGoto);

            // Начало ветки прямого направления
            var forwardLabel = GetEmptyLabeledNode();

            dirIfGoto.TargetLabel = forwardLabel.Label;

            // Для прямого направления счетчик сравнивается с границей на больше равно - это условие выхода
            var initialForwardCondition = new TACNodes.Assign
            {
                Result    = new TACExpr.Var(),
                Left      = counter,
                Right     = RecAssign(f.Border),
                Operation = OpCode.GreaterEq
            };

            code.AddNode(initialForwardCondition);

            // Добавляем переход за конец цикла при выполнении условия выхода
            var ifGotoForw = new TACNodes.IfGoto();

            ifGotoForw.Condition = initialForwardCondition.Result;
            code.AddNode(ifGotoForw);

            // Метка перед телом цикла - сюда происходит переход при пропуске ветки прямого обхода
            var forwSkipLabel = GetEmptyLabeledNode();

            forwSkipGoto.TargetLabel = forwSkipLabel.Label;

            // Дальнейший разбор тела выражения
            f.Body.Visit(this);

            // Пересчет инкремента
            inc = RecAssign(f.Inc);

            // Создаем строку с увеличением счетчика
            var ass1 = new TACNodes.Assign
            {
                Result    = counter,
                Left      = counter,
                Right     = inc,
                Operation = OpCode.Plus
            };

            code.AddNode(ass1);

            // Команда перехода к началу цикла
            var cycleGoto = new TACNodes.Goto {
                TargetLabel = cycle.Label
            };

            code.AddNode(cycleGoto);

            // Метка за концом цикла - сюда происходит переход при выполнении условия выхода
            var endCycle = GetEmptyLabeledNode();

            ifGotoForw.TargetLabel  = endCycle.Label;
            ifGotoBackw.TargetLabel = endCycle.Label;
        }