// 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.TreeRealization; using System.Collections; namespace PascalABCCompiler.TreeConverter { class OpenMPException : Exception { string msg; public SyntaxTree.SourceContext SC; public OpenMPException(string message) { msg = message; } public OpenMPException(string message, SyntaxTree.SourceContext source_context) { msg = message; SC = source_context; } public override string ToString() { return msg; } } class StackLoopVariables { Stack names = new Stack(); public StackLoopVariables() { } public StackLoopVariables(string var_name) { Push(var_name); } public void Push(string var_name) { names.Push(var_name); } public string Pop() { return names.Pop(); } public bool Contains(string var_name) { return names.Contains(var_name); } public void Clear() { names.Clear(); } } class ReductionDirective { public ReductionOperations Oper; public List variables = new List(); } class VarInfoContainer { public List Constants = new List(); public List SharedVariables = new List(); public List PrivateVariables = new List(); public List ReductionVariables = new List(); public List ReductionActions = new List(); public void UnionWith(VarInfoContainer container) { foreach (SemanticTree.IConstantDefinitionNode node in container.Constants) if (!Constants.Contains(node)) Constants.Add(node); foreach (SemanticTree.IVAriableDefinitionNode node in container.SharedVariables) if (!SharedVariables.Contains(node)) SharedVariables.Add(node); foreach (SemanticTree.IVAriableDefinitionNode node in container.PrivateVariables) if (!PrivateVariables.Contains(node)) PrivateVariables.Add(node); for (int i = 0; i < container.ReductionVariables.Count; ++i ) if (!ReductionVariables.Contains(container.ReductionVariables[i])) { ReductionVariables.Add(container.ReductionVariables[i]); ReductionActions.Add(container.ReductionActions[i]); } } } class ContextInfo { public ContextInfo(syntax_tree_visitor syntax_tree_visitor) { SaveContext(syntax_tree_visitor); } public common_type_node converted_type; public statement_list_stack statement_list_stack; public SemanticTree.field_access_level curr_fal; public List current_var_defs; public Stack block_stack; public statement_node_stack cycle_stack; public Hashtable current_member_decls; public common_function_node_stack function_node_stack; public SymbolInfo current_last_created_function; public bool SemanticRulesThrowErrorWithoutSave; public void SaveContext(syntax_tree_visitor syntax_tree_visitor) { converted_type = syntax_tree_visitor.context.converted_type; syntax_tree_visitor.context.converted_type = null; statement_list_stack = syntax_tree_visitor.convertion_data_and_alghoritms.statement_list_stack; syntax_tree_visitor.convertion_data_and_alghoritms.statement_list_stack = new statement_list_stack(); curr_fal = syntax_tree_visitor.context.get_field_access_level(); current_var_defs = syntax_tree_visitor.context.var_defs; syntax_tree_visitor.context.var_defs = new List(); block_stack = syntax_tree_visitor.context.block_stack; syntax_tree_visitor.context.block_stack = new Stack(); cycle_stack = syntax_tree_visitor.context.CyclesStack; syntax_tree_visitor.context.CyclesStack = new statement_node_stack(); current_member_decls = syntax_tree_visitor.context.member_decls; syntax_tree_visitor.context.member_decls = new Hashtable(); function_node_stack = syntax_tree_visitor.context.func_stack; syntax_tree_visitor.context.func_stack = new common_function_node_stack(); current_last_created_function = syntax_tree_visitor.context.last_created_function; SemanticRulesThrowErrorWithoutSave = SemanticRulesConstants.ThrowErrorWithoutSave; SemanticRulesConstants.ThrowErrorWithoutSave = true; } public void RestoreContext(syntax_tree_visitor syntax_tree_visitor) { SemanticRulesConstants.ThrowErrorWithoutSave = SemanticRulesThrowErrorWithoutSave; syntax_tree_visitor.convertion_data_and_alghoritms.statement_list_stack = statement_list_stack; syntax_tree_visitor.context.converted_type = converted_type; syntax_tree_visitor.context.var_defs = current_var_defs; syntax_tree_visitor.context.set_field_access_level(curr_fal); syntax_tree_visitor.context.block_stack = block_stack; syntax_tree_visitor.context.CyclesStack = cycle_stack; syntax_tree_visitor.context.member_decls = current_member_decls; syntax_tree_visitor.context.func_stack = function_node_stack; syntax_tree_visitor.context.last_created_function = current_last_created_function; } } class DirectiveInfo { /// /// Вспомогательная функция возвращает содержится ли переменная в списке переменных редукции /// /// /// /// private static bool ContainsVarible(List rds, string var) { foreach (ReductionDirective red_dir in rds) if (red_dir.variables.Contains(var)) return true; return false; } /// ///Из списка приватных переменных убираем все переменные редукции и возвращаем этот список /// /// /// /// private static List FiltrPrivVarsReductionsVars(List privs, List reds) { List res = new List(); foreach (string var in privs) if (!ContainsVarible(reds, var)) res.Add(var); return res; } public DirectiveInfo(SyntaxTree.compiler_directive dir) { Reductions = new List(); Privates = new List(); string DirText = dir.Directive.text.ToLower(); if (DirText.StartsWith("critical ") || DirText.Length == "critical".Length) { Kind = DirectiveKind.Critical; DirText = DirText.Substring("critical".Length).Trim().Replace(" ", ""); Name = DirText; //Если что, потом допилим } else if (DirText.StartsWith("parallel ")) { DirText = DirText.Substring("parallel".Length).Trim(); if (DirText.StartsWith("for ") || DirText.Length == "for".Length) { Kind = DirectiveKind.ParallelFor; DirText = DirText.Substring("for".Length).Trim(); ProcessClauses(DirText, dir.Directive.source_context, true); } else if (DirText.StartsWith("sections ") || DirText.Length == "sections".Length) { Kind = DirectiveKind.ParallelSections; DirText = DirText.Substring("sections".Length).Trim(); ProcessClauses(DirText, dir.Directive.source_context, false); } else { Kind = DirectiveKind.Unknown; PutError(DirText.Length, dir.Directive.source_context, "OMPERROR_UNKNOWN_DIRECTIVE"); } } else { Kind = DirectiveKind.Unknown; PutError(DirText.Length, dir.Directive.source_context != null ? dir.Directive.source_context : dir.source_context, "OMPERROR_UNKNOWN_DIRECTIVE"); } } //DirSC - SC текста директивы private void ProcessClauses(string Text, SyntaxTree.SourceContext DirSC, bool AllowReduction) { if (Text == "") return; if (Text.StartsWith("private ") || Text.StartsWith("private(")) { Text = Text.Substring("private".Length).Trim(); if (!Text.StartsWith("(")) { PutError(Text.Length, DirSC, "OMPERROR_ERROR_IN_CLAUSE_PARAMETERS"); return; } int ClosePos = Text.IndexOf(")"); if (ClosePos == -1) { PutError(Text.Length, DirSC, "OMPERROR_ERROR_IN_CLAUSE_PARAMETERS"); return; } string ClauseParam = Text.Substring(1, ClosePos - 1).Trim(); if (ClauseParam.Length == 0) { PutError(Text.Length, DirSC, "OMPERROR_ERROR_IN_CLAUSE_PARAMETERS"); return; } int err_code; List prs = ProcessPrivateParametrs(ClauseParam, Privates, out err_code); if (err_code == 0) { prs = FiltrPrivVarsReductionsVars(prs, Reductions); Privates.AddRange(prs); } else if (err_code == 1) { PutError(Text.Length, DirSC, "OMPERROR_ERROR_IN_CLAUSE_PARAMETERS"); return; } else { PutError(Text.Length, DirSC, "OMPERROR_WARNING_IN_CLAUSE_PARAMETERS_REPEATED_VARS"); //return; if (prs != null) { prs = FiltrPrivVarsReductionsVars(prs, Reductions); Privates.AddRange(prs); } } Text = Text.Substring(ClosePos + 1).Trim(); } else if (AllowReduction && (Text.StartsWith("reduction") || Text.StartsWith("reduction("))) { Text = Text.Substring("reduction".Length).Trim(); if (!Text.StartsWith("(")) { PutError(Text.Length, DirSC, "OMPERROR_ERROR_IN_CLAUSE_PARAMETERS"); return; } int ClosePos = Text.IndexOf(")"); if (ClosePos == -1) { PutError(Text.Length, DirSC, "OMPERROR_ERROR_IN_CLAUSE_PARAMETERS"); return; } string ClauseParam = Text.Substring(1, ClosePos - 1).Trim(); if (ClauseParam.Length == 0) { PutError(Text.Length, DirSC, "OMPERROR_ERROR_IN_CLAUSE_PARAMETERS"); return; } int err_code; ReductionDirective rd = ProcessReductionParametrs(ClauseParam, Reductions, out err_code); if (err_code == 0) { if (rd != null) Reductions.Add(rd); } else if (err_code == 1) { PutError(Text.Length, DirSC, "OMPERROR_ERROR_IN_CLAUSE_PARAMETERS"); return; } else { PutError(Text.Length, DirSC, "OMPERROR_WARNING_IN_CLAUSE_PARAMETERS_REPEATED_VARS"); if (rd != null && rd.variables.Count != 0) Reductions.Add(rd); //return; } Text = Text.Substring(ClosePos + 1).Trim(); } else { PutError(Text.Length, DirSC, "OMPERROR_ERROR_IN_CLAUSE"); return; } ProcessClauses(Text, DirSC, AllowReduction); } /// /// Обрабатывает параметры редукции и возвращает их /// /// текст, содержащий параметры редукции /// список уже построенных кляуз редукции /// код ошибки. 0 - нет ошибок,1-ошибка в параметрах редукции, 2- повторно обьявленная переменная редукции проигнорирована /// private ReductionDirective ProcessReductionParametrs(string param_text, List rds, out int err_code) { //string err_mes = "Ошибка в директиве OpenMP. Неверные параметры reduction. Опция проигнорирована!"; // теперь надо найти параметры редукции ReductionDirective rd = new ReductionDirective(); int state = 1; int ind = 0; err_code = 0; string ident = ""; while (ind < param_text.Length) { switch (state) { case 1: if (param_text[ind] == '+') { rd.Oper = ReductionOperations.plus; state = 7; } else if (param_text[ind] == '-') { rd.Oper = ReductionOperations.minus; state = 7; } else if (param_text[ind] == '*') { rd.Oper = ReductionOperations.mult; state = 7; } else if (param_text[ind] == 'o') state = 2; else if (param_text[ind] == 'x') state = 3; else if (param_text[ind] == 'a') state = 4; else if (param_text[ind] != ' ') { err_code = 1; return null; } break; case 2: if (param_text[ind] == 'r') { rd.Oper = ReductionOperations.or; state = 7; } else { err_code = 1; return null; } break; case 3: if (param_text[ind] == 'o') { state = 5; } else { err_code = 1; return null; } break; case 4: if (param_text[ind] == 'n') { state = 6; } else { err_code = 1; return null; } break; case 5: if (param_text[ind] == 'r') { rd.Oper = ReductionOperations.xor; state = 7; } else { err_code = 1; return null; } break; case 6: if (param_text[ind] == 'd') { rd.Oper = ReductionOperations.and; state = 7; } else { err_code = 1; return null; } break; case 7: if (param_text[ind] == ':') { state = 8; } else if (param_text[ind] != ' ') { err_code = 1; return null; } break; case 8: if (param_text[ind] == '_' || param_text[ind] >= 'A' && param_text[ind] <= 'z') { state = 9; ident += param_text[ind]; } else if (param_text[ind] != ' ') { err_code = 1; return null; } break; case 9:// читаем имя идентификатора if (param_text[ind] == '_' || param_text[ind] >= 'A' && param_text[ind] <= 'z' || param_text[ind] >= '0' && param_text[ind] <= '9') { ident += param_text[ind]; } else if (param_text[ind] == ' ') { state = 10; if (ContainsVarible(rds, ident.ToLower())) { err_code = 2; } else { rd.variables.Add(ident.ToLower()); } ident = ""; } else if (param_text[ind] == ',') { state = 8; if (rd.variables.Contains(ident.ToLower()) || ContainsVarible(rds, ident.ToLower())) { err_code = 2; } else { rd.variables.Add(ident.ToLower()); } ident = ""; } else { err_code = 1; return null; } break; case 10: if (param_text[ind] == ',') state = 8; else if (param_text[ind] != ' ') { err_code = 1; return null; } break; } ind++; } if (state != 9 && state != 10) { err_code = 1; return null; } if (state == 9) if (ContainsVarible(rds, ident.ToLower())) { err_code = 2; } else { rd.variables.Add(ident.ToLower()); } return rd; } private List ProcessPrivateParametrs(string param_text, List privateVars, out int err_code) { List res = new List(); int ind = 0; //string err_mes = "Ошибка в директиве OpenMP. Неверные параметры директивы private. Опция проигнорирована!"; // надо найти переменные private int state = 1; err_code = 0; string ident = ""; while (ind < param_text.Length) { switch (state) { case 1: if (param_text[ind] == '_' || param_text[ind] >= 'A' && param_text[ind] <= 'z') { state = 2; ident += param_text[ind]; } else if (param_text[ind] != ' ') { err_code = 1; res.Clear(); return res; } break; case 2:// читаем дальше имя идентификатора if (param_text[ind] == '_' || param_text[ind] >= 'A' && param_text[ind] <= 'z' || param_text[ind] >= '0' && param_text[ind] <= '9') { ident += param_text[ind]; } else if (param_text[ind] == ' ') { state = 3; if (res.Contains(ident.ToLower()) || privateVars.Contains(ident.ToLower())) { err_code = 2; } else res.Add(ident.ToLower()); ident = ""; } else if (param_text[ind] == ',') { state = 1; if (res.Contains(ident.ToLower()) || privateVars.Contains(ident.ToLower())) { err_code = 2; } else res.Add(ident.ToLower()); ident = ""; } else { err_code = 1; res.Clear(); return res; } break; case 3: if (param_text[ind] == ',') state = 1; else if (param_text[ind] != ' ') { err_code = 1; res.Clear(); return res; } break; } ind++; } if (state != 2 && state != 3) { err_code = 1; res.Clear(); return res; } if (state == 2) { if (res.Contains(ident.ToLower()) || privateVars.Contains(ident.ToLower())) { err_code = 2; } else res.Add(ident.ToLower()); } return res; } private void PutError(int TextLength, SyntaxTree.SourceContext DirSC, string ErrorName) { if (DirSC != null) { int bp = DirSC.Length - TextLength - "omp".Length; SC = new SyntaxTree.SourceContext(DirSC.begin_position.line_num, DirSC.begin_position.column_num + bp, DirSC.begin_position.line_num, DirSC.begin_position.column_num + bp); } this.ErrorName = ErrorName; } /// /// Тип директивы /// public DirectiveKind Kind; /// /// Имя (в случае если это критическая секция) /// public string Name; /// /// Список предложений /// public List Privates; public List Reductions; /// /// Если есть ошибка - здесь будет храниться ее позиция. Иначе - null. /// public SyntaxTree.SourceContext SC; public string ErrorName; } class Clause { /// /// Тип предложения /// public ClauseKind Kind; /// /// Оператор редукции /// public ReductionOperations Oper; /// /// Список имен переменных /// public List Names; } public enum ParallelPosition { Outside, InsideParallel, InsideSequential } public enum ReductionOperations { plus, minus, mult, xor, and, or } public enum DirectiveKind { Critical, ParallelFor, ParallelSections, Unknown } public enum ClauseKind { Private, Reduction } internal class OpenMP { #region Флаги //В программе встречаются критические секции public static bool LocksFound = false; private static bool LocksInitialized = false; //после инициализации хранит название класса с обьектами для блокировок private static string LocksName = ""; // хранит имя булевской глобальной переменной, означающей, что мы в текущий момент в параллельной секции private static string InParallelSection = ""; private static bool InParallelSectionCreated = false; //временно удаленные директивы private static Dictionary DisabledDirectives = new Dictionary(); //В программе встречаются директивы parallel for public static bool ForsFound = false; //в программе встречаются директивы parallel sections public static bool SectionsFound = false; #endregion #region Инициализация public static StackLoopVariables LoopVariables = new StackLoopVariables(); /// /// Словарь, возвращающий по директиве (compiler_directive) информацию о ней (DirectiveInfo) /// public static Dictionary DirInfosTable = new Dictionary(); //приведение класса в исходное состояние public static void InternalReset() { DisabledDirectives = new Dictionary(); LocksName = ""; LocksFound = false; LocksInitialized = false; ForsFound = false; SectionsFound = false; LoopVariables.Clear(); DirInfosTable.Clear(); InParallelSection = ""; InParallelSectionCreated = false; } //инициализация OpenMP public static void InitOpenMP(List directives, syntax_tree_visitor visitor, SyntaxTree.compilation_unit cu) { //Из-за переноса этой проверки в секцию инициализации - оно не всегда успевает инициализироваться до выполнения этого кода. //Будем надеяться, что условие никогда не выполнится. Без постороннего вмешательства (замена файлов старыми версиями) - не должно. //if (SystemLibrary.SystemLibInitializer.OMP_Available == null || SystemLibrary.SystemLibInitializer.OMP_Available.NotFound) //{ // visitor.AddWarning(new Errors.CommonWarning(PascalABCCompiler.StringResources.Get("OMPERROR_OMP_NOT_AVAILABLE"), cu.file_name, cu.source_context.begin_position.line_num, cu.source_context.begin_position.column_num)); // return; //} foreach (SyntaxTree.compiler_directive dir in directives) { if (dir.Name.text.ToLower() == "omp") { string DirText = dir.Directive.text.ToLower(); DirectiveInfo dirInf = new DirectiveInfo(dir); DirInfosTable.Add(dir, dirInf); if (dirInf.Kind == DirectiveKind.ParallelFor) ForsFound = true; else if (dirInf.Kind == DirectiveKind.ParallelSections) SectionsFound = true; else if (dirInf.Kind == DirectiveKind.Critical) LocksFound = true; else { visitor.AddWarning(new Errors.CommonWarning(PascalABCCompiler.StringResources.Get(dirInf.ErrorName), dir.source_context.FileName, dirInf.SC != null ? dirInf.SC.begin_position.line_num : dir.source_context.begin_position.line_num, dirInf.SC != null ? dirInf.SC.begin_position.column_num : dir.source_context.begin_position.column_num)); } } } //уже не нужно //if (ForsFound && SystemLibrary.SystemLibInitializer.OMP_ParallelFor.NotFound) //{ // visitor.AddWarning(new Errors.CommonWarning(PascalABCCompiler.StringResources.Get("OMPERROR_PARALLELIZATION_FOR_NOT_AVAILABLE"), cu.file_name, cu.source_context.begin_position.line_num, cu.source_context.begin_position.column_num)); // ForsFound = false; //} //if (SectionsFound && SystemLibrary.SystemLibInitializer.OMP_ParallelSections.NotFound) //{ // visitor.AddWarning(new Errors.CommonWarning(PascalABCCompiler.StringResources.Get("OMPERROR_PARALLELIZATION_SECTIONS_NOT_AVAILABLE"), cu.file_name, cu.source_context.begin_position.line_num, cu.source_context.begin_position.column_num)); // SectionsFound = false; //} //"оторванные" директивы: //можно использовать директивы синхронизации и вне параллельных областей. //if (!SectionsFound && !ForsFound && LocksFound) //{ // visitor.AddWarning(new Errors.CommonWarning(PascalABCCompiler.StringResources.Get("OMPERROR_USING_CRITICAL_SECTIONS_OUTSIDE_PARALLEL_STRUCTURES"), cu.file_name, cu.source_context.begin_position.line_num, cu.source_context.begin_position.column_num)); // LocksFound = false; //} } //инициализация критических секций с созданием класса private static void InitCriticals(syntax_tree_visitor visitor) { //генерируем класс SyntaxTree.type_declarations TypeDecls = new PascalABCCompiler.SyntaxTree.type_declarations(); SyntaxTree.type_declaration TypeDecl = new PascalABCCompiler.SyntaxTree.type_declaration(); TypeDecls.types_decl.Add(TypeDecl); LocksName = visitor.context.get_free_name("$locks_container{0}"); TypeDecl.type_name = new PascalABCCompiler.SyntaxTree.ident(LocksName); SyntaxTree.class_definition ClassDef = new PascalABCCompiler.SyntaxTree.class_definition(); TypeDecl.type_def = ClassDef; SyntaxTree.class_body_list ClassBody = new PascalABCCompiler.SyntaxTree.class_body_list(); ClassDef.body = ClassBody; SyntaxTree.class_members ClassMember = new PascalABCCompiler.SyntaxTree.class_members(); ClassBody.class_def_blocks.Add(ClassMember); ClassMember.access_mod = new PascalABCCompiler.SyntaxTree.access_modifer_node(PascalABCCompiler.SyntaxTree.access_modifer.public_modifer); List ProcessedNames = new List(); foreach (KeyValuePair pair in DirInfosTable) { if (pair.Value.Kind == DirectiveKind.Critical) { string LockName = "$default"; if (pair.Value.Name.Length != 0) LockName = pair.Value.Name; if (ProcessedNames.Contains(LockName)) continue; ProcessedNames.Add(LockName); SyntaxTree.var_def_statement vds = new PascalABCCompiler.SyntaxTree.var_def_statement(); SyntaxTree.ident_list idl = new PascalABCCompiler.SyntaxTree.ident_list(); vds.vars = idl; idl.Add(new SyntaxTree.ident(LockName)); SyntaxTree.named_type_reference ntr = new PascalABCCompiler.SyntaxTree.named_type_reference(); vds.vars_type = ntr; ntr.Add(new SyntaxTree.ident("object")); SyntaxTree.new_expr ne = new PascalABCCompiler.SyntaxTree.new_expr(); vds.inital_value = ne; ne.type = ntr; vds.var_attr = PascalABCCompiler.SyntaxTree.definition_attribute.Static; ClassMember.members.Add(vds); } } //сохраняем контекст ContextInfo contextInfo = new ContextInfo(visitor); try { visitor.visit(TypeDecls); LocksInitialized = true; } finally { //восстанавливаем контекст contextInfo.RestoreContext(visitor); } } #endregion #region Обработка критических секций public static void TryConvertCritical(ref SyntaxTree.statement st, syntax_tree_visitor visitor, SyntaxTree.compiler_directive directive) { if (!LocksInitialized) InitCriticals(visitor); string LockName = "$default"; if (DirInfosTable[directive].Name.Length != 0) LockName = DirInfosTable[directive].Name; SyntaxTree.lock_stmt LockStmt = new PascalABCCompiler.SyntaxTree.lock_stmt(); LockStmt.lock_object = new SyntaxTree.dot_node(new SyntaxTree.ident(LocksName), new SyntaxTree.ident(LockName)); LockStmt.stmt = st; st = LockStmt; } public static void DisableDirective(SyntaxTree.syntax_tree_node node, Dictionary linker) { if (!linker.ContainsKey(node)) return; SyntaxTree.compiler_directive dir = linker[node]; if (DirInfosTable.ContainsKey(dir) && DirInfosTable[dir].Kind == DirectiveKind.Critical) { DisabledDirectives.Add(node, dir); linker.Remove(node); } } public static void EnableDirective(SyntaxTree.syntax_tree_node node, Dictionary linker) { if (!DisabledDirectives.ContainsKey(node)) return; SyntaxTree.compiler_directive dir = DisabledDirectives[node]; DisabledDirectives.Remove(node); linker.Add(node, dir); } #endregion public static bool IsParallelSectionsDirective(SyntaxTree.compiler_directive directive) { return DirInfosTable.ContainsKey(directive) && DirInfosTable[directive].Kind == DirectiveKind.ParallelSections; } public static bool IsParallelForDirective(SyntaxTree.compiler_directive directive) { return DirInfosTable.ContainsKey(directive) && DirInfosTable[directive].Kind == DirectiveKind.ParallelFor; } public static bool IsCriticalDirective(SyntaxTree.compiler_directive directive) { return DirInfosTable.ContainsKey(directive) && DirInfosTable[directive].Kind == DirectiveKind.Critical; } #region Распараллеливание For //Проверки на доступность OMP и директиву проводятся перед вызовом. internal static statements_list TryConvertFor(statements_list for_head_stmts, SyntaxTree.for_node for_node, for_node fn, var_definition_node loop_variable, expression_node fromInclusive, expression_node toInclusive, syntax_tree_visitor syntax_tree_visitor) { try { location loc = fn.location; statements_list omp_stmts = new statements_list(loc); statements_list head_stmts = new statements_list(loc); syntax_tree_visitor.convertion_data_and_alghoritms.statement_list_stack_push(head_stmts); if (!InParallelSectionCreated) CreateInParallelVariable(syntax_tree_visitor, out InParallelSection); //если omp доступен то (выполнять паралельно) иначе (выполнять for) if_node ifnode = CreateIfCondition(syntax_tree_visitor, omp_stmts, for_head_stmts, loc); head_stmts.statements.AddElement(ifnode); //генерим ветку в случае когда доступен omp if (!GenerateOMPParallelForCall(fn.body, for_node, loop_variable, omp_stmts, syntax_tree_visitor, fromInclusive, toInclusive)) { syntax_tree_visitor.convertion_data_and_alghoritms.statement_list_stack_pop(); return null; } syntax_tree_visitor.convertion_data_and_alghoritms.statement_list_stack_pop(); return head_stmts; } catch (OpenMPException e) { Exception ex = new Exception(e.ToString()); syntax_tree_visitor.convertion_data_and_alghoritms.statement_list_stack_pop(); syntax_tree_visitor.WarningsList.Add(new OMP_BuildigError(ex, syntax_tree_visitor.get_location(new SyntaxTree.syntax_tree_node(e.SC)))); } catch (Exception e) { syntax_tree_visitor.convertion_data_and_alghoritms.statement_list_stack_pop(); syntax_tree_visitor.WarningsList.Add(new OMP_BuildigError(e, fn.location)); } return null; } private static bool GenerateOMPParallelForCall(statement_node body, SyntaxTree.for_node for_node, var_definition_node loop_variable, statements_list omp_stmts, syntax_tree_visitor syntax_tree_visitor, expression_node fromInclusive, expression_node toInclusive) { SyntaxTree.statement syntax_body = for_node.statements; expression_node omp_call = null; base_function_call bfc = body as base_function_call; if (bfc != null && bfc.parameters.Count == 1 && bfc.parameters[0] is variable_reference && ((variable_reference)bfc.parameters[0]).VariableDefinition == loop_variable && ((bfc.function.parameters[0].type as type_node).PrintableName.ToLower() == "integer")) { //если тело цикла - вызов функции с одни параметром - переменной цикла, //если при этом у вызываемой функции тип параметра - integer, а не какой-нибудь object, как это бывает с write и вообще может быть с перегрузкой //то генерировать класс не надо. //генерируем вызов и все omp_call = syntax_tree_visitor.CreateDelegateCall(bfc); if (omp_call == null) { syntax_tree_visitor.AddWarning(new OMP_ConstructionNotSupportedNow(body.location)); syntax_tree_visitor.convertion_data_and_alghoritms.statement_list_stack_pop(); return false; } base_function_call omp_parallel_for_call = null; if (SystemLibrary.SystemLibInitializer.OMP_ParallelFor.sym_info is common_namespace_function_node) omp_parallel_for_call = new common_namespace_function_call(SystemLibrary.SystemLibInitializer.OMP_ParallelFor.sym_info as common_namespace_function_node, body.location); else omp_parallel_for_call = new compiled_static_method_call(SystemLibrary.SystemLibInitializer.OMP_ParallelFor.sym_info as compiled_function_node, body.location); omp_parallel_for_call.parameters.AddElement(fromInclusive); omp_parallel_for_call.parameters.AddElement(toInclusive); omp_parallel_for_call.parameters.AddElement(omp_call); omp_stmts.statements.AddElement(omp_parallel_for_call); } else { //ищем используемые переменные, получаем редукцию из директивы и составляем список переменных по типам VarFinderSyntaxVisitor VFvis = new VarFinderSyntaxVisitor(syntax_body, syntax_tree_visitor.context, true); SyntaxTree.compiler_directive dir = syntax_tree_visitor.DirectivesToNodesLinks[for_node]; //if (DirInfosTable[dir].ErrorName == "WARNING_IN_CLAUSE_PARAMETERS_REPEATED_VARS") // syntax_tree_visitor.AddWarning(new Errors.CommonWarning(StringResources.Get(DirInfosTable[dir].ErrorName), for_node.source_context.file_name, DirInfosTable[dir].SC.begin_position.line_num, DirInfosTable[dir].SC.begin_position.column_num)); //else if (DirInfosTable[dir].ErrorName == "ERROR_IN_CLAUSE_PARAMETERS") //{ // syntax_tree_visitor.AddWarning(new Errors.CommonWarning(StringResources.Get(DirInfosTable[dir].ErrorName), for_node.source_context.file_name, DirInfosTable[dir].SC.begin_position.line_num, DirInfosTable[dir].SC.begin_position.column_num)); //} //else if (DirInfosTable[dir].ErrorName !=null)//== "ERROR_IN_CLAUSE") { syntax_tree_visitor.AddWarning(new Errors.CommonWarning(PascalABCCompiler.StringResources.Get(DirInfosTable[dir].ErrorName), for_node.source_context.FileName, DirInfosTable[dir].SC.begin_position.line_num, DirInfosTable[dir].SC.begin_position.column_num)); } VarInfoContainer Vars = GetVarInfoContainer(VFvis, DirInfosTable[dir].Reductions, DirInfosTable[dir].Privates, syntax_tree_visitor, dir); //сохраняем контекст ContextInfo contextInfo = new ContextInfo(syntax_tree_visitor); string ClassName = syntax_tree_visitor.context.get_free_name("$for_class{0}"); try { //создаем и конвертируем класс SyntaxTree.class_members member; SyntaxTree.type_declarations Decls = CreateClass(ClassName, out member, Vars); member.members.Add(CreateMethod("Method", syntax_body, for_node.loop_variable.name, member, Vars)); syntax_tree_visitor.visit(Decls); } finally { //восстанавливаем контекст contextInfo.RestoreContext(syntax_tree_visitor); } //создаем инициализацию, вызов и финализацию string ObjName = syntax_tree_visitor.context.get_free_name("$for_obj{0}"); SyntaxTree.dot_node dn = new SyntaxTree.dot_node(new SyntaxTree.ident(ObjName), new SyntaxTree.ident("Method")); SyntaxTree.statement_list stl = CreateInitPart(ClassName, ObjName, Vars); stl.subnodes.Add(CreateNestedRegionBorder(true)); stl.subnodes.Add(CreateOMPParallelForCall(dn, for_node.initial_value, for_node.finish_value)); stl.subnodes.Add(CreateNestedRegionBorder(false)); stl.subnodes.AddRange(CreateFinalPart(ObjName, Vars).subnodes); omp_stmts.statements.AddElement(syntax_tree_visitor.ret.visit(stl)); } return true; } #endregion #region Распараллеливание секций internal static statements_list TryConvertSections(statements_list semantic_stmts, SyntaxTree.statement_list syntax_stmts, syntax_tree_visitor syntax_tree_visitor) { try { location loc = semantic_stmts.location; statements_list omp_stmts = new statements_list(loc); statements_list head_stmts = new statements_list(loc); syntax_tree_visitor.convertion_data_and_alghoritms.statement_list_stack_push(head_stmts); if (!InParallelSectionCreated) CreateInParallelVariable(syntax_tree_visitor, out InParallelSection); //если omp доступен то (выполнять паралельно) иначе (выполнять последовательно операторы) if_node ifnode = CreateIfCondition(syntax_tree_visitor, omp_stmts, semantic_stmts, loc); head_stmts.statements.AddElement(ifnode); //генерим ветку в случае когда доступен omp if (!GenerateOMPParallelSectionsCall(semantic_stmts, syntax_stmts, omp_stmts, syntax_tree_visitor)) { syntax_tree_visitor.convertion_data_and_alghoritms.statement_list_stack_pop(); return null; } syntax_tree_visitor.convertion_data_and_alghoritms.statement_list_stack_pop(); return head_stmts; } catch (OpenMPException e) { Exception ex = new Exception(e.ToString()); syntax_tree_visitor.convertion_data_and_alghoritms.statement_list_stack_pop(); syntax_tree_visitor.WarningsList.Add(new OMP_BuildigError(ex, syntax_tree_visitor.get_location(new SyntaxTree.syntax_tree_node(e.SC)))); } catch (Exception e) { syntax_tree_visitor.convertion_data_and_alghoritms.statement_list_stack_pop(); syntax_tree_visitor.WarningsList.Add(new OMP_BuildigError(e, semantic_stmts.location)); } return null; } private static bool GenerateOMPParallelSectionsCall(statements_list stmts, SyntaxTree.statement_list syntax_stmts, statements_list omp_stmts, syntax_tree_visitor syntax_tree_visitor) { SyntaxTree.expression_list delegates = new PascalABCCompiler.SyntaxTree.expression_list(); SyntaxTree.statement_list stlInit = new PascalABCCompiler.SyntaxTree.statement_list(); SyntaxTree.statement_list stlFinal = new PascalABCCompiler.SyntaxTree.statement_list(); VarInfoContainer Vars = new VarInfoContainer(); string ClassName = syntax_tree_visitor.context.get_free_name("$section_class{0}"); List Sections = new List(); foreach (SyntaxTree.statement syntax_statement in syntax_stmts.subnodes) { if (syntax_statement is SyntaxTree.empty_statement) continue; //А зачем? ;-) if (syntax_statement is SyntaxTree.var_statement) { //выдать предупреждение. Это не нормально для параллельных секций syntax_tree_visitor.visit(syntax_statement as SyntaxTree.var_statement); } else { //ищем используемые переменные VarFinderSyntaxVisitor VFvis = new VarFinderSyntaxVisitor(syntax_statement, syntax_tree_visitor.context, false); SyntaxTree.compiler_directive dir = syntax_tree_visitor.DirectivesToNodesLinks[syntax_stmts]; //if (DirInfosTable[dir].ErrorName == "WARNING_IN_CLAUSE_PARAMETERS_REPEATED_VARS") // syntax_tree_visitor.AddWarning(new Errors.CommonWarning(StringResources.Get(DirInfosTable[dir].ErrorName), syntax_stmts.source_context.file_name, DirInfosTable[dir].SC.begin_position.line_num, DirInfosTable[dir].SC.begin_position.column_num)); //else if (DirInfosTable[dir].ErrorName == "ERROR_IN_CLAUSE_PARAMETERS") //{ // syntax_tree_visitor.AddWarning(new Errors.CommonWarning(StringResources.Get(DirInfosTable[dir].ErrorName), syntax_stmts.source_context.file_name, DirInfosTable[dir].SC.begin_position.line_num, DirInfosTable[dir].SC.begin_position.column_num)); //} //else if (DirInfosTable[dir].ErrorName != null) { syntax_tree_visitor.AddWarning(new Errors.CommonWarning(PascalABCCompiler.StringResources.Get(DirInfosTable[dir].ErrorName), syntax_stmts.source_context.FileName, DirInfosTable[dir].SC.begin_position.line_num, DirInfosTable[dir].SC.begin_position.column_num)); } Vars.UnionWith(GetVarInfoContainer(VFvis, null, DirInfosTable[dir].Privates, syntax_tree_visitor, dir)); Sections.Add(syntax_statement); } } //сохраняем контекст ContextInfo contextInfo = new ContextInfo(syntax_tree_visitor); try { //создание и конвертирование класса SyntaxTree.class_members member; SyntaxTree.type_declarations Decls = CreateClass(ClassName, out member, Vars); for (int i = 0; i < Sections.Count; ++i) member.members.Add(CreateMethod("method" + i.ToString(), Sections[i], "", member, Vars)); syntax_tree_visitor.visit(Decls); } finally { //восстанавливаем контекст contextInfo.RestoreContext(syntax_tree_visitor); } //создаем инициализацию и финализацию int NameNum = 0; string ObjName = GetFreeName("$section_obj", ref NameNum, syntax_tree_visitor.context); stlInit.subnodes.AddRange(CreateInitPart(ClassName, ObjName, Vars).subnodes); stlFinal.subnodes.AddRange(CreateFinalPart(ObjName, Vars).subnodes); SyntaxTree.procedure_call pc = new PascalABCCompiler.SyntaxTree.procedure_call(); SyntaxTree.method_call mc = new PascalABCCompiler.SyntaxTree.method_call(); mc.dereferencing_value = CreateTPLFunctionReference("Invoke"); pc.func_name = mc; SyntaxTree.expression_list exl = new PascalABCCompiler.SyntaxTree.expression_list(); //foreach (string str in ObjNames) for (int i=0; i /// Вспомогательная функция - возвращает подстроку между квадратными скобками, при поиске индексеров массива /// /// /// private static string get_indexer_string(string type_str) { string res = ""; int from = type_str.IndexOf("["); if (from == -1) return res; int to = type_str.IndexOf("]"); if (to == -1) return res; res = type_str.Substring(from + 1, to - from - 1); return res; } /// /// Возращает диапазоны массива из строки индексеров /// /// /// private static List get_diapasons(string index_str) { List res = new List(); string[] diaps = index_str.Split(','); foreach (string str in diaps) { if (str.Trim() == "") { res.Add(null); } else { string left = str.Substring(0, str.IndexOf('.')).Trim(); int from = str.LastIndexOf('.'); string right = str.Substring(from + 1, str.Length - from - 1).Trim(); int val; SyntaxTree.expression left_expr, right_expr; if (Int32.TryParse(left, out val)) { left_expr = new SyntaxTree.int32_const(val); } else left_expr = new SyntaxTree.ident(left); if (Int32.TryParse(right, out val)) { right_expr = new SyntaxTree.int32_const(val); } else right_expr = new SyntaxTree.ident(right); res.Add(new PascalABCCompiler.SyntaxTree.diapason(left_expr, right_expr)); } } return res; } /// /// Вспомогательная функция - разбивает строку по точкам и возвращает подстроки в виде списка ident-в /// /// /// private static List get_idents_from_dot_string(string s, SyntaxTree.SourceContext sc) { List idents = new List(); string[] strs = s.Split('.'); foreach (string id in strs) idents.Add(new SyntaxTree.ident(id, sc)); return idents; } /// /// Возвращает список ident-в, необходимых для генерации named_type_reference /// /// семантический тип /// private static List get_idents_from_generic_type(type_node sem_type, SyntaxTree.SourceContext sc) { if (sem_type != null) { List idents = null; if (sem_type.original_generic != null) idents = get_idents_from_dot_string(sem_type.original_generic.full_name, sc); return idents; } return null; } private static SyntaxTree.type_definition get_diapason(type_node sem_type) { if (sem_type is compiled_type_node) return new PascalABCCompiler.SyntaxTree.named_type_reference(get_idents_from_dot_string(sem_type.PrintableName, sem_type.location)); if (sem_type is common_type_node) { SyntaxTree.diapason diap = new PascalABCCompiler.SyntaxTree.diapason(); diap.source_context = sem_type.location; common_type_node ctn = sem_type as common_type_node; diap.left = ConvertConstant(ctn.low_bound); diap.right = ConvertConstant(ctn.upper_bound); return diap; } return null; } /// /// Возвращает по семантическому типу соответсвующий ему синтаксический тип /// /// семантический тип /// Синтаксический тип public static SyntaxTree.type_definition ConvertToSyntaxType(type_node sem_type) { // SSM 29/12/18 для перечислимого типа возвращает null! if (sem_type.IsPointer)// если указатель { SyntaxTree.ref_type rt = new PascalABCCompiler.SyntaxTree.ref_type(); if (sem_type is compiled_type_node) rt.pointed_to = ConvertToSyntaxType((sem_type as compiled_type_node).element_type); else rt.pointed_to = ConvertToSyntaxType((sem_type as ref_type_node).pointed_type); return rt; } else if (sem_type.type_special_kind == SemanticTree.type_special_kind.none_kind || sem_type.type_special_kind == SemanticTree.type_special_kind.record || sem_type.type_special_kind == SemanticTree.type_special_kind.text_file) { if (sem_type.is_generic_type_instance)// это шаблонный тип { SyntaxTree.template_type_reference ttr = new PascalABCCompiler.SyntaxTree.template_type_reference(); SyntaxTree.named_type_reference ntr = new PascalABCCompiler.SyntaxTree.named_type_reference(); ttr.name = ntr; ttr.source_context = sem_type.location; ntr.source_context = ttr.source_context; ntr.names.AddRange(get_idents_from_generic_type(sem_type, sem_type.location)); SyntaxTree.template_param_list tpl = new PascalABCCompiler.SyntaxTree.template_param_list(); ttr.params_list = tpl; foreach (type_node tn in sem_type.instance_params) tpl.params_list.Add(ConvertToSyntaxType(tn)); return ttr; } else if (sem_type.IsEnum) return new PascalABCCompiler.SyntaxTree.named_type_reference(get_idents_from_dot_string(sem_type.name, sem_type.location), sem_type.location); else if (sem_type is compiled_type_node ctn1 && ctn1.compiled_type == typeof(System.IntPtr)) return new PascalABCCompiler.SyntaxTree.named_type_reference(get_idents_from_dot_string("System.IntPtr", sem_type.location), sem_type.location); else if (sem_type is compiled_type_node ctn2 && ctn2.compiled_type == typeof(System.UIntPtr)) return new PascalABCCompiler.SyntaxTree.named_type_reference(get_idents_from_dot_string("System.UIntPtr", sem_type.location), sem_type.location); else if (sem_type is common_type_node && (sem_type as common_type_node).IsDelegate) { var tn = sem_type as common_type_node; var invokeMeth = tn.find_first_in_type("Invoke"); if (invokeMeth != null) { var fn = invokeMeth.sym_info as function_node; PascalABCCompiler.SyntaxTree.procedure_header header; if (fn.return_value_type != null) { header = new PascalABCCompiler.SyntaxTree.function_header(ConvertToSyntaxType(fn.return_value_type)); } else { header = new PascalABCCompiler.SyntaxTree.procedure_header(); } header.parameters = new PascalABCCompiler.SyntaxTree.formal_parameters(); foreach (var param in fn.parameters) { var tparam = new PascalABCCompiler.SyntaxTree.typed_parameters(); tparam.vars_type = ConvertToSyntaxType(param.type); tparam.idents = new PascalABCCompiler.SyntaxTree.ident_list(); tparam.idents.Add(new PascalABCCompiler.SyntaxTree.ident(param.name)); header.parameters.Add(tparam); } return header; } else return new PascalABCCompiler.SyntaxTree.named_type_reference(get_idents_from_dot_string(sem_type.PrintableName, sem_type.location), sem_type.location); } else return new PascalABCCompiler.SyntaxTree.named_type_reference(get_idents_from_dot_string(sem_type.PrintableName, sem_type.location), sem_type.location); } else if (sem_type.type_special_kind == SemanticTree.type_special_kind.array_kind || sem_type.type_special_kind == SemanticTree.type_special_kind.array_wrapper) { //значит тип-это массив SyntaxTree.array_type arr_t = new PascalABCCompiler.SyntaxTree.array_type(); arr_t.source_context = sem_type.location; // Cоздаем индексер для массива SyntaxTree.indexers_types indt = new PascalABCCompiler.SyntaxTree.indexers_types(); indt.source_context = arr_t.source_context; if (sem_type is common_type_node) { SyntaxTree.diapason diap = new PascalABCCompiler.SyntaxTree.diapason(); common_type_node ctn = sem_type as common_type_node; if (ctn.constants.Length > 1) { diap.left = ConvertConstant(ctn.constants[0].constant_value); diap.right = ConvertConstant(ctn.constants[1].constant_value); indt.indexers.Add(diap); } else { if (ctn.rank == 1) indt = null; else for (int i = 0; i < ctn.rank; i++) indt.indexers.Add(null); } arr_t.indexers = indt; } else if (sem_type is compiled_type_node) { compiled_type_node ctn = sem_type as compiled_type_node; if (ctn.rank > 1) { for (int i = 0; i < ctn.rank; i++) indt.indexers.Add(null); arr_t.indexers = indt; } //Получаем индексеры из строки //string ind_str = sem_type.PrintableName; //ind_str = get_indexer_string(ind_str); //if (ind_str.Length != 0) //{ // indt.indexers.AddRange(get_diapasons(ind_str).ToArray()); // arr_t.indexers = indt; //} } //проверяем тип элементов массива if (sem_type.element_type != null) { arr_t.elements_type = ConvertToSyntaxType(sem_type.element_type); } return arr_t; } else if (sem_type.type_special_kind == SemanticTree.type_special_kind.typed_file || sem_type.type_special_kind == SemanticTree.type_special_kind.binary_file) { SyntaxTree.file_type ft = new PascalABCCompiler.SyntaxTree.file_type(); ft.source_context = sem_type.location; if (sem_type.element_type != null) ft.file_of_type = ConvertToSyntaxType(sem_type.element_type); //SyntaxTree.named_type_reference ntr = null; //if (sem_type.element_type!= null) // ntr= new PascalABCCompiler.SyntaxTree.named_type_reference(get_idents_from_dot_string(sem_type.element_type.name)); //ft.file_of_type = ntr; return ft; } else if (sem_type.type_special_kind == PascalABCCompiler.SemanticTree.type_special_kind.short_string) { SyntaxTree.string_num_definition snd = new PascalABCCompiler.SyntaxTree.string_num_definition(); snd.source_context = sem_type.location; snd.name = new SyntaxTree.ident(sem_type.name.Substring(0, sem_type.name.IndexOf('['))); snd.num_of_symbols = new SyntaxTree.int32_const(Int32.Parse(get_indexer_string(sem_type.PrintableName))); return snd; } else if (sem_type.type_special_kind == PascalABCCompiler.SemanticTree.type_special_kind.set_type) { SyntaxTree.set_type_definition std = new PascalABCCompiler.SyntaxTree.set_type_definition(); std.source_context = sem_type.location; if (sem_type.element_type != null) std.of_type = ConvertToSyntaxType(sem_type.element_type); return std; } else if (sem_type.type_special_kind == SemanticTree.type_special_kind.diap_type) { return get_diapason(sem_type); } else if (sem_type.type_special_kind == SemanticTree.type_special_kind.enum_kind) return new SyntaxTree.semantic_type_node(sem_type); return null; } /// /// Возвращает ассоциативный массив диапазонов массива из синтаксического узла /// /// массив-синтаксический узел /// private static Dictionary> get_diapasons_from_array(SyntaxTree.array_type arr) { if (arr != null) { Dictionary> res = new Dictionary>(); int i = 0; while (true) { if (arr.indexers != null) { List diaps = new List(); foreach (SyntaxTree.type_definition td in arr.indexers.indexers) { if (td is SyntaxTree.diapason) diaps.Add(td as SyntaxTree.diapason); } res.Add(i, diaps); } if (arr.elements_type is SyntaxTree.array_type) arr = arr.elements_type as SyntaxTree.array_type; else break; i++; } return res; } return null; } /// /// Возвращает список диапазонов массива из синтаксического узла /// /// массив-синтаксический узел /// private static List> get_list_of_diapasons(SyntaxTree.array_type arr) { if (arr != null) { List> res = new List>(); while (true) { List diaps = new List(); if (arr.indexers != null) { foreach (SyntaxTree.type_definition td in arr.indexers.indexers) { diaps.Add(td as SyntaxTree.diapason); } } res.Add(diaps); if (arr.elements_type is SyntaxTree.array_type) arr = arr.elements_type as SyntaxTree.array_type; else break; } return res; } return null; } private static SyntaxTree.statement_list AssignArrs(SyntaxTree.array_type ArrFrom, SyntaxTree.addressed_value IdFrom, SyntaxTree.addressed_value IdTo) { SyntaxTree.statement_list OuterSTL = new PascalABCCompiler.SyntaxTree.statement_list(); SyntaxTree.statement_list InnerSTL = OuterSTL; List> DiapasonsList = get_list_of_diapasons(ArrFrom); List> IdentsList = new List>(); int VarNum = 0; if (DiapasonsList == null) DiapasonsList = new List>(); foreach (List Diapasons in DiapasonsList) { bool IsDynamicArray = false; List Lens = new List(); if ((Diapasons.Count == 0) || (Diapasons[0] == null)) { //массив динамический, нужно делать setlength IsDynamicArray = true; SyntaxTree.procedure_call SetLenPC = new PascalABCCompiler.SyntaxTree.procedure_call(); SyntaxTree.method_call SetLenMC = new PascalABCCompiler.SyntaxTree.method_call(); SetLenMC.dereferencing_value = new SyntaxTree.ident("SetLength"); SetLenPC.func_name = SetLenMC; SyntaxTree.expression_list SetLenParamsExl = new PascalABCCompiler.SyntaxTree.expression_list(); SetLenMC.parameters = SetLenParamsExl; //индексное выражение для массива-приемника SyntaxTree.addressed_value IndexerTo = IdTo; foreach (List Idents in IdentsList) { SyntaxTree.indexer InnerInd = new PascalABCCompiler.SyntaxTree.indexer(); InnerInd.dereferencing_value = IndexerTo; SyntaxTree.expression_list IndexersExl = new PascalABCCompiler.SyntaxTree.expression_list(); foreach (SyntaxTree.ident Ident in Idents) IndexersExl.expressions.Add(new SyntaxTree.ident(Ident.name)); InnerInd.indexes = IndexersExl; IndexerTo = InnerInd; } //индексное выражение для массива-источника SyntaxTree.addressed_value IndexerFrom = IdFrom; foreach (List Idents in IdentsList) { SyntaxTree.indexer InnerInd = new PascalABCCompiler.SyntaxTree.indexer(); InnerInd.dereferencing_value = IndexerFrom; SyntaxTree.expression_list IndexersExl = new PascalABCCompiler.SyntaxTree.expression_list(); foreach (SyntaxTree.ident Ident in Idents) IndexersExl.expressions.Add(new SyntaxTree.ident(Ident.name)); InnerInd.indexes = IndexersExl; IndexerFrom = InnerInd; } SetLenParamsExl.expressions.Add(IndexerTo); //List Lengths = new List(); if (Diapasons.Count == 0) { SyntaxTree.method_call LengthMC = new PascalABCCompiler.SyntaxTree.method_call(); LengthMC.dereferencing_value = new SyntaxTree.ident("Length"); SyntaxTree.expression_list LenMCExl = new PascalABCCompiler.SyntaxTree.expression_list(); LengthMC.parameters = LenMCExl; LenMCExl.expressions.Add(IndexerFrom); SetLenParamsExl.expressions.Add(LengthMC); Lens.Add(LengthMC); } else { for (int i = 0; i < Diapasons.Count; ++i) { SyntaxTree.method_call LengthMC = new PascalABCCompiler.SyntaxTree.method_call(); LengthMC.dereferencing_value = new SyntaxTree.ident("Length"); SyntaxTree.expression_list LenMCExl = new PascalABCCompiler.SyntaxTree.expression_list(); LengthMC.parameters = LenMCExl; LenMCExl.expressions.Add(IndexerFrom); LenMCExl.expressions.Add(new SyntaxTree.int32_const(i)); SetLenParamsExl.expressions.Add(LengthMC); Lens.Add(LengthMC); } } InnerSTL.subnodes.Add(SetLenPC); } //к этому моменту вызов SetLength с параметрами сформирован //в Lens содержатся вызовы length по нужной размерности если массив динамический //теперь нужно создать циклы for и список переменных, по которым идут циклы List LoopIdents = new List(); for (int i = 0; i < Math.Max(Diapasons.Count, 1); ++i) { SyntaxTree.for_node ForNode = new PascalABCCompiler.SyntaxTree.for_node(); SyntaxTree.ident LoopVar = new PascalABCCompiler.SyntaxTree.ident("$i" + (VarNum++).ToString()); LoopIdents.Add(LoopVar); ForNode.loop_variable = LoopVar; ForNode.create_loop_variable = true; if (IsDynamicArray) { ForNode.initial_value = new SyntaxTree.int32_const(0); ForNode.finish_value = new PascalABCCompiler.SyntaxTree.bin_expr(Lens[i], new SyntaxTree.int32_const(1), PascalABCCompiler.SyntaxTree.Operators.Minus); } else { ForNode.initial_value = Diapasons[i].left; ForNode.finish_value = Diapasons[i].right; } InnerSTL.subnodes.Add(ForNode); ForNode.statements = new PascalABCCompiler.SyntaxTree.statement_list(); InnerSTL = ForNode.statements as SyntaxTree.statement_list; } IdentsList.Add(LoopIdents); } // к этому моменту создано гнездо циклов с установкой длины динамических массивов и перебором // вообще всех массивов. Осталось создать самое внутреннее присваивание SyntaxTree.addressed_value AssignIndexerFrom = IdFrom; SyntaxTree.addressed_value AssignIndexerTo = IdTo; foreach (List AssignIdents in IdentsList) { SyntaxTree.indexer FromIndexer = new PascalABCCompiler.SyntaxTree.indexer(); SyntaxTree.indexer ToIndexer = new PascalABCCompiler.SyntaxTree.indexer(); FromIndexer.dereferencing_value = AssignIndexerFrom; ToIndexer.dereferencing_value = AssignIndexerTo; SyntaxTree.expression_list Exl = new PascalABCCompiler.SyntaxTree.expression_list(); foreach (SyntaxTree.ident id in AssignIdents) Exl.expressions.Add(id); FromIndexer.indexes = Exl; ToIndexer.indexes = Exl; AssignIndexerFrom = FromIndexer; AssignIndexerTo = ToIndexer; } SyntaxTree.assign Assign = new PascalABCCompiler.SyntaxTree.assign(); Assign.from = AssignIndexerFrom; Assign.to = AssignIndexerTo; Assign.operator_type = PascalABCCompiler.SyntaxTree.Operators.Assignment; InnerSTL.subnodes.Add(Assign); return OuterSTL; } /// /// По списку диапазонов, определяет динаимеческий или нет. Если нет, то возвращает в ind номер первого непустого диапазона /// /// Ассоциативный массив диапазонов /// выходной параметр - индекс непустого дипазона. Если динамический массив, то возвращает -1 /// private static bool is_dyn_arr(SyntaxTree.array_type arr) { Dictionary> diaps = get_diapasons_from_array(arr); if (diaps == null) return true; foreach (int key in diaps.Keys) { foreach (SyntaxTree.diapason d in diaps[key]) if (d != null) { return false; } } return true; } private static SyntaxTree.type_declarations CreateClass(string ClassName,out SyntaxTree.class_members ClassMember, VarInfoContainer Vars) { //генерация класса SyntaxTree.type_declarations TypeDecls = new PascalABCCompiler.SyntaxTree.type_declarations(); SyntaxTree.type_declaration TypeDecl = new PascalABCCompiler.SyntaxTree.type_declaration(); TypeDecls.types_decl.Add(TypeDecl); TypeDecl.type_name = new PascalABCCompiler.SyntaxTree.ident(ClassName); SyntaxTree.class_definition ClassDef = new PascalABCCompiler.SyntaxTree.class_definition(); TypeDecl.type_def = ClassDef; SyntaxTree.class_body_list ClassBody = new PascalABCCompiler.SyntaxTree.class_body_list(); ClassDef.body = ClassBody; ClassMember = new PascalABCCompiler.SyntaxTree.class_members(); ClassBody.class_def_blocks.Add(ClassMember); ClassMember.access_mod = new PascalABCCompiler.SyntaxTree.access_modifer_node(PascalABCCompiler.SyntaxTree.access_modifer.public_modifer); // генерация полей класса // shared переменные for (int i = 0; i < Vars.SharedVariables.Count; ++i) ClassMember.members.Add(CreateClassMember(Vars.SharedVariables[i], "")); // переменные редукции - с долларовым префиксом for (int i = 0; i < Vars.ReductionVariables.Count; ++i) ClassMember.members.Add(CreateClassMember(Vars.ReductionVariables[i], "$")); return TypeDecls; } private static SyntaxTree.procedure_definition CreateMethod(string MethodName, SyntaxTree.statement Body, string LoopVariableName, SyntaxTree.class_members ClassMember, VarInfoContainer Vars) { // генерация метода SyntaxTree.procedure_definition ProcDef = new PascalABCCompiler.SyntaxTree.procedure_definition(); //ClassMember.members.Add(ProcDef); SyntaxTree.procedure_header ProcHead = new PascalABCCompiler.SyntaxTree.procedure_header(); ProcDef.proc_header = ProcHead; ProcHead.name = new PascalABCCompiler.SyntaxTree.method_name(null, null, new PascalABCCompiler.SyntaxTree.ident(MethodName), null); if (LoopVariableName != "") { // параметр, счетчик цикла string ParamType = "integer"; SyntaxTree.formal_parameters FormalParams = new PascalABCCompiler.SyntaxTree.formal_parameters(); ProcHead.parameters = FormalParams; SyntaxTree.typed_parameters TypedParams = new PascalABCCompiler.SyntaxTree.typed_parameters(); FormalParams.params_list.Add(TypedParams); SyntaxTree.ident_list idl = new PascalABCCompiler.SyntaxTree.ident_list(); TypedParams.idents = idl; idl.Add(new SyntaxTree.ident(LoopVariableName)); SyntaxTree.named_type_reference ntr = new PascalABCCompiler.SyntaxTree.named_type_reference(); TypedParams.vars_type = ntr; ntr.Add(new SyntaxTree.ident(ParamType)); } SyntaxTree.block ProcBlock = new PascalABCCompiler.SyntaxTree.block(); ProcDef.proc_body = ProcBlock; ProcBlock.defs = new PascalABCCompiler.SyntaxTree.declarations(); if (Vars.Constants.Count > 0) { SyntaxTree.consts_definitions_list cdl = new PascalABCCompiler.SyntaxTree.consts_definitions_list(); ProcBlock.defs.defs.Add(cdl); // константы - в методе for (int i = 0; i < Vars.Constants.Count; ++i) cdl.Add(CreateClassMember(Vars.Constants[i], "") as SyntaxTree.typed_const_definition); } if ((Vars.ReductionVariables.Count > 0) || (Vars.PrivateVariables.Count > 0)) { // переменные редукции - в методе тоже, но без префикса SyntaxTree.variable_definitions vds = new PascalABCCompiler.SyntaxTree.variable_definitions(); ProcBlock.defs.defs.Add(vds); for (int i = 0; i < Vars.ReductionVariables.Count; ++i) vds.Add(CreateClassMember(Vars.ReductionVariables[i], "") as SyntaxTree.var_def_statement); // и приватные переменные for (int i = 0; i < Vars.PrivateVariables.Count; ++i) vds.Add(CreateClassMember(Vars.PrivateVariables[i], "") as SyntaxTree.var_def_statement); } if (Body is SyntaxTree.statement_list) ProcBlock.program_code = Body as SyntaxTree.statement_list; else { SyntaxTree.statement_list stl = new PascalABCCompiler.SyntaxTree.statement_list(); stl.subnodes.Add(Body); ProcBlock.program_code = stl; } //присваивания для переменных редукции if (Vars.ReductionVariables.Count > 0) { SyntaxTree.statement_list LoopBodyInit = new PascalABCCompiler.SyntaxTree.statement_list(); SyntaxTree.statement_list LoopBodyFinal = new PascalABCCompiler.SyntaxTree.statement_list(); for (int i = 0; i < Vars.ReductionVariables.Count; ++i) { //присваивание начального значения SyntaxTree.assign Assign = new PascalABCCompiler.SyntaxTree.assign(); Assign.operator_type = PascalABCCompiler.SyntaxTree.Operators.Assignment; Assign.to = new SyntaxTree.ident(Vars.ReductionVariables[i].name); bool isBool = Vars.ReductionVariables[i].type.name.ToLower() == "boolean"; switch (Vars.ReductionActions[i]) { case ReductionOperations.and: { if (isBool) Assign.from = new SyntaxTree.bool_const(true); else { //отрицание нуля Assign.from = new SyntaxTree.int32_const(0); LoopBodyInit.subnodes.Add(Assign); Assign = new PascalABCCompiler.SyntaxTree.assign(); Assign.operator_type = PascalABCCompiler.SyntaxTree.Operators.Assignment; Assign.to = new SyntaxTree.ident(Vars.ReductionVariables[i].name); SyntaxTree.un_expr ue = new PascalABCCompiler.SyntaxTree.un_expr(); ue.operation_type = PascalABCCompiler.SyntaxTree.Operators.LogicalNOT; ue.subnode = new SyntaxTree.ident(Vars.ReductionVariables[i].name); Assign.from = ue; } break; } case ReductionOperations.or: if (isBool) Assign.from = new SyntaxTree.bool_const(false); else { Assign.from = new SyntaxTree.int32_const(0); } break; case ReductionOperations.xor: // case ReductionOperations.plus: //см следующую ветку case ReductionOperations.minus: Assign.from = new SyntaxTree.int32_const(0); break; case ReductionOperations.mult: Assign.from = new SyntaxTree.int32_const(1); break; } LoopBodyInit.Add(Assign); //присваивание после итерации Assign = new PascalABCCompiler.SyntaxTree.assign(); Assign.operator_type = PascalABCCompiler.SyntaxTree.Operators.Assignment; Assign.to = new SyntaxTree.ident("$" + Vars.ReductionVariables[i].name); SyntaxTree.bin_expr From = new PascalABCCompiler.SyntaxTree.bin_expr(); From.left = new SyntaxTree.ident("$" + Vars.ReductionVariables[i].name); From.right = new SyntaxTree.ident(Vars.ReductionVariables[i].name); Assign.from = From; switch (Vars.ReductionActions[i]) { case ReductionOperations.and: From.operation_type = PascalABCCompiler.SyntaxTree.Operators.LogicalAND; break; case ReductionOperations.or: From.operation_type = PascalABCCompiler.SyntaxTree.Operators.LogicalOR; break; case ReductionOperations.xor: From.operation_type = PascalABCCompiler.SyntaxTree.Operators.BitwiseXOR; break; case ReductionOperations.plus: From.operation_type = PascalABCCompiler.SyntaxTree.Operators.Plus; break; case ReductionOperations.minus: From.operation_type = PascalABCCompiler.SyntaxTree.Operators.Minus; break; case ReductionOperations.mult: From.operation_type = PascalABCCompiler.SyntaxTree.Operators.Multiplication; break; } LoopBodyFinal.Add(Assign); } //создаем обьект для блокировки в классе SyntaxTree.var_def_statement Lvds = new PascalABCCompiler.SyntaxTree.var_def_statement(); SyntaxTree.ident_list Lidl = new PascalABCCompiler.SyntaxTree.ident_list(); Lvds.vars = Lidl; Lidl.Add(new SyntaxTree.ident("$ReductionLock")); SyntaxTree.named_type_reference Lntr = new PascalABCCompiler.SyntaxTree.named_type_reference(); Lvds.vars_type = Lntr; Lntr.Add(new SyntaxTree.ident("object")); SyntaxTree.new_expr Lne = new PascalABCCompiler.SyntaxTree.new_expr(); Lvds.inital_value = Lne; Lne.type = Lntr; ClassMember.members.Add(Lvds); //создаем lock Statement на обьекте с присваиваниями в конце итерации SyntaxTree.lock_stmt reductionLock = new PascalABCCompiler.SyntaxTree.lock_stmt(); reductionLock.lock_object = new SyntaxTree.ident("$ReductionLock"); reductionLock.stmt = LoopBodyFinal; //собираем все вместе и присваиваем это телу процедуры LoopBodyInit.subnodes.AddRange(ProcBlock.program_code.subnodes); LoopBodyInit.subnodes.Add(reductionLock); ProcBlock.program_code = LoopBodyInit; } return ProcDef; } private static SyntaxTree.declaration CreateClassMember(SemanticTree.IDefinitionNode Def, string Prefix) { if (Def is SemanticTree.IConstantDefinitionNode) { SemanticTree.IConstantDefinitionNode ConstDef = Def as SemanticTree.IConstantDefinitionNode; SyntaxTree.typed_const_definition tcd = new PascalABCCompiler.SyntaxTree.typed_const_definition(); tcd.const_name = new PascalABCCompiler.SyntaxTree.ident(Prefix + ConstDef.name); tcd.const_type = ConvertToSyntaxType(ConstDef.type as type_node); tcd.const_value = ConvertConstant(ConstDef.constant_value); return tcd; } else { SemanticTree.IVAriableDefinitionNode VarDef = Def as SemanticTree.IVAriableDefinitionNode; SyntaxTree.var_def_statement vds = new PascalABCCompiler.SyntaxTree.var_def_statement(); SyntaxTree.ident_list idl = new PascalABCCompiler.SyntaxTree.ident_list(); vds.vars = idl; idl.Add(new SyntaxTree.ident(Prefix + VarDef.name)); vds.vars_type = ConvertToSyntaxType(VarDef.type as type_node); return vds; } } private static SyntaxTree.statement_list CreateInitPart(string ClassName, string ObjName, VarInfoContainer Vars) { SyntaxTree.statement_list stl = new PascalABCCompiler.SyntaxTree.statement_list(); //Var Statement - объявление экземпляра обьекта-функции SyntaxTree.var_statement ClassVar = new PascalABCCompiler.SyntaxTree.var_statement(); stl.subnodes.Add(ClassVar); SyntaxTree.var_def_statement ClassVarDef = new PascalABCCompiler.SyntaxTree.var_def_statement(); ClassVar.var_def = ClassVarDef; SyntaxTree.ident_list ClassIdl = new PascalABCCompiler.SyntaxTree.ident_list(); ClassVarDef.vars = ClassIdl; ClassIdl.idents.Add(new PascalABCCompiler.SyntaxTree.ident(ObjName)); SyntaxTree.named_type_reference ClassTypeNTR = new PascalABCCompiler.SyntaxTree.named_type_reference(); ClassVarDef.vars_type = ClassTypeNTR; ClassTypeNTR.names.Add(new PascalABCCompiler.SyntaxTree.ident(ClassName)); SyntaxTree.new_expr ClassInitNE = new PascalABCCompiler.SyntaxTree.new_expr(); ClassVarDef.inital_value = ClassInitNE; SyntaxTree.named_type_reference ClassInitNTR = new PascalABCCompiler.SyntaxTree.named_type_reference(); ClassInitNE.type = ClassInitNTR; ClassInitNTR.names.Add(new PascalABCCompiler.SyntaxTree.ident(ClassName)); //создаем присваивания разделяемым переменным for (int i = 0; i < Vars.SharedVariables.Count; ++i) { string VarName = Vars.SharedVariables[i].name; SyntaxTree.dot_node DotNode = new PascalABCCompiler.SyntaxTree.dot_node(); DotNode.left = new SyntaxTree.ident(ObjName); DotNode.right = new SyntaxTree.ident(VarName); SyntaxTree.array_type arrType = ConvertToSyntaxType(Vars.SharedVariables[i].type as type_node) as SyntaxTree.array_type; if (arrType != null && !is_dyn_arr(arrType)) { stl.subnodes.Add(AssignArrs(arrType, new SyntaxTree.ident(VarName), DotNode)); } else { SyntaxTree.assign Assign = new PascalABCCompiler.SyntaxTree.assign(); Assign.operator_type = PascalABCCompiler.SyntaxTree.Operators.Assignment; Assign.from = new SyntaxTree.ident(VarName); Assign.to = DotNode; stl.subnodes.Add(Assign); } } //создаем присваивания переменным редукции for (int i = 0; i < Vars.ReductionVariables.Count; ++i) { string VarName = Vars.ReductionVariables[i].name; SyntaxTree.dot_node DotNode = new PascalABCCompiler.SyntaxTree.dot_node(); DotNode.left = new SyntaxTree.ident(ObjName); DotNode.right = new SyntaxTree.ident("$" + VarName); SyntaxTree.array_type arrType = ConvertToSyntaxType(Vars.ReductionVariables[i].type as type_node) as SyntaxTree.array_type; if (arrType != null && !is_dyn_arr(arrType)) { stl.subnodes.Add(AssignArrs(arrType, new SyntaxTree.ident(VarName), DotNode)); } else { SyntaxTree.assign Assign = new PascalABCCompiler.SyntaxTree.assign(); Assign.operator_type = PascalABCCompiler.SyntaxTree.Operators.Assignment; Assign.from = new SyntaxTree.ident(VarName); Assign.to = DotNode; stl.subnodes.Add(Assign); } } return stl; } private static SyntaxTree.statement_list CreateFinalPart(string ObjName, VarInfoContainer Vars) { SyntaxTree.statement_list stl = new PascalABCCompiler.SyntaxTree.statement_list(); //создаем присваивания разделяемым переменным for (int i = 0; i < Vars.SharedVariables.Count; ++i) { string VarName = Vars.SharedVariables[i].name; if (LoopVariables.Contains(VarName.ToLower())) continue; SyntaxTree.dot_node DotNode = new PascalABCCompiler.SyntaxTree.dot_node(); DotNode.left = new SyntaxTree.ident(ObjName); DotNode.right = new SyntaxTree.ident(VarName); SyntaxTree.array_type arrType = ConvertToSyntaxType(Vars.SharedVariables[i].type as type_node) as SyntaxTree.array_type; if (arrType != null && !is_dyn_arr(arrType)) { stl.subnodes.Add(AssignArrs(arrType, DotNode, new SyntaxTree.ident(VarName))); } else { SyntaxTree.assign Assign = new PascalABCCompiler.SyntaxTree.assign(); Assign.operator_type = PascalABCCompiler.SyntaxTree.Operators.Assignment; Assign.to = new SyntaxTree.ident(VarName); Assign.from = DotNode; stl.subnodes.Add(Assign); } } //создаем присваивания переменным редукции for (int i = 0; i < Vars.ReductionVariables.Count; ++i) { string VarName = Vars.ReductionVariables[i].name; SyntaxTree.dot_node DotNode = new PascalABCCompiler.SyntaxTree.dot_node(); DotNode.left = new SyntaxTree.ident(ObjName); DotNode.right = new SyntaxTree.ident("$" + VarName); SyntaxTree.array_type arrType = ConvertToSyntaxType(Vars.ReductionVariables[i].type as type_node) as SyntaxTree.array_type; if (arrType != null && !is_dyn_arr(arrType)) { stl.subnodes.Add(AssignArrs(arrType, DotNode, new SyntaxTree.ident(VarName))); } else { SyntaxTree.assign Assign = new PascalABCCompiler.SyntaxTree.assign(); Assign.operator_type = PascalABCCompiler.SyntaxTree.Operators.Assignment; Assign.to = new SyntaxTree.ident(VarName); Assign.from = DotNode; stl.subnodes.Add(Assign); } } return stl; } private static SyntaxTree.procedure_call CreateOMPParallelForCall(SyntaxTree.dot_node dn, SyntaxTree.expression FromInclusive, SyntaxTree.expression ToInclusive) { SyntaxTree.procedure_call pc = new PascalABCCompiler.SyntaxTree.procedure_call(); SyntaxTree.method_call mc = new PascalABCCompiler.SyntaxTree.method_call(); pc.func_name = mc; mc.dereferencing_value = CreateTPLFunctionReference("For"); //Здесь прибавляем единицу ко второму параметру, так как в паскале верхняя граница включается, а в parallel.for - нет SyntaxTree.bin_expr ToExclusive = new SyntaxTree.bin_expr(); ToExclusive.left = ToInclusive; ToExclusive.right = new SyntaxTree.int32_const(1); ToExclusive.operation_type = SyntaxTree.Operators.Plus; mc.parameters = new PascalABCCompiler.SyntaxTree.expression_list(); mc.parameters.Add(FromInclusive); mc.parameters.Add(ToExclusive); mc.parameters.Add(dn); return pc; } private static if_node CreateIfCondition(syntax_tree_visitor syntax_tree_visitor, statements_list ifthen, statements_list ifelse, location loc) { //сохраняем контекст ContextInfo contextInfo = new ContextInfo(syntax_tree_visitor); if_node res = null; try { SyntaxTree.if_node if_node = new PascalABCCompiler.SyntaxTree.if_node(); SyntaxTree.un_expr une = new PascalABCCompiler.SyntaxTree.un_expr(); une.operation_type = SyntaxTree.Operators.LogicalNOT; une.subnode = new SyntaxTree.ident(InParallelSection); if_node.condition = une; if_node.then_body = new SyntaxTree.empty_statement(); if_node.then_body = new SyntaxTree.empty_statement(); res = syntax_tree_visitor.convert_strong(if_node) as if_node; res.then_body = ifthen; res.else_body = ifelse; res.location = loc; } finally { //восстанавливаем контекст contextInfo.RestoreContext(syntax_tree_visitor); } return res; } private static SyntaxTree.dot_node CreateTPLFunctionReference(string FunctionName) { //Создаем конструкцию вида "System.Threading.Tasks.Parallel." SyntaxTree.dot_node dn1 = new SyntaxTree.dot_node(); dn1.left = new SyntaxTree.ident("System"); dn1.right = new SyntaxTree.ident("Threading"); SyntaxTree.dot_node dn2 = new SyntaxTree.dot_node(); dn2.right = new SyntaxTree.ident("Tasks"); dn2.left = dn1; SyntaxTree.dot_node dn3 = new SyntaxTree.dot_node(); dn3.right = new SyntaxTree.ident("Parallel"); dn3.left = dn2; SyntaxTree.dot_node Result = new SyntaxTree.dot_node(); Result.right = new SyntaxTree.ident(FunctionName); Result.left = dn3; return Result; } private static void CreateInParallelVariable(syntax_tree_visitor syntax_tree_visitor, out string VarName) { //сохраняем контекст ContextInfo contextInfo = new ContextInfo(syntax_tree_visitor); VarName = "$InParallelSection"; try { //создание и конвертирование переменной SyntaxTree.var_def_statement vds = new PascalABCCompiler.SyntaxTree.var_def_statement(); SyntaxTree.variable_definitions var_def = new PascalABCCompiler.SyntaxTree.variable_definitions(vds, null); SyntaxTree.ident_list idl = new PascalABCCompiler.SyntaxTree.ident_list(); vds.vars = idl; idl.Add(new SyntaxTree.ident(VarName)); SyntaxTree.named_type_reference ntr = new PascalABCCompiler.SyntaxTree.named_type_reference(); vds.vars_type = ntr; ntr.names.Add(new PascalABCCompiler.SyntaxTree.ident("boolean")); vds.inital_value = new PascalABCCompiler.SyntaxTree.ident("false"); syntax_tree_visitor.visit(var_def); } finally { //восстанавливаем контекст contextInfo.RestoreContext(syntax_tree_visitor); } InParallelSectionCreated = true; } private static SyntaxTree.if_node CreateNestedRegionBorder(bool ifEnter) { SyntaxTree.if_node result = new PascalABCCompiler.SyntaxTree.if_node(); SyntaxTree.un_expr ue = new PascalABCCompiler.SyntaxTree.un_expr(); ue.operation_type = PascalABCCompiler.SyntaxTree.Operators.LogicalNOT; ue.subnode = new SyntaxTree.ident(StringConstants.OMP_NESTED); result.condition = ue; SyntaxTree.assign AssignInParVar = new PascalABCCompiler.SyntaxTree.assign(); AssignInParVar.operator_type = PascalABCCompiler.SyntaxTree.Operators.Assignment; AssignInParVar.from = new SyntaxTree.ident(ifEnter ? "true" : "false"); AssignInParVar.to = new SyntaxTree.ident(InParallelSection); result.then_body = AssignInParVar; return result; } private static SyntaxTree.expression ConvertConstant(SemanticTree.IConstantNode value) { if (value is bool_const_node) return new SyntaxTree.ident((value as bool_const_node).constant_value ? "true" : "false"); else if (value is null_const_node) return new SyntaxTree.nil_const(); else if (value is byte_const_node) return new SyntaxTree.int32_const((value as byte_const_node).constant_value); else if (value is char_const_node) return new SyntaxTree.char_const((value as char_const_node).constant_value); else if (value is double_const_node) return new SyntaxTree.double_const((value as double_const_node).constant_value); else if (value is float_const_node) return new SyntaxTree.double_const((value as float_const_node).constant_value); else if (value is int_const_node) return new SyntaxTree.int32_const((value as int_const_node).constant_value); else if (value is long_const_node) return new SyntaxTree.int64_const((value as long_const_node).constant_value); else if (value is sbyte_const_node) return new SyntaxTree.int32_const((value as sbyte_const_node).constant_value); else if (value is short_const_node) return new SyntaxTree.int32_const((value as short_const_node).constant_value); else if (value is uint_const_node) return new SyntaxTree.uint64_const((value as uint_const_node).constant_value); else if (value is ulong_const_node) return new SyntaxTree.uint64_const((value as ulong_const_node).constant_value); else if (value is ushort_const_node) return new SyntaxTree.int32_const((value as ushort_const_node).constant_value); else if (value is string_const_node) return new SyntaxTree.string_const((value as string_const_node).constant_value); else if (value is array_const) { array_const ac = value as array_const; SyntaxTree.expression_list el = new PascalABCCompiler.SyntaxTree.expression_list(); for (int i = 0; i < ac.element_values.Count; ++i) el.Add(ConvertConstant(ac.element_values[i])); SyntaxTree.array_const synAC = new PascalABCCompiler.SyntaxTree.array_const(); synAC.elements = el; return synAC; } else if (value is enum_const_node) { //Есть сомнения, что будет работать во всех случаях enum_const_node ec = value as enum_const_node; SyntaxTree.ident r = new SyntaxTree.ident((ec.type as common_type_node).const_defs[ec.constant_value].name); SyntaxTree.ident l = new SyntaxTree.ident(ec.type.name); return new SyntaxTree.dot_node(l, r); } else if (value is record_constant) { record_constant rc = value as record_constant; SyntaxTree.record_const synRC = new PascalABCCompiler.SyntaxTree.record_const(); for (int i = 0; i < rc.field_values.Count; ++i) { SyntaxTree.record_const_definition rcd = new PascalABCCompiler.SyntaxTree.record_const_definition(); rcd.name = rc.record_const_definition_list[i].name; rcd.val = rc.record_const_definition_list[i].val; synRC.rec_consts.Add(rcd); } return synRC; } else throw new Exception("Не реализовано"); //выяснить, что тут может быть } /// /// выдает свободное имя /// /// шаблон /// перебирать имена, приписывая к шаблону числа начиная с этой позиции. После того как найдет - возвращает следующее число /// контекст, в котором искать /// первое свободное имя private static string GetFreeName(string template, ref int StartFrom, compilation_context context) { string name; while (context.CurrentScope.Find((name = string.Format(template + StartFrom.ToString(), StartFrom++))) != null) ; return name; } private static VarInfoContainer GetVarInfoContainer(VarFinderSyntaxVisitor VFVis, List Reductions, List PrivateVars, syntax_tree_visitor visitor, SyntaxTree.compiler_directive dir) { if (Reductions == null) Reductions = new List(); if (PrivateVars == null) PrivateVars = new List(); VarInfoContainer Result = new VarInfoContainer(); //константы копируются сразу Result.Constants = VFVis.Constants; //список переменных для редукции //ищем переменные с такими именами, проверяем их наличие, тип и если все хорошо - добавляем в список foreach (ReductionDirective rd in Reductions) foreach (string rdVarName in rd.variables) { if (LoopVariables.Contains(rdVarName)) { visitor.AddWarning(new PascalABCCompiler.Errors.CommonWarning(String.Format(PascalABCCompiler.StringResources.Get("OMPERROR_REDUCTION_WITH_LOOPVAR_{0}"), rdVarName), visitor.CurrentDocument, dir.source_context.begin_position.line_num, dir.source_context.begin_position.column_num)); continue; } SymbolInfo si = visitor.context.find_first(rdVarName); if (si == null) { visitor.AddWarning(new PascalABCCompiler.Errors.CommonWarning(String.Format(PascalABCCompiler.StringResources.Get("OMPERROR_UNKNOWN_VARNAME_{0}"), rdVarName), visitor.CurrentDocument, dir.source_context.begin_position.line_num, dir.source_context.begin_position.column_num)); continue; } if (!(si.sym_info is SemanticTree.IVAriableDefinitionNode)) { visitor.AddWarning(new PascalABCCompiler.Errors.CommonWarning(String.Format(PascalABCCompiler.StringResources.Get("OMPERROR_NAME_IS_NOT_VAR_{0}"), rdVarName), visitor.CurrentDocument, dir.source_context.begin_position.line_num, dir.source_context.begin_position.column_num)); continue; } if (!IsValidVarForReduction(si.sym_info as SemanticTree.IVAriableDefinitionNode)) { visitor.AddWarning(new PascalABCCompiler.Errors.CommonWarning(String.Format(PascalABCCompiler.StringResources.Get("OMPERROR_IS_NOT_POSSIBLE_REDUCTION_WITH_THIS_VAR_{0}"), rdVarName), visitor.CurrentDocument, dir.source_context.begin_position.line_num, dir.source_context.begin_position.column_num)); continue; } Result.ReductionVariables.Add(si.sym_info as SemanticTree.IVAriableDefinitionNode); Result.ReductionActions.Add(rd.Oper); //for (int i = 0; i < VFVis.Variables.Count; ++i) // if (VFVis.Variables[i].name.ToLower() == rdVarName.ToLower()) // { // Result.ReductionVariables.Add(VFVis.Variables[i]); // Result.ReductionActions.Add(rd.Oper); // break; // } } //приватные переменные - аналогично, но без проверки на тип foreach (string privateVar in PrivateVars) { SymbolInfo si = visitor.context.find_first(privateVar); if (si == null) { visitor.AddWarning(new PascalABCCompiler.Errors.CommonWarning(String.Format(PascalABCCompiler.StringResources.Get("OMPERROR_UNKNOWN_VARNAME_{0}"), privateVar), visitor.CurrentDocument, dir.source_context.begin_position.line_num, dir.source_context.begin_position.column_num)); continue; } if (!(si.sym_info is SemanticTree.IVAriableDefinitionNode)) { visitor.AddWarning(new PascalABCCompiler.Errors.CommonWarning(String.Format(PascalABCCompiler.StringResources.Get("OMPERROR_NAME_IS_NOT_VAR_{0}"), privateVar), visitor.CurrentDocument, dir.source_context.begin_position.line_num, dir.source_context.begin_position.column_num)); continue; } Result.PrivateVariables.Add(si.sym_info as SemanticTree.IVAriableDefinitionNode); } //по всем переменным: //если она не приватная и по ней нет редукции - переписываем ее в список разделяемых foreach (SemanticTree.IVAriableDefinitionNode var in VFVis.Variables) { bool NotShared = false; foreach (SemanticTree.IVAriableDefinitionNode rdn in Result.ReductionVariables) if (rdn.name.ToLower() == var.name.ToLower()) { NotShared = true; break; } if (!NotShared) foreach (SemanticTree.IVAriableDefinitionNode prVar in Result.PrivateVariables) if (prVar.name.ToLower() == var.name.ToLower()) { NotShared = true; break; } if (!NotShared) Result.SharedVariables.Add(var); } return Result; } private static bool IsValidVarForReduction(SemanticTree.IVAriableDefinitionNode var) { //допустимые типы: //shortint byte smallint word integer longword int64 uint64 single real //+ страховка на случай наличия записей вида "type integer = object" if (var.type.type_special_kind != PascalABCCompiler.SemanticTree.type_special_kind.none_kind) return false; if (var.type.is_class) return false; return ((var.type.name.ToLower() == "shortint") || (var.type.name.ToLower() == "byte") || (var.type.name.ToLower() == "smallint") || (var.type.name.ToLower() == "integer") || (var.type.name.ToLower() == "longword") || (var.type.name.ToLower() == "word") || (var.type.name.ToLower() == "int64") || (var.type.name.ToLower() == "uint64") || (var.type.name.ToLower() == "single") || (var.type.name.ToLower() == "real") || (var.type.name.ToLower() == "boolean")); } #endregion } }