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); }
/// <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); }
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; }