/
n-dimens
/
pascalabcnet
Обзор
Документация
Войти
/
n-dimens
/
pascalabcnet
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
master
TreeConverter/OpenMP/VarFinderSyntaxVisitor.cs
145 строк
8 KB
AlexanderZemlyak
Fix result variable case sensitive comparing (#3282)
18 июн 2025, 23:56
Не верифицирован
18 июн 2025, 23:56
a07b644
Код
Авторство
О чём код?
// Copyright (c) Ivan Bondarev, Stanislav Mikhalkovich (for details please see \doc\copyright.txt) // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; using System.Collections.Generic; using System.Text; using PascalABCCompiler.SyntaxTree; using PascalABCCompiler.TreeConverter; //Визитор предназначен для обхода поддерева синтаксического дерева и поиска //обращений к константам и элементам массива - их не получится найти в семантическом дереве. //Запускать через RunVisitor() //После работы визитора в нем содержится: //- Список констант, обьявленных внутри функций или класса. Их нужно включать в генерируемую функцию в любом случае. //- Список локальных переменных, параметров функций и полей класса. Их нужно включать только если генерируется обьект-функция. //- Список локальных блочных переменных. Если они есть - генерировать объект-функцию и включать в нее все локальные переменные, // иначе можно обойтись просто локальной функцией и переменные не включать. namespace PascalABCCompiler.TreeConverter { class VarFinderSyntaxVisitor : SyntaxTree.WalkingVisitorNew { /// <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(StringConstants.result_var_name, 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_first(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); } } }