diff --git a/Configuration/GlobalAssemblyInfo.cs b/Configuration/GlobalAssemblyInfo.cs index 53c76f753..6f13585a9 100644 --- a/Configuration/GlobalAssemblyInfo.cs +++ b/Configuration/GlobalAssemblyInfo.cs @@ -15,7 +15,7 @@ internal static class RevisionClass public const string Major = "2"; public const string Minor = "2"; public const string Build = "0"; - public const string Revision = "966"; + public const string Revision = "967"; public const string MainVersion = Major + "." + Minor; public const string FullVersion = Major + "." + Minor + "." + Build + "." + Revision; diff --git a/Configuration/Version.defs b/Configuration/Version.defs index 254e7f2e2..4e420c509 100644 --- a/Configuration/Version.defs +++ b/Configuration/Version.defs @@ -1,4 +1,4 @@ %MINOR%=2 -%REVISION%=966 +%REVISION%=967 %MAJOR%=2 %COREVERSION%=0 diff --git a/ReleaseGenerators/PascalABCNET_version.nsh b/ReleaseGenerators/PascalABCNET_version.nsh index f8c538b6e..c13c7cd4f 100644 --- a/ReleaseGenerators/PascalABCNET_version.nsh +++ b/ReleaseGenerators/PascalABCNET_version.nsh @@ -1 +1 @@ -!define VERSION '2.2.0.966' \ No newline at end of file +!define VERSION '2.2.0.967' \ No newline at end of file diff --git a/_ParsePABC1/ParsePABC1.sln b/_ParsePABC1/ParsePABC1.sln new file mode 100644 index 000000000..16eaf8ac5 --- /dev/null +++ b/_ParsePABC1/ParsePABC1.sln @@ -0,0 +1,34 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 2013 +VisualStudioVersion = 12.0.21005.1 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ParsePABC1", "ParsePABC1\ParsePABC1.csproj", "{BAA767F1-6544-4A44-BA17-5FBFCF6F2D99}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SyntaxTree", "..\..\PascalABC.NET\!PABC_Git\SyntaxTree\SyntaxTree.csproj", "{C2CAC65A-B2AE-4CCC-B067-E6B8E75DF73A}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CodeCompletion", "..\..\PascalABC.NET\!PABC_Git\CodeCompletion\CodeCompletion.csproj", "{1AB15F6E-C22E-499A-A7ED-54BA7DE5CFA6}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {BAA767F1-6544-4A44-BA17-5FBFCF6F2D99}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {BAA767F1-6544-4A44-BA17-5FBFCF6F2D99}.Debug|Any CPU.Build.0 = Debug|Any CPU + {BAA767F1-6544-4A44-BA17-5FBFCF6F2D99}.Release|Any CPU.ActiveCfg = Release|Any CPU + {BAA767F1-6544-4A44-BA17-5FBFCF6F2D99}.Release|Any CPU.Build.0 = Release|Any CPU + {C2CAC65A-B2AE-4CCC-B067-E6B8E75DF73A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {C2CAC65A-B2AE-4CCC-B067-E6B8E75DF73A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {C2CAC65A-B2AE-4CCC-B067-E6B8E75DF73A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {C2CAC65A-B2AE-4CCC-B067-E6B8E75DF73A}.Release|Any CPU.Build.0 = Release|Any CPU + {1AB15F6E-C22E-499A-A7ED-54BA7DE5CFA6}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {1AB15F6E-C22E-499A-A7ED-54BA7DE5CFA6}.Debug|Any CPU.Build.0 = Debug|Any CPU + {1AB15F6E-C22E-499A-A7ED-54BA7DE5CFA6}.Release|Any CPU.ActiveCfg = Release|Any CPU + {1AB15F6E-C22E-499A-A7ED-54BA7DE5CFA6}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/_ParsePABC1/ParsePABC1/AllVarsInProcYieldsProba.cs b/_ParsePABC1/ParsePABC1/AllVarsInProcYieldsProba.cs new file mode 100644 index 000000000..8090acc84 --- /dev/null +++ b/_ParsePABC1/ParsePABC1/AllVarsInProcYieldsProba.cs @@ -0,0 +1,81 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using PascalABCCompiler; +using PascalABCCompiler.SyntaxTree; + +namespace ParsePABC1 +{ + class AllVarsInProcYields : CollectUpperNamespacesVisitor + { + public FindMainIdentsVisitor mids = new FindMainIdentsVisitor(); + + public Dictionary> d = new Dictionary>(); + + public int countNodesVisited; + + public AllVarsInProcYields() + { + PrintInfo = false; + } + + public override void Enter(syntax_tree_node st) + { + base.Enter(st); + countNodesVisited++; + if (st is procedure_definition) + { + // пока вложенные процедуры не анализируются, хотя надо + mids.vars.Clear(); + } + + // сокращение обходимых узлов. Как сделать фильтр по тем узлам, которые необходимо обходить? Например, все операторы (без выражений и описаний), все описания (без операторов) + if (st is assign || st is var_def_statement || st is procedure_call || st is procedure_header || st is expression) + { + visitNode = false; + } + } + public override void Exit(syntax_tree_node st) + { + if (st is procedure_definition) + { + if (mids.vars.Count>0) + { + d[st as procedure_definition] = new HashSet(mids.vars); + } + var fld = new FindLocalDefsVisitor(); + st.visit(fld); + fld.Print(); + var t = fld.ids.Intersect(mids.vars); // идентификаторы, захваченные из локального контекста + + } + base.Exit(st); + } + public override void visit(yield_node yn) + { + yn.visit(mids); + // mids.vars - надо установить, какие из них - локальные, какие - из этого класса, какие - являются параметрами функции, а какие - глобальные (все остальные) + // те, которые являются параметрами, надо скопировать в локальные переменные и переименовать использование везде по ходу данной функции + // самое сложное - переменные-поля этого класса - они требуют в создаваемом классе, реализующем итератор, хранить Self текущего класса и добавлять это Self везде по ходу алгоритма + // вначале будем считать, что переменные-поля этого класса и переменные-параметры не захватываются yield + //base.visit(yn); + } + + public void PrintDict() + { + foreach (var a in d) + { + Console.Write("{0}: {1} ", a.Key.proc_header.name.meth_name, a.Value.Count); + foreach (var v in a.Value) + Console.Write("{0}, ", v); + Console.WriteLine(); + Console.WriteLine(); + Console.WriteLine("countNodesVisited={0}", countNodesVisited); + } + + } + } +} diff --git a/_ParsePABC1/ParsePABC1/App.config b/_ParsePABC1/ParsePABC1/App.config new file mode 100644 index 000000000..8e1564635 --- /dev/null +++ b/_ParsePABC1/ParsePABC1/App.config @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/_ParsePABC1/ParsePABC1/BaseVisitors/BaseChangeVisitor.cs b/_ParsePABC1/ParsePABC1/BaseVisitors/BaseChangeVisitor.cs new file mode 100644 index 000000000..dbd479653 --- /dev/null +++ b/_ParsePABC1/ParsePABC1/BaseVisitors/BaseChangeVisitor.cs @@ -0,0 +1,72 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using PascalABCCompiler; +using PascalABCCompiler.SyntaxTree; + +namespace ParsePABC1 +{ + class BaseChangeVisitor : CollectUpperNodesVisitor + { + public void Replace(syntax_tree_node from, syntax_tree_node to) + { + var upper = UpperNode(); + if (upper == null) + throw new Exception("У корневого элемента нельзя получить UpperNode"); + + int ind = -1; + for (var i = 0; i < upper.subnodes_count; i++) + if (from == upper[i]) + { + ind = i; + break; + } + upper[ind] = to; + } + + public statement_list UpperStatementList() + { + var stl = UpperNode() as statement_list; + if (stl == null) + throw new Exception("оператор вложен не в statement_list"); + return stl; + } + + public bool DeleteInStatementList(statement st) + { + var stl = UpperStatementList(); + bool b = stl.subnodes.Remove(st); + return b; + } + public bool DeleteInIdentList(ident id) + { + var idl = UpperNode() as ident_list; + if (idl==null) + throw new Exception("идентификатор не вложен в id_list"); + var b = idl.idents.Remove(id); + return b; + } + + public void ReplaceStatement(statement from, statement to) + { + var stl = UpperStatementList(); + var ind = stl.subnodes.IndexOf(from); + if (ind == -1) + throw new Exception("оператор from не найден - некорректный вызов ReplaceStatement"); + stl.subnodes[ind] = to; + } + public void ReplaceStatement(statement from, List to) + { + var stl = UpperStatementList(); + var ind = stl.subnodes.IndexOf(from); + if (ind == -1) + throw new Exception("оператор from не найден - некорректный вызов ReplaceStatement"); + stl.subnodes.RemoveAt(ind); + stl.subnodes.InsertRange(ind, to); + } + } + +} diff --git a/_ParsePABC1/ParsePABC1/BaseVisitors/BaseEnterExitVisitor.cs b/_ParsePABC1/ParsePABC1/BaseVisitors/BaseEnterExitVisitor.cs new file mode 100644 index 000000000..f98d2e4e2 --- /dev/null +++ b/_ParsePABC1/ParsePABC1/BaseVisitors/BaseEnterExitVisitor.cs @@ -0,0 +1,27 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using PascalABCCompiler; +using PascalABCCompiler.SyntaxTree; + +namespace ParsePABC1 +{ + class BaseEnterExitVisitor: WalkingVisitor + { + public BaseEnterExitVisitor() + { + OnEnter = Enter; + OnLeave = Exit; + } + + public virtual void Enter(syntax_tree_node st) + { + } + public virtual void Exit(syntax_tree_node st) + { + } + } +} diff --git a/_ParsePABC1/ParsePABC1/BaseVisitors/CollectNamespaces.cs b/_ParsePABC1/ParsePABC1/BaseVisitors/CollectNamespaces.cs new file mode 100644 index 000000000..dc6e1510a --- /dev/null +++ b/_ParsePABC1/ParsePABC1/BaseVisitors/CollectNamespaces.cs @@ -0,0 +1,59 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using PascalABCCompiler; +using PascalABCCompiler.SyntaxTree; + +namespace ParsePABC1 +{ + class CollectUpperNamespacesVisitor : CollectUpperNodesVisitor + { + protected List list = new List(); + + public bool PrintInfo = true; + + public override void Enter(syntax_tree_node st) + { + base.Enter(st); + if (st is procedure_definition || st is class_definition) + { + list.Add(st as declaration); + if (PrintInfo) + Console.Write("+: "+st.GetType().Name); + } + } + public override void Exit(syntax_tree_node st) + { + if (st is procedure_definition || st is class_definition) + { + if (PrintInfo) + Console.WriteLine("-: " + st.GetType().Name); + list.RemoveAt(list.Count - 1); + } + base.Exit(st); + } + + public override void visit(procedure_definition p) + { + if (PrintInfo) + Console.WriteLine(" " + p.proc_header.name.meth_name); + + var ld = new FindLocalDefsVisitor(); + p.visit(ld); + + base.visit(p); + } + public override void visit(class_definition cl) + { + type_declarations tds = UpperNode(2) as type_declarations; + var f = tds.types_decl.Find(td => td.type_def == cl); + if (PrintInfo) + Console.WriteLine(" " + f.type_name); + base.visit(cl); + } + } + +} diff --git a/_ParsePABC1/ParsePABC1/BaseVisitors/CollectUpperNodesVisitor.cs b/_ParsePABC1/ParsePABC1/BaseVisitors/CollectUpperNodesVisitor.cs new file mode 100644 index 000000000..573285d72 --- /dev/null +++ b/_ParsePABC1/ParsePABC1/BaseVisitors/CollectUpperNodesVisitor.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using PascalABCCompiler; +using PascalABCCompiler.SyntaxTree; + +namespace ParsePABC1 +{ + class CollectUpperNodesVisitor : BaseEnterExitVisitor + { + protected List listNodes = new List(); + + public syntax_tree_node CurrentNode + { + get + { + return listNodes[listNodes.Count - 1]; + } + } + + public syntax_tree_node UpperNode(int up = 1) + { + return listNodes[listNodes.Count - 1 - up]; + } + + public override void Enter(syntax_tree_node st) + { + listNodes.Add(st); + } + public override void Exit(syntax_tree_node st) + { + listNodes.RemoveAt(listNodes.Count - 1); + } + } + +} diff --git a/_ParsePABC1/ParsePABC1/BaseVisitors/SmallHelperVisitors.cs b/_ParsePABC1/ParsePABC1/BaseVisitors/SmallHelperVisitors.cs new file mode 100644 index 000000000..698c9dbf0 --- /dev/null +++ b/_ParsePABC1/ParsePABC1/BaseVisitors/SmallHelperVisitors.cs @@ -0,0 +1,50 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using PascalABCCompiler; +using PascalABCCompiler.SyntaxTree; + +namespace ParsePABC1 +{ + public class FindLocalDefsVisitor : WalkingVisitor // Запускать только для подпрограмм + { + public ISet ids = new HashSet(); + private bool indef = false; + public override void visit(ident id) + { + if (indef) + ids.Add(id.name); + } + public override void visit(var_def_statement defs) + { + indef = true; + ProcessNode(defs.vars); // исключаем типы - просматриваем только имена переменных + indef = false; + } + + public void Print() + { + foreach (var x in ids) + Console.Write(x + ", "); + Console.WriteLine(); + } + } + + public class FindMainIdentsVisitor : WalkingVisitor // в выражении yield это надо будет. + { + public HashSet vars = new HashSet(); + public override void visit(ident id) + { + vars.Add(id.name); + } + public override void visit(dot_node dn) + { + ProcessNode(dn.left); + if (dn.right.GetType() != typeof(ident)) + ProcessNode(dn.right); + } + } +} diff --git a/_ParsePABC1/ParsePABC1/ChangeWhileVisitor.cs b/_ParsePABC1/ParsePABC1/ChangeWhileVisitor.cs new file mode 100644 index 000000000..f7a0922ea --- /dev/null +++ b/_ParsePABC1/ParsePABC1/ChangeWhileVisitor.cs @@ -0,0 +1,56 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using PascalABCCompiler.Errors; +using PascalABCCompiler; +using PascalABCCompiler.SyntaxTree; + +namespace ParsePABC1 +{ + class ChangeWhileVisitor : BaseChangeVisitor + { + int lbnum = 0; + + public string newLabelName() + { + lbnum++; + return "lb#" + lbnum.ToString(); + } + public override void Exit(syntax_tree_node st) + { + if (st.GetType() == typeof(while_node)) + { + var wn = st as while_node; + + var stl = new statement_list(); + + var gt1 = new goto_statement(newLabelName()); + var gt2 = new goto_statement(newLabelName()); + var gt3 = new goto_statement(newLabelName()); + + var if0 = new if_node(wn.expr, gt1, null); + var lb3 = new labeled_statement(gt3.label, if0); + var lb1 = new labeled_statement(gt1.label, wn.statements); + var lb2 = new labeled_statement(gt2.label, new empty_statement()); + + stl.Add(lb3).Add(gt2).Add(lb1).Add(gt3).Add(lb2); + + //var op = new if_node(wn.expr, wn.statements, null); + Replace(wn, stl); + // в declarations ближайшего блока добавить описание labels + block bl = listNodes.FindLast(x => x is block) as block; + + var il = new ident_list(); + il.Add(gt1.label).Add(gt2.label).Add(gt3.label); + var ld = new label_definitions(il); + bl.defs.Add(ld); + } + base.Exit(st); + } + + } + +} diff --git a/_ParsePABC1/ParsePABC1/CountNodesVisitor.cs b/_ParsePABC1/ParsePABC1/CountNodesVisitor.cs new file mode 100644 index 000000000..64b633777 --- /dev/null +++ b/_ParsePABC1/ParsePABC1/CountNodesVisitor.cs @@ -0,0 +1,44 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using PascalABCCompiler; +using PascalABCCompiler.SyntaxTree; + +namespace ParsePABC1 +{ + class CountNodesVisitor : BaseEnterExitVisitor + { + public Dictionary d = new Dictionary(); + + public int exprcount,statcount; + public override void Enter(syntax_tree_node st) + { + if (d.ContainsKey(st.GetType())) + d[st.GetType()] += 1; + else d[st.GetType()] = 1; + if (st is expression) + exprcount++; + if (st is statement) + statcount++; + } + + public void PrintSortedByValue() + { + var q = d.Select(x => new { x.Key, x.Value }).OrderByDescending(y => y.Value); + foreach (var a in q) + Console.WriteLine("{0}: {1} ", a.Key.Name, a.Value); + Console.WriteLine(); + Console.WriteLine("Expressions Count: {0}", exprcount); + Console.WriteLine("Statements Count: {0}", statcount); + } + + public void Print() + { + foreach (var a in d) + Console.WriteLine("{0}: {1} ", a.Key.Name, a.Value); + } + } +} diff --git a/_ParsePABC1/ParsePABC1/DeleteLocalDefs.cs b/_ParsePABC1/ParsePABC1/DeleteLocalDefs.cs new file mode 100644 index 000000000..3f3ebced8 --- /dev/null +++ b/_ParsePABC1/ParsePABC1/DeleteLocalDefs.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using PascalABCCompiler; +using PascalABCCompiler.SyntaxTree; + +namespace ParsePABC1 +{ + class DeleteLocalDefs : BaseChangeVisitor + { + public List LocalDeletedIds = new List(); + public List BlockDeletedIds = new List(); + public HashSet idsToDelete; + public HashSet deletedIdsToDeleteInLocalScope = new HashSet(); // одно множество и на Local и на Block + + public DeleteLocalDefs(HashSet ids) // надо запускать этот визитор начиная с корня подпрограммы + { + idsToDelete = ids; + } + public override void visit(var_statement vs) + { + var idents = vs.var_def.vars.idents; + + var IdentsToDeleteInVarDef = idents.FindAll(id => idsToDelete.Contains(id.name)); // найти в операторе все идентификаторы для удаления + if (IdentsToDeleteInVarDef.Count != 0) + { + deletedIdsToDeleteInLocalScope.UnionWith(IdentsToDeleteInVarDef.Select(id => id.name)); // добавить те идентификаторы, которые мы удаляем из данного описания + + LocalDeletedIds.Add(new var_def_statement(new ident_list(IdentsToDeleteInVarDef), vs.var_def.vars_type, vs.var_def.inital_value)); // добавить описание из удаленных в данном разделе описаний идентификаторов + idents.RemoveAll(id => idsToDelete.Contains(id.name)); // удалить в операторе все идентификаторы для удаления + + idsToDelete.ExceptWith(deletedIdsToDeleteInLocalScope); + + if (idents.Count == 0) // то и весь var_statement надо убить + this.DeleteInStatementList(vs); + } + // Здесь мы не обрабатываем вложенный var_def_statement, поэтому когда мы будем обрабатывать его в другом visit, то это будут переменные до beginа подпрограммы или основной программы + } + public override void visit(var_def_statement vd) + { + var idents = vd.vars.idents; + + var IdentsToDeleteInVarDef = idents.FindAll(id => idsToDelete.Contains(id.name)); // найти в операторе все идентификаторы для удаления + if (IdentsToDeleteInVarDef.Count != 0) + { + deletedIdsToDeleteInLocalScope.UnionWith(IdentsToDeleteInVarDef.Select(id => id.name)); // добавить те идентификаторы, которые мы удаляем из данного описания + + BlockDeletedIds.Add(new var_def_statement(new ident_list(IdentsToDeleteInVarDef), vd.vars_type, vd.inital_value)); // добавить описание из удаленных в данном разделе описаний идентификаторов + idents.RemoveAll(id => idsToDelete.Contains(id.name)); // удалить в операторе все идентификаторы для удаления + + if (idents.Count == 0) + { + // Выше - variable_definitions, еще выше - declarations + var uvdsl = UpperNode() as variable_definitions; + uvdsl.var_definitions.Remove(vd); // Проблема - мы удаляем первую var_def_statement и вторая становится первой. А в цикле обхода - индексы что естественно + if (uvdsl.var_definitions.Count == 0) + { + var d = UpperNode(2) as declarations; + d.defs.Remove(uvdsl); + } + } + + } + } + public override void visit(variable_definitions vd) + { + if (vd.var_definitions != null) + for (int i = vd.var_definitions.Count - 1; i >= 0; --i) // в обратном порядке - тогда удаление текущего элемента работает корректно + ProcessNode(vd.var_definitions[i]); + } + + public override void visit(declarations d) + { + if (d.defs != null) + for (int i = d.defs.Count - 1; i >= 0; --i) // в обратном порядке - тогда удаление текущего элемента работает корректно + ProcessNode(d.defs[i]); + } + + public void AfterProcTraverse() + { + idsToDelete.ExceptWith(deletedIdsToDeleteInLocalScope); // исключаем из множества удаляемых идентификаторов те, которые мы нашли и удалили в секции var_statement. Это надо делать не для каждого описания, а в конце подпрограммы после удаления из всех секций var_statement + } + } +} diff --git a/_ParsePABC1/ParsePABC1/DeleteRedundantBeginEnds.cs b/_ParsePABC1/ParsePABC1/DeleteRedundantBeginEnds.cs new file mode 100644 index 000000000..fd1ef9f38 --- /dev/null +++ b/_ParsePABC1/ParsePABC1/DeleteRedundantBeginEnds.cs @@ -0,0 +1,36 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using PascalABCCompiler.Errors; +using PascalABCCompiler; +using PascalABCCompiler.SyntaxTree; + +namespace ParsePABC1 +{ + class DeleteRedundantBeginEnds : BaseChangeVisitor + { + public override void Exit(syntax_tree_node st) + { + var stl = st as statement_list; + if (stl != null && UpperNode() is statement_list) + ReplaceStatement(stl, stl.subnodes); + + var lst = st as labeled_statement; + if (lst != null) + { + var sttl = lst.to_statement as statement_list; + if (sttl != null) + { + sttl.subnodes[0] = new labeled_statement(lst.label_name, sttl.subnodes[0]); // а если [0] элемента вообще нет? + ReplaceStatement(lst,sttl.subnodes); + } + } + + base.Exit(st); + } + + } +} diff --git a/_ParsePABC1/ParsePABC1/Optimization/CalcConstExprs.cs b/_ParsePABC1/ParsePABC1/Optimization/CalcConstExprs.cs new file mode 100644 index 000000000..69ba9e9e5 --- /dev/null +++ b/_ParsePABC1/ParsePABC1/Optimization/CalcConstExprs.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using PascalABCCompiler; +using PascalABCCompiler.SyntaxTree; + +namespace ParsePABC1 +{ + class CalcConstExprs : BaseChangeVisitor // вычисление целых и вещественных константных выражений на этапе парсинга + { + public override void Exit(syntax_tree_node st) + { + bracket_expr bre = st as bracket_expr; + if (bre != null) + { + if (bre.expr is int32_const) + Replace(st, bre.expr); + } + + bin_expr vs = st as bin_expr; + if (vs != null) + { + if (vs.left is int32_const && vs.right is int32_const) + { + var a = vs.left as int32_const; + var b = vs.right as int32_const; + var op = vs.operation_type; + + syntax_tree_node res; + switch (op) + { + case Operators.Plus: + res = new int32_const(a.val + b.val); + break; + case Operators.Minus: + res = new int32_const(a.val - b.val); + break; + case Operators.Multiplication: + res = new int32_const(a.val * b.val); + break; + case Operators.Division: + res = new double_const((double)a.val / b.val); + break; + case Operators.Greater: + res = new bool_const(a.val > b.val); + break; + case Operators.Less: + res = new bool_const(a.val < b.val); + break; + case Operators.GreaterEqual: + res = new bool_const(a.val >= b.val); + break; + case Operators.LessEqual: + res = new bool_const(a.val <= b.val); + break; + default: + res = vs; + break; + } + + Replace(vs, res); + } + if (vs.left is int32_const && vs.right is double_const || vs.right is int32_const && vs.left is double_const || vs.left is double_const && vs.right is double_const) + { + double x,y; + if (vs.left is int32_const) + x = (vs.left as int32_const).val; + else + x = (vs.left as double_const).val; + if (vs.right is int32_const) + y = (vs.right as int32_const).val; + else + y = (vs.right as double_const).val; + + var op = vs.operation_type; + + syntax_tree_node res; + switch (op) + { + case Operators.Plus: + res = new double_const(x + y); + break; + case Operators.Minus: + res = new double_const(x - y); + break; + case Operators.Multiplication: + res = new double_const(x * y); + break; + case Operators.Division: + res = new double_const(x / y); + break; + case Operators.Greater: + res = new bool_const(x > y); + break; + case Operators.Less: + res = new bool_const(x < y); + break; + case Operators.GreaterEqual: + res = new bool_const(x >= y); + break; + case Operators.LessEqual: + res = new bool_const(x <= y); + break; + default: + res = vs; + break; + } + + Replace(vs, res); + } + + } + + base.Exit(st); // это обязательно! + } + } +} diff --git a/_ParsePABC1/ParsePABC1/ParsePABC1.csproj b/_ParsePABC1/ParsePABC1/ParsePABC1.csproj new file mode 100644 index 000000000..9c32cdf65 --- /dev/null +++ b/_ParsePABC1/ParsePABC1/ParsePABC1.csproj @@ -0,0 +1,103 @@ + + + + + Debug + AnyCPU + {BAA767F1-6544-4A44-BA17-5FBFCF6F2D99} + Exe + Properties + ParsePABC1 + ParsePABC1 + v4.5 + 512 + + + AnyCPU + true + full + false + bin\Debug\ + DEBUG;TRACE + prompt + 4 + + + AnyCPU + pdbonly + true + bin\Release\ + TRACE + prompt + 4 + + + + ..\..\..\PascalABC.NET\!PABC_SVN1\bin\Compiler.dll + + + ..\..\..\PascalABC.NET\!PABC_SVN1\bin\CompilerTools.dll + + + ..\..\..\PascalABC.NET\!PABC_SVN1\bin\Errors.dll + + + ..\..\..\PascalABC.NET\!PABC_SVN1\bin\Localization.dll + + + ..\..\..\PascalABC.NET\!PABC_SVN1\bin\ParserTools.dll + + + ..\..\..\PascalABC.NET\!PABC_Git\bin\PascalABCParser.dll + + + + + + + + + + + + + + Code + + + + + + + + + + + Code + + + + + + + + + + + {1ab15f6e-c22e-499a-a7ed-54ba7de5cfa6} + CodeCompletion + + + {c2cac65a-b2ae-4ccc-b067-e6b8e75df73a} + SyntaxTree + + + + + \ No newline at end of file diff --git a/_ParsePABC1/ParsePABC1/ProcessYieldsCapturedVars.cs b/_ParsePABC1/ParsePABC1/ProcessYieldsCapturedVars.cs new file mode 100644 index 000000000..33a7cdf67 --- /dev/null +++ b/_ParsePABC1/ParsePABC1/ProcessYieldsCapturedVars.cs @@ -0,0 +1,104 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using PascalABCCompiler; +using PascalABCCompiler.SyntaxTree; + +namespace ParsePABC1 +{ + class ProcessYieldCapturedVarsVisitor : BaseChangeVisitor + { + int clnum = 0; + + public string newClassName() + { + clnum++; + return "clyield#" + clnum.ToString(); + } + + + public FindMainIdentsVisitor mids = new FindMainIdentsVisitor(); // захваченные переменные процедуры по всем её yield + + public int countNodesVisited; + + public bool hasYields = false; + + public ProcessYieldCapturedVarsVisitor() + { + //PrintInfo = false; + } + + /*public override void visit(procedure_definition pd) + { + + } */ + + public override void Enter(syntax_tree_node st) + { + base.Enter(st); + countNodesVisited++; + + // сокращение обходимых узлов. Как сделать фильтр по тем узлам, которые необходимо обходить? Например, все операторы (без выражений и описаний), все описания (без операторов) + if (st is assign || st is var_def_statement || st is procedure_call || st is procedure_header || st is expression) + { + visitNode = false; + } + if (st is procedure_definition) + { + mids.vars.Clear(); // очищать при входе в процедуру + } + } + public override void Exit(syntax_tree_node st) + { + if (st is procedure_definition) // т.е. мы разобрали процедуру и уже выходим. Это значит, что пока yield будет обрабатываться только в процедурах. Так это и надо. + { + if (!hasYields) + return; + + var dld = new DeleteLocalDefs(mids.vars); // mids.vars - все захваченные переменные + st.visit(dld); // Удалить в локальных и блочных описаниях этой процедуры все захваченные переменные + // В результате работы в mids.vars что-то осталось. Это не локальные переменные и с ними непонятно что делать + dld.AfterProcTraverse(); + + var cm = new class_members(access_modifer.public_modifer); + foreach (var m in dld.BlockDeletedIds) + cm.Add(m); + cm.Add(st as procedure_definition); + var cc = new type_declaration(newClassName(), SyntaxTreeBuilder.BuildClassDefinition(true, cm), SyntaxTreeBuilder.BuildGenSC); + var cct = new type_declarations(cc, null); + + Replace(st, cct); + + /*Console.WriteLine("Удаленные переменные: " + (st as procedure_definition).proc_header.name.meth_name.name); + foreach (var dd in dld.deletedIdsToDeleteInLocalScope) + Console.Write(dd + " "); + Console.WriteLine(); + Console.WriteLine("Оставшиеся переменные: " + (st as procedure_definition).proc_header.name.meth_name.name); + foreach (var dd in mids.vars) + Console.Write(dd + " "); + Console.WriteLine();*/ + } + base.Exit(st); + } + public override void visit(yield_node yn) + { + hasYields = true; + yn.visit(mids); + // mids.vars - надо установить, какие из них - локальные, какие - из этого класса, какие - являются параметрами функции, а какие - глобальные (все остальные) + // те, которые являются параметрами, надо скопировать в локальные переменные и переименовать использование везде по ходу данной функции + // самое сложное - переменные-поля этого класса - они требуют в создаваемом классе, реализующем итератор, хранить Self текущего класса и добавлять это Self везде по ходу алгоритма + // вначале будем считать, что переменные-поля этого класса и переменные-параметры не захватываются yield + //base.visit(yn); + } + public override void visit(declarations d) // в обратном порядке + { + if (d.defs != null) + for (int i = d.defs.Count - 1; i >= 0; --i) // в обратном порядке - тогда удаление текущего элемента работает корректно + ProcessNode(d.defs[i]); + } + + } +} diff --git a/_ParsePABC1/ParsePABC1/Program.cs b/_ParsePABC1/ParsePABC1/Program.cs new file mode 100644 index 000000000..6840fab38 --- /dev/null +++ b/_ParsePABC1/ParsePABC1/Program.cs @@ -0,0 +1,67 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using PascalABCCompiler.Errors; +using PascalABCCompiler; +using PascalABCCompiler.SyntaxTree; + +namespace ParsePABC1 +{ + class Program + { + static syntax_tree_node ParseFile(string fname) + { + Compiler c = new Compiler(); + + var err = new List(); + + var txt = System.IO.File.ReadAllText(fname); + + var cu = c.ParsersController.Compile(fname, txt, err, PascalABCCompiler.Parsers.ParseMode.ForFormatter); + + if (cu == null) + { + Console.WriteLine("Не распарсилось"); + } + return cu; + } + + static void Main(string[] args) + { + var cu = ParseFile(@"d:\w5\ex1.pas"); + if (cu == null) + return; + + /*cu.visit(new ChangeWhileVisitor()); + cu.visit(new DeleteRedundantBeginEnds());*/ + + /*cu.visit(new CollectUpperNamespacesVisitor()); + + var allv = new AllVarsInProcYields(); + cu.visit(allv); + allv.PrintDict();*/ + + /*var cnt = new CountNodesVisitor(); + cu.visit(cnt); + cnt.PrintSortedByValue();*/ + + /*var ld = new HashSet(); + ld.Add("a"); + ld.Add("p1"); + ld.Add("s"); + var dld = new DeleteLocalDefs(ld); + cu.visit(dld);*/ + + /*var p = new ProcessYieldCapturedVarsVisitor(); + cu.visit(p);*/ + + var p = new CalcConstExprs(); + cu.visit(p); + + cu.visit(new SimplePrettyPrinterVisitor()); + } + } +} diff --git a/_ParsePABC1/ParsePABC1/ProgramOld.cs b/_ParsePABC1/ParsePABC1/ProgramOld.cs new file mode 100644 index 000000000..651d8d97a --- /dev/null +++ b/_ParsePABC1/ParsePABC1/ProgramOld.cs @@ -0,0 +1,62 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using PascalABCCompiler.Errors; +using PascalABCCompiler; +using PascalABCCompiler.SyntaxTree; + +namespace ParsePABC1 +{ + class Program + { + static syntax_tree_node ParseFile(string fname) + { + Compiler c = new Compiler(); + + var err = new List(); + + var txt = System.IO.File.ReadAllText(fname); + + var cu = c.ParsersController.Compile(fname, txt, err, PascalABCCompiler.Parsers.ParseMode.ForFormatter); + + if (cu == null) + { + Console.WriteLine("Не распарсилось"); + } + return cu; + } + + static void Main(string[] args) + { + var cu = ParseFile(@"d:\w5\e.pas"); + if (cu == null) + return; + + //CodeFormatters.CodeFormatter cf = new CodeFormatters.CodeFormatter(0); + //txt = cf.FormatTree(txt, cu as compilation_unit, 0, 0); + + cu.visit(new ChangeWhileVisitor()); + cu.visit(new DeleteRedundantBeginEnds()); + + /*cu.visit(new CollectUpperNamespacesVisitor()); + + var allv = new AllVarsInProcYields(); + cu.visit(allv); + allv.PrintDict();*/ + + /*var cnt = new CountNodesVisitor(); + cu.visit(cnt); + cnt.PrintSortedByValue();*/ + + var ld = new List(); + ld.Add("p1"); + var dld = new DeleteLocalDefs(ld); + cu.visit(dld); + + cu.visit(new SimplePrettyPrinterVisitor()); + } + } +} diff --git a/_ParsePABC1/ParsePABC1/Properties/AssemblyInfo.cs b/_ParsePABC1/ParsePABC1/Properties/AssemblyInfo.cs new file mode 100644 index 000000000..624a2bb1d --- /dev/null +++ b/_ParsePABC1/ParsePABC1/Properties/AssemblyInfo.cs @@ -0,0 +1,36 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// Управление общими сведениями о сборке осуществляется с помощью +// набора атрибутов. Измените значения этих атрибутов, чтобы изменить сведения, +// связанные со сборкой. +[assembly: AssemblyTitle("ParsePABC1")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("ParsePABC1")] +[assembly: AssemblyCopyright("Copyright © 2015")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Параметр ComVisible со значением FALSE делает типы в сборке невидимыми +// для COM-компонентов. Если требуется обратиться к типу в этой сборке через +// COM, задайте атрибуту ComVisible значение TRUE для этого типа. +[assembly: ComVisible(false)] + +// Следующий GUID служит для идентификации библиотеки типов, если этот проект будет видимым для COM +[assembly: Guid("fa30eefc-3fcc-45a3-8b6f-465b1a5c17ba")] + +// Сведения о версии сборки состоят из следующих четырех значений: +// +// Основной номер версии +// Дополнительный номер версии +// Номер сборки +// Редакция +// +// Можно задать все значения или принять номера сборки и редакции по умолчанию +// используя "*", как показано ниже: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/_ParsePABC1/ParsePABC1/SimplePrettyPrinterVisitor.cs b/_ParsePABC1/ParsePABC1/SimplePrettyPrinterVisitor.cs new file mode 100644 index 000000000..be11bd4ed --- /dev/null +++ b/_ParsePABC1/ParsePABC1/SimplePrettyPrinterVisitor.cs @@ -0,0 +1,183 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +using PascalABCCompiler.Errors; +using PascalABCCompiler.PCU; +using PascalABCCompiler.SemanticTreeConverters; +using System.CodeDom.Compiler; +using PascalABCCompiler; +using PascalABCCompiler.SyntaxTree; + + +namespace ParsePABC1 +{ + class SimplePrettyPrinterVisitor: WalkingVisitor + { + int off = 0; + + bool printNodeType = false; + + public SimplePrettyPrinterVisitor() + { + OnEnter = Enter; + OnLeave = Exit; + } + + public void Println(string s) + { + Console.Write(new string(' ', off)); + Console.WriteLine(s); + } + public void Print(string s) + { + Console.Write(new string(' ', off)); + Console.Write(s); + } + public void PrintNoOffset(string s) + { + Console.Write(s); + } + public void PrintlnNoOffset(string s) + { + Console.WriteLine(s); + } + + public void PrintlnNode(syntax_tree_node st) + { + if (printNodeType) + Console.Write(st.GetType().Name + ": "); + Console.WriteLine(new string(' ', off)+st); + } + public virtual void Enter(syntax_tree_node st) + { + if (st is statement_list) + { + Println("begin"); + off += 2; + } + else if (st is type_declarations) // надо в visit и самому всё обрабатывать + { + var tds = st is type_declarations; + Println("type "); + off += 2; + } + else if (st is type_declaration) + { + var td = st as type_declaration; + Print(td.type_name + " = "); + ProcessNode(td.type_def); + visitNode = false; + } + else if (st is class_definition) + { + var cd = st as class_definition; + PrintlnNoOffset("class"); + off += 2; + ProcessNode(cd.body); + visitNode = false; + } + else if (st is access_modifer_node) + { + var am = st as access_modifer_node; + Println(am.access_level.ToString()); + + } + else if (st is variable_definitions) + { + var vds = st as variable_definitions; + Println("var"); + off += 2; + } + else if (st is var_def_statement) + { + var vds = st as var_def_statement; + Println(vds.ToString()); + } + else if (st is empty_statement || st is declarations || st is block || st is class_body || st is class_members) + { + } + else if (st is if_node) + { + var ifn = st as if_node; + + Println("if " + ifn.condition.ToString() + " then"); + off += 2; + ProcessNode(ifn.then_body); + if (ifn.else_body == null) + { + visitNode = false; + return; + } + off -= 2; + Println("else "); + off += 2; + ProcessNode(ifn.else_body); + visitNode = false; + } + else if (st is while_node) + { + var wn = st as while_node; + + Println("while " + wn.expr.ToString() + " do"); + off += 2; + } + else if (st is labeled_statement) + { + var lst = st as labeled_statement; + + Println(lst.label_name.name + ": "); + ProcessNode(lst.to_statement); + visitNode = false; + } + else if (st is var_statement || st is procedure_header) + { + Println(st.ToString()); + visitNode = false; + } + else if (st is procedure_definition) + { + Println(""); + } + else if (st is statement || st is variable_definitions || st is label_definitions) + { + PrintlnNode(st); + if (st is labeled_statement) + visitNode = false; + } + else if (st is token_info) + { + var s = st.ToString(); + if (s == "begin" || s == "end") + return; + PrintlnNode(st); + } + else + { + var q = st.GetType().GetMethod("ToString", System.Reflection.BindingFlags.Public | System.Reflection.BindingFlags.Instance | System.Reflection.BindingFlags.DeclaredOnly); + if (q == null) + Println(st.GetType().Name); + } + } + public virtual void Exit(syntax_tree_node st) + { + if (st is statement_list) + { + off -= 2; + Println("end"); + } + else if (st is while_node || st is if_node || st is type_declarations || st is variable_definitions) + { + off -= 2; + } + else if (st is class_definition) + { + off -= 2; + Println("end;"); + } + } + + } +} diff --git a/_ParsePABC1/ParsePABC1/obj/Debug/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs b/_ParsePABC1/ParsePABC1/obj/Debug/TemporaryGeneratedFile_036C0B5B-1481-4323-8D20-8F5ADCB23D92.cs new file mode 100644 index 000000000..e69de29bb diff --git a/_ParsePABC1/ParsePABC1/obj/Debug/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs b/_ParsePABC1/ParsePABC1/obj/Debug/TemporaryGeneratedFile_5937a670-0e60-4077-877b-f7221da3dda1.cs new file mode 100644 index 000000000..e69de29bb diff --git a/_ParsePABC1/ParsePABC1/obj/Debug/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs b/_ParsePABC1/ParsePABC1/obj/Debug/TemporaryGeneratedFile_E7A71F73-0F8D-4B9B-B56E-8E70B10BC5D3.cs new file mode 100644 index 000000000..e69de29bb diff --git a/bin/Lib/PABCRtl.dll b/bin/Lib/PABCRtl.dll index d246a5c60..202c63b90 100644 Binary files a/bin/Lib/PABCRtl.dll and b/bin/Lib/PABCRtl.dll differ