2015-06-01 22:15:17 +03:00
|
|
|
|
// Copyright (c) Ivan Bondarev, Stanislav Mihalkovich (for details please see \doc\copyright.txt)
|
|
|
|
|
|
// This code is distributed under the GNU LGPL (for details please see \doc\license.txt)
|
|
|
|
|
|
using System;
|
2015-05-14 22:35:07 +03:00
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.Text;
|
|
|
|
|
|
using PascalABCCompiler.SyntaxTree;
|
|
|
|
|
|
using PascalABCCompiler.TreeConverter;
|
|
|
|
|
|
|
|
|
|
|
|
//Визитор предназначен для обхода поддерева синтаксического дерева и поиска
|
|
|
|
|
|
//обращений к константам и элементам массива - их не получится найти в семантическом дереве.
|
|
|
|
|
|
//Запускать через RunVisitor()
|
|
|
|
|
|
//После работы визитора в нем содержится:
|
|
|
|
|
|
//- Список констант, обьявленных внутри функций или класса. Их нужно включать в генерируемую функцию в любом случае.
|
|
|
|
|
|
//- Список локальных переменных, параметров функций и полей класса. Их нужно включать только если генерируется обьект-функция.
|
|
|
|
|
|
//- Список локальных блочных переменных. Если они есть - генерировать объект-функцию и включать в нее все локальные переменные,
|
|
|
|
|
|
// иначе можно обойтись просто локальной функцией и переменные не включать.
|
|
|
|
|
|
|
|
|
|
|
|
namespace PascalABCCompiler.TreeConverter
|
|
|
|
|
|
{
|
2015-07-27 21:54:07 +03:00
|
|
|
|
class VarFinderSyntaxVisitor : SyntaxTree.WalkingVisitorNew
|
2015-05-14 22:35:07 +03:00
|
|
|
|
{
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Содержит список определений констант, объявленных внутри функций [и класса].
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public List<SemanticTree.IConstantDefinitionNode> Constants =
|
|
|
|
|
|
new List<SemanticTree.IConstantDefinitionNode>();
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Содержит список определений переменных
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
public List<SemanticTree.IVAriableDefinitionNode> Variables =
|
|
|
|
|
|
new List<SemanticTree.IVAriableDefinitionNode>();
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Необходимо инициализировать для правильного поиска.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private compilation_context context;
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Признак того, что мы распараллеливаем цикл for. Установить в true перед обходом тела распараллеливаемого цикла.
|
|
|
|
|
|
/// Нужно для коррекции continue и break
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private bool isForNode = false;
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Признак обхода счетчика цикла.
|
|
|
|
|
|
/// При запрете объявления счетчиков цикла вне самого цикла - не нужно
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private bool isLoopVariable = false;
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Конструктор
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
/// <param name="root">Корень обходимого поддерева</param>
|
|
|
|
|
|
/// <param name="context">Контекст. Необходим для поиска переменных</param>
|
|
|
|
|
|
/// <param name="isForNode">True при обходе цикла, False при обходе секций</param>
|
|
|
|
|
|
public VarFinderSyntaxVisitor(syntax_tree_node root, compilation_context context, bool isForNode)
|
|
|
|
|
|
{
|
|
|
|
|
|
this.isForNode = isForNode;
|
|
|
|
|
|
this.context = context;
|
|
|
|
|
|
ProcessNode(root);
|
|
|
|
|
|
FixResultVar();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// <summary>
|
|
|
|
|
|
/// Исправление VariableDefinitionNode для переменной Result функций.
|
|
|
|
|
|
/// В семантике эта переменная называется $rv_{FuncName}, а нам нужно имя result
|
|
|
|
|
|
/// Создается новый фиктивный экземпляр local_variable с тем же типом и именем result и возвращается вместо старого.
|
|
|
|
|
|
/// </summary>
|
|
|
|
|
|
private void FixResultVar()
|
|
|
|
|
|
{
|
|
|
|
|
|
for (int i=0; i<Variables.Count; ++i)
|
|
|
|
|
|
if (Variables[i].name.StartsWith("$rv_"))
|
|
|
|
|
|
{
|
|
|
|
|
|
TreeRealization.local_variable OldResult = Variables[i] as TreeRealization.local_variable;
|
|
|
|
|
|
TreeRealization.local_variable NewResult = new PascalABCCompiler.TreeRealization.local_variable("result", OldResult.type, OldResult.function, OldResult.loc);
|
|
|
|
|
|
Variables[i] = NewResult;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public override void visit(ident value)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (value == null)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
int pos = value.name.LastIndexOf('`');
|
|
|
|
|
|
if (pos != -1)
|
|
|
|
|
|
value.name = value.name.Remove(pos);
|
|
|
|
|
|
|
|
|
|
|
|
SymbolInfo si = context.find(value.name);
|
|
|
|
|
|
if (si == null)
|
|
|
|
|
|
return; //ничего не нашли => переменная совсем локальная, никуда добавлять не нужно
|
|
|
|
|
|
|
|
|
|
|
|
if ((si.sym_info is SemanticTree.ICommonParameterNode) //параметр или
|
|
|
|
|
|
|| (si.sym_info is SemanticTree.ILocalVariableNode) //локальная переменная
|
|
|
|
|
|
|| (si.sym_info is SemanticTree.ICommonClassFieldNode) //поле класса
|
|
|
|
|
|
|| (si.sym_info is SemanticTree.ILocalBlockVariableNode)//локальная блочная переменная
|
|
|
|
|
|
|| isLoopVariable) //счетчик цикла
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!Variables.Contains(si.sym_info as SemanticTree.IVAriableDefinitionNode))
|
|
|
|
|
|
Variables.Add(si.sym_info as SemanticTree.IVAriableDefinitionNode);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if ((si.sym_info is SemanticTree.ICommonFunctionConstantDefinitionNode)//константа из функции
|
|
|
|
|
|
||(si.sym_info is SemanticTree.IClassConstantDefinitionNode)) //константа из класса
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!Constants.Contains(si.sym_info as SemanticTree.IConstantDefinitionNode))
|
|
|
|
|
|
Constants.Add(si.sym_info as SemanticTree.IConstantDefinitionNode);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
public override void visit(dot_node _dot_node)
|
|
|
|
|
|
{
|
|
|
|
|
|
ProcessNode(_dot_node.left);
|
|
|
|
|
|
//правую часть не обходим
|
|
|
|
|
|
}
|
|
|
|
|
|
public override void visit(for_node _for_node)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!_for_node.create_loop_variable && (_for_node.type_name == null))
|
|
|
|
|
|
throw new OpenMPException("Счетчик цикла должен быть обьявлен в заголовке цикла", _for_node.source_context);
|
|
|
|
|
|
|
|
|
|
|
|
bool _isForNode = isForNode;
|
|
|
|
|
|
isForNode = false;
|
|
|
|
|
|
|
|
|
|
|
|
isLoopVariable = true;
|
|
|
|
|
|
ProcessNode(_for_node.loop_variable);
|
|
|
|
|
|
isLoopVariable = false;
|
|
|
|
|
|
ProcessNode(_for_node.initial_value);
|
|
|
|
|
|
ProcessNode(_for_node.increment_value);
|
|
|
|
|
|
ProcessNode(_for_node.finish_value);
|
|
|
|
|
|
ProcessNode(_for_node.type_name);
|
|
|
|
|
|
ProcessNode(_for_node.statements);
|
|
|
|
|
|
|
|
|
|
|
|
isForNode = _isForNode;
|
|
|
|
|
|
}
|
|
|
|
|
|
//public override void visit(method_call _method_call)
|
|
|
|
|
|
public override void visit(procedure_call _proc_call)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (isForNode)
|
|
|
|
|
|
if ((_proc_call.func_name!= null)
|
|
|
|
|
|
&& (_proc_call.func_name is ident))
|
|
|
|
|
|
{
|
|
|
|
|
|
if ((_proc_call.func_name as ident).name.ToLower() == "continue")
|
|
|
|
|
|
(_proc_call.func_name as ident).name = "exit";
|
|
|
|
|
|
if ((_proc_call.func_name as ident).name.ToLower() == "break")
|
|
|
|
|
|
throw new OpenMPException("Нельзя использовать break в распараллеливаемом цикле", _proc_call.source_context);
|
|
|
|
|
|
}
|
|
|
|
|
|
base.visit(_proc_call);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|