2015-07-27 21:54:07 +03:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
namespace PascalABCCompiler.SyntaxTree
|
|
|
|
|
|
{
|
|
|
|
|
|
|
2015-12-28 14:25:15 +03:00
|
|
|
|
//Два варианта использования визитора:
|
|
|
|
|
|
//1. Создать экземпляр этого класса, привязать к OnEnter и OnLeave обработчики посещений узла
|
|
|
|
|
|
//и запустить обход. Визитор обойдет дерево и для каждого узла вызовет эти обработчики.
|
2015-07-27 21:54:07 +03:00
|
|
|
|
//
|
2015-12-28 14:25:15 +03:00
|
|
|
|
//2. Унаследовать от этого класса свой класс, в котором переорпеделить обработку нужных узлов.
|
|
|
|
|
|
//Не забывать при этом о вызове visit'ов для подузлов (или base.visit), если это нужно.
|
2015-07-27 21:54:07 +03:00
|
|
|
|
|
|
|
|
|
|
public class WalkingVisitorNew : AbstractVisitor
|
|
|
|
|
|
{
|
|
|
|
|
|
|
2016-12-17 17:31:09 +03:00
|
|
|
|
protected Action<syntax_tree_node> OnEnter;
|
|
|
|
|
|
protected Action<syntax_tree_node> OnLeave;
|
2015-07-27 21:54:07 +03:00
|
|
|
|
|
2015-12-28 14:25:15 +03:00
|
|
|
|
protected bool visitNode = true; // в OnEnter можно сделать false
|
2015-07-27 21:54:07 +03:00
|
|
|
|
|
|
|
|
|
|
public virtual void ProcessNode(syntax_tree_node Node)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (Node != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (OnEnter != null)
|
|
|
|
|
|
OnEnter(Node);
|
|
|
|
|
|
|
|
|
|
|
|
if (visitNode)
|
|
|
|
|
|
Node.visit(this);
|
|
|
|
|
|
else visitNode = true;
|
|
|
|
|
|
|
|
|
|
|
|
if (OnLeave != null)
|
|
|
|
|
|
OnLeave(Node);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public override void DefaultVisit(syntax_tree_node n)
|
|
|
|
|
|
{
|
2017-01-10 08:49:49 +03:00
|
|
|
|
// n.subnodes_count может меняться в процессе работы этого алгоритма
|
|
|
|
|
|
// В частности, в результате ReplaceStatementWithParent
|
|
|
|
|
|
for (var i = 0; i < n.subnodes_count; i++)
|
2015-07-27 21:54:07 +03:00
|
|
|
|
ProcessNode(n[i]);
|
|
|
|
|
|
}
|
2016-12-01 23:46:54 +03:00
|
|
|
|
|
|
|
|
|
|
// Можно перенести сюда поскольку замена 1 на 1 позволяет пользоваться текущим DefaultVisit
|
2017-01-20 19:56:43 +03:00
|
|
|
|
public void ReplaceUsingParent(syntax_tree_node from, syntax_tree_node to)
|
2016-12-01 23:46:54 +03:00
|
|
|
|
{
|
2017-02-04 20:02:07 +03:00
|
|
|
|
to.Parent = from.Parent;
|
2016-12-01 23:46:54 +03:00
|
|
|
|
if (from.Parent == null)
|
|
|
|
|
|
throw new Exception("У корневого элемента нельзя получить Parent");
|
|
|
|
|
|
from.Parent.ReplaceDescendant(from, to);
|
|
|
|
|
|
}
|
2017-01-10 08:49:49 +03:00
|
|
|
|
|
|
|
|
|
|
public void ReplaceStatementUsingParent(statement from, IEnumerable<statement> to, Desc d = Desc.DirectDescendants)
|
|
|
|
|
|
{
|
2018-10-02 17:53:43 +03:00
|
|
|
|
var fp = from.Parent; // SSM 02.10.18 - запомним, т.к. from.Parent может быть одним из x.Parent
|
2018-11-12 06:44:51 +03:00
|
|
|
|
//foreach (var x in to) // Это и так делается по обоим веткам!
|
|
|
|
|
|
// x.Parent = fp;
|
2018-10-02 17:53:43 +03:00
|
|
|
|
var sl = fp as statement_list;
|
2017-01-10 08:49:49 +03:00
|
|
|
|
if (sl != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
sl.ReplaceInList(from, to);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
var l = new statement_list();
|
|
|
|
|
|
l.AddMany(to);
|
|
|
|
|
|
l.source_context = from.source_context;
|
2018-10-02 17:53:43 +03:00
|
|
|
|
fp.ReplaceDescendant(from, l, d);
|
2018-11-12 06:44:51 +03:00
|
|
|
|
l.Parent = fp; // на всякий случай
|
2017-01-10 08:49:49 +03:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2015-07-27 21:54:07 +03:00
|
|
|
|
}
|
2016-12-01 23:46:54 +03:00
|
|
|
|
|
2015-07-27 21:54:07 +03:00
|
|
|
|
}
|