public override void VisitGoToNode(GoToNode g) { string labelName = g.Label.Name; // При посещении узла GoTо создаем соответсвующую команду трехадресного кода var gt = new TACNodes.Goto(); code.AddNode(gt); // Если метка ведет в уже преобразованную часть программы if (labeledTANodes.ContainsKey(labelName)) { // Получаем помеченную строку треадресного кода и задаем ее как цель перехода var target = labeledTANodes[labelName]; gt.TargetLabel = target.Label; } else { // Иначе помещаем строку в лист ожидания пока помеченная часть программы не будет преобразована if (!forwardGotos.ContainsKey(labelName)) { forwardGotos.Add(labelName, new List <TACNodes.Goto>()); } forwardGotos[labelName].Add(gt); } }
public override void VisitIfNode(IfNode iif) { var ifGoto = new TACNodes.IfGoto(); // Результат вычисления логического выражения var cond1 = RecAssign(iif.Conditon); ifGoto.Condition = cond1; code.AddNode(ifGoto); // Разбор тела else (если есть) iif.ElseClause?.Visit(this); // Пропускаем тело if var elseGoTo = new TACNodes.Goto(); code.AddNode(elseGoTo); // Добавление новой метки непосредственно перед телом if var newLabelIf = GetEmptyLabeledNode(); ifGoto.TargetLabel = newLabelIf.Label; // Обход выражений тела условного оператора iif.IfClause.Visit(this); // Метка после тела if, на нее передается управление из else var newLabelElse = GetEmptyLabeledNode(); elseGoTo.TargetLabel = newLabelElse.Label; }
public override void VisitCycleNode(CycleNode c) { // Метка в начале цикла var cycleLabel = GetEmptyLabeledNode(); // Результат вычисления логического выражения var cond = RecAssign(c.Condition); // При истинности условия, переходим к телу цикла var ifGotoBody = new TACNodes.IfGoto { Condition = cond }; code.AddNode(ifGotoBody); // Иначе переходим за тело цикла var gotoEnd = new TACNodes.Goto(); code.AddNode(gotoEnd); // Добавление новой метки непосредственно перед телом цикла var bodyLabel = GetEmptyLabeledNode(); ifGotoBody.TargetLabel = bodyLabel.Label; // Обход выражений тела цикла c.Body.Visit(this); // В конце цикла снова переходим к началу var cycleGoto = new TACNodes.Goto { TargetLabel = cycleLabel.Label }; code.AddNode(cycleGoto); // Метка за телом цикла, сюда происходит переход, если не выполняется условие продолжения var endLabel = GetEmptyLabeledNode(); gotoEnd.TargetLabel = endLabel.Label; }
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; }