From 35c7bc5877a612cb03b02c79b80d3cc8fd137c62 Mon Sep 17 00:00:00 2001 From: AlexanderZemlyak <92867056+AlexanderZemlyak@users.noreply.github.com> Date: Sun, 21 Jul 2024 13:36:15 +0300 Subject: [PATCH] Add constructors to scanner, parser and parserTools (#3185) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Add constructors to scanner, parser and parserTools Добавил конструкторы, чтобы код был почище * Change type of keywords in Scanner * Make cast explicit * Rebuild ABCPascal.cs --- ParserTools/ParserTools/BaseParserTools.cs | 28 +++--- .../PascalABCParserNewSaushkin/ABCPascal.cs | 18 ++-- .../PascalABCParserNewSaushkin/ABCPascal.lex | 14 ++- .../PascalABCParserNewSaushkin/ABCPascal.y | 11 ++- .../ABCPascalParserTools.cs | 90 ++++++++++--------- .../ABCPascalYacc.cs | 11 ++- Parsers/PascalABCParserNewSaushkin/Parser.cs | 19 ++-- .../SemanticRulesForYacc.cs | 37 ++++---- 8 files changed, 127 insertions(+), 101 deletions(-) diff --git a/ParserTools/ParserTools/BaseParserTools.cs b/ParserTools/ParserTools/BaseParserTools.cs index d2aee4196..80d7f3a01 100644 --- a/ParserTools/ParserTools/BaseParserTools.cs +++ b/ParserTools/ParserTools/BaseParserTools.cs @@ -25,7 +25,7 @@ namespace PascalABCCompiler.ParserTools } } - // Класс глобальных описаний и статических методов + // Класс глобальных описаний и общих методов // для использования различными подсистемами парсера и сканера public abstract class BaseParserTools { @@ -38,13 +38,21 @@ namespace PascalABCCompiler.ParserTools public string currentFileName; public List compilerDirectives; - public static Dictionary tokenNum; // строки, соответствующие терминалам, для вывода ошибок - SSM + public abstract Dictionary TokenNum { get; protected set; } // строки, соответствующие терминалам, для вывода ошибок - SSM - public IParser ParserRef { get; private set; } + public Dictionary ValidDirectives { get; private set; } - protected BaseParserTools(IParser parserRef) + protected BaseParserTools(List errors, List warnings, + Dictionary validDirectives, bool buildTreeForFormatter, bool buildTreeForFormatterStrings, + string currentFileName, List compilerDirectives) { - this.ParserRef = parserRef; + this.errors = errors; + this.warnings = warnings; + this.ValidDirectives = validDirectives; + this.buildTreeForFormatter = buildTreeForFormatter; + this.buildTreeForFormatterStrings = buildTreeForFormatterStrings; + this.currentFileName = currentFileName; + this.compilerDirectives = compilerDirectives; } public SourceContext ToSourceContext(LexLocation loc) @@ -57,8 +65,8 @@ namespace PascalABCCompiler.ParserTools public string ConvertToHumanName(string s) { var v = s; - if (tokenNum.ContainsKey(v)) - v = tokenNum[v]; + if (TokenNum.ContainsKey(v)) + v = TokenNum[v]; else if (v.StartsWith("tk")) v = v.Remove(0, 2).ToLower(); @@ -204,7 +212,7 @@ namespace PascalABCCompiler.ParserTools string paramsString = directiveText.Substring(directiveText.IndexOf(directiveName) + directiveName.Length); // если кавычки используются как специальные символы (для объединения нескольких слов в одно) - if (ParserRef.ValidDirectives[directiveName].quotesAreSpecialSymbols) + if (ValidDirectives[directiveName].quotesAreSpecialSymbols) { directiveParams = SplitDirectiveParamsWithQuotesAsSpecialSymbols(paramsString); } @@ -229,7 +237,7 @@ namespace PascalABCCompiler.ParserTools } // проверка имени директивы - if (!ParserRef.ValidDirectives.ContainsKey(directiveName)) + if (!ValidDirectives.ContainsKey(directiveName)) { AddErrorFromResource("UNKNOWN_DIRECTIVE{0}", location, directiveName); return; @@ -246,7 +254,7 @@ namespace PascalABCCompiler.ParserTools /// public void ValidateDirectiveParams(string directiveName, List directiveParams, SourceContext loc) { - var directiveInfo = ParserRef.ValidDirectives[directiveName]; + var directiveInfo = ValidDirectives[directiveName]; if (directiveInfo.checkParamsNumNeeded) { diff --git a/Parsers/PascalABCParserNewSaushkin/ABCPascal.cs b/Parsers/PascalABCParserNewSaushkin/ABCPascal.cs index 9be8bb376..0056096d9 100644 --- a/Parsers/PascalABCParserNewSaushkin/ABCPascal.cs +++ b/Parsers/PascalABCParserNewSaushkin/ABCPascal.cs @@ -136,19 +136,25 @@ namespace Languages.Pascal.Frontend.Core #region user code public PascalParserTools parserTools; - private PascalABCCompiler.Parsers.BaseKeywords keywords; + public PascalABCKeywords keywords; + public List Defines = new List(); private Stack buffStack = new Stack(); private Stack fNameStack = new Stack(); private Stack IfDefInElseBranch = new Stack(); private Stack IfDefVar = new Stack(); - public List Defines = new List(); private int IfExclude; - private string Pars; private LexLocation currentLexLocation; private bool HiddenIdents = false; private bool ExprMode = false; - public Scanner(PascalABCCompiler.Parsers.BaseKeywords keywords) { this.keywords = keywords; } + public Scanner(string text, PascalParserTools parserTools, PascalABCCompiler.Parsers.BaseKeywords keywords, List defines = null) + { + this.parserTools = parserTools; + this.keywords = (PascalABCKeywords)keywords; + if (defines != null) + this.Defines.AddRange(defines); + SetSource(text, 0); + } #endregion user code int state; @@ -2187,7 +2193,7 @@ if (parserTools.buildTreeForFormatter) parserTools.ParseDirective(yytext, CurrentLexLocation, out var directiveName, out var directiveParams); var orgDirectiveName = directiveName; - if (directiveName == "") // сл??ай п?с?ой ди?ек?ив? + if (directiveName == "") // сл�?�?ай п�?с�?ой ди�?ек�?ив�? break; directiveName = directiveName.ToUpper(); @@ -2284,7 +2290,7 @@ BEGIN(INITIAL); parserTools.ParseDirective(yytext, CurrentLexLocation, out directiveName, out directiveParams); orgDirectiveName = directiveName; - if (directiveName == "") // сл??ай п?с?ой ди?ек?ив? + if (directiveName == "") // сл�?�?ай п�?с�?ой ди�?ек�?ив�? break; directiveName = directiveName.ToUpper(); diff --git a/Parsers/PascalABCParserNewSaushkin/ABCPascal.lex b/Parsers/PascalABCParserNewSaushkin/ABCPascal.lex index bcebc27f6..4fbb5ed38 100644 --- a/Parsers/PascalABCParserNewSaushkin/ABCPascal.lex +++ b/Parsers/PascalABCParserNewSaushkin/ABCPascal.lex @@ -1,18 +1,24 @@ %{ public PascalParserTools parserTools; - private PascalABCCompiler.Parsers.BaseKeywords keywords; + public PascalABCKeywords keywords; + public List Defines = new List(); private Stack buffStack = new Stack(); private Stack fNameStack = new Stack(); private Stack IfDefInElseBranch = new Stack(); private Stack IfDefVar = new Stack(); - public List Defines = new List(); private int IfExclude; - private string Pars; private LexLocation currentLexLocation; private bool HiddenIdents = false; private bool ExprMode = false; - public Scanner(PascalABCCompiler.Parsers.BaseKeywords keywords) { this.keywords = keywords; } + public Scanner(string text, PascalParserTools parserTools, PascalABCCompiler.Parsers.BaseKeywords keywords, List defines = null) + { + this.parserTools = parserTools; + this.keywords = (PascalABCKeywords)keywords; + if (defines != null) + this.Defines.AddRange(defines); + SetSource(text, 0); + } %} %namespace Languages.Pascal.Frontend.Core diff --git a/Parsers/PascalABCParserNewSaushkin/ABCPascal.y b/Parsers/PascalABCParserNewSaushkin/ABCPascal.y index 98d6d525b..0365488ea 100644 --- a/Parsers/PascalABCParserNewSaushkin/ABCPascal.y +++ b/Parsers/PascalABCParserNewSaushkin/ABCPascal.y @@ -7,11 +7,14 @@ public syntax_tree_node root; // Корневой узел синтаксического дерева - public int maxErrors = 10; - public PascalParserTools parserTools; - public ParserLambdaHelper lambdaHelper = new ParserLambdaHelper(); + // private int maxErrors = 10; + private PascalParserTools parserTools; + private ParserLambdaHelper lambdaHelper = new ParserLambdaHelper(); - public GPPGParser(AbstractScanner scanner) : base(scanner) { } + public GPPGParser(AbstractScanner scanner, PascalParserTools parserTools) : base(scanner) + { + this.parserTools = parserTools; + } %} %output=ABCPascalYacc.cs diff --git a/Parsers/PascalABCParserNewSaushkin/ABCPascalParserTools.cs b/Parsers/PascalABCParserNewSaushkin/ABCPascalParserTools.cs index 670f78398..412ae78d3 100644 --- a/Parsers/PascalABCParserNewSaushkin/ABCPascalParserTools.cs +++ b/Parsers/PascalABCParserNewSaushkin/ABCPascalParserTools.cs @@ -4,8 +4,8 @@ using System.Collections.Generic; using PascalABCCompiler.SyntaxTree; using System.Linq; using PascalABCCompiler.ParserTools; -using PascalABCCompiler.Parsers; -using PascalABCCompiler; +using PascalABCCompiler.Errors; +using PascalABCCompiler.ParserTools.Directives; namespace Languages.Pascal.Frontend.Core { @@ -20,54 +20,62 @@ namespace Languages.Pascal.Frontend.Core public List pascalABCVarStatements; public List pascalABCTypeDeclarations; - static PascalParserTools() + public override Dictionary TokenNum { get; protected set; } + + private void InitializeTokenNum() { - tokenNum = new Dictionary(); + TokenNum = new Dictionary() + { + ["tkStatement"] = StringResources.Get("OPERATOR"), + ["tkExpression"] = StringResources.Get("EXPR"), + ["EOF"] = StringResources.Get("EOF1"), + ["tkIdentifier"] = StringResources.Get("TKIDENTIFIER"), + ["tkStringLiteral"] = StringResources.Get("TKSTRINGLITERAL"), + ["tkAmpersend"] = "'", + ["tkColon"] = "':'", + ["tkDotDot"] = "'..'", + ["tkPoint"] = "'.'", + ["tkRoundOpen"] = "'('", + ["tkRoundClose"] = "')'", + ["tkSemiColon"] = "','", + ["tkSquareOpen"] = "'['", + ["tkSquareClose"] = "']'", + ["tkQuestion"] = "'?'", - tokenNum["tkStatement"] = StringResources.Get("OPERATOR"); - tokenNum["tkExpression"] = StringResources.Get("EXPR"); - tokenNum["EOF"] = StringResources.Get("EOF1"); - tokenNum["tkIdentifier"] = StringResources.Get("TKIDENTIFIER"); - tokenNum["tkStringLiteral"] = StringResources.Get("TKSTRINGLITERAL"); - tokenNum["tkAmpersend"] = "'"; - tokenNum["tkColon"] = "':'"; - tokenNum["tkDotDot"] = "'..'"; - tokenNum["tkPoint"] = "'.'"; - tokenNum["tkRoundOpen"] = "'('"; - tokenNum["tkRoundClose"] = "')'"; - tokenNum["tkSemiColon"] = "';'"; - tokenNum["tkSquareOpen"] = "'['"; - tokenNum["tkSquareClose"] = "']'"; - tokenNum["tkQuestion"] = "'?'"; - - tokenNum["tkComma"] = "','"; - tokenNum["tkAssign"] = "':='"; - tokenNum["tkPlusEqual"] = "'+='"; - tokenNum["tkMinusEqual"] = "'-='"; - tokenNum["tkMultEqual"] = "'*='"; - tokenNum["tkDivEqual"] = "'/='"; - tokenNum["tkMinus"] = "'-'"; - tokenNum["tkPlus"] = "'+'"; - tokenNum["tkSlash"] = "'//'"; - tokenNum["tkStar"] = "'*'"; - tokenNum["tkEqual"] = "'='"; - tokenNum["tkGreater"] = "'>'"; - tokenNum["tkGreaterEqual"] = "'>='"; - tokenNum["tkLower"] = "'<'"; - tokenNum["tkLowerEqual"] = "'<='"; - tokenNum["tkNotEqual"] = "'<>'"; - tokenNum["tkArrow"] = "'->'"; - tokenNum["tkAddressOf"] = "'@'"; - tokenNum["tkDeref"] = "'^'"; - tokenNum["tkStarStar"] = "'**'"; + ["tkComma"] = "','", + ["tkAssign"] = "':='", + ["tkPlusEqual"] = "'+='", + ["tkMinusEqual"] = "'-='", + ["tkMultEqual"] = "'*='", + ["tkDivEqual"] = "'/='", + ["tkMinus"] = "'-'", + ["tkPlus"] = "'+'", + ["tkSlash"] = "'//'", + ["tkStar"] = "'*'", + ["tkEqual"] = "'='", + ["tkGreater"] = "'>'", + ["tkGreaterEqual"] = "'>='", + ["tkLower"] = "'<'", + ["tkLowerEqual"] = "'<='", + ["tkNotEqual"] = "'<>'", + ["tkArrow"] = "'->'", + ["tkAddressOf"] = "'@'", + ["tkDeref"] = "'^'", + ["tkStarStar"] = "'**'" + }; } - public PascalParserTools(IParser parserRef) : base(parserRef) + public PascalParserTools(List errors, List warnings, + Dictionary validDirectives, bool buildTreeForFormatter = false, bool buildTreeForFormatterStrings = false, + string currentFileName = null, List compilerDirectives = null) + : base(errors, warnings, validDirectives, buildTreeForFormatter, buildTreeForFormatterStrings, currentFileName, compilerDirectives) { NodesStack = new System.Collections.Stack(); pascalABCLambdaDefinitions = new List(); pascalABCVarStatements = new List(); pascalABCTypeDeclarations = new List(); + + InitializeTokenNum(); } protected override string ExtractDirectiveTextWithoutSpecialSymbols(string directive) diff --git a/Parsers/PascalABCParserNewSaushkin/ABCPascalYacc.cs b/Parsers/PascalABCParserNewSaushkin/ABCPascalYacc.cs index ff056826b..28c6cdc7e 100644 --- a/Parsers/PascalABCParserNewSaushkin/ABCPascalYacc.cs +++ b/Parsers/PascalABCParserNewSaushkin/ABCPascalYacc.cs @@ -63,11 +63,14 @@ public partial class GPPGParser: ShiftReduceParser scanner) : base(scanner) { } + public GPPGParser(AbstractScanner scanner, PascalParserTools parserTools) : base(scanner) + { + this.parserTools = parserTools; + } // End verbatim content from ABCPascal.y #pragma warning disable 649 diff --git a/Parsers/PascalABCParserNewSaushkin/Parser.cs b/Parsers/PascalABCParserNewSaushkin/Parser.cs index 59ab4e79d..7695e5c39 100644 --- a/Parsers/PascalABCParserNewSaushkin/Parser.cs +++ b/Parsers/PascalABCParserNewSaushkin/Parser.cs @@ -150,22 +150,13 @@ namespace Languages.Pascal.Frontend.Wrapping #endif #endif - PascalParserTools parserTools = new PascalParserTools(this); // контекст сканера и парсера - parserTools.errors = Errors; - parserTools.warnings = Warnings; - parserTools.compilerDirectives = CompilerDirectives; - parserTools.currentFileName = Path.GetFullPath(fileName); + PascalParserTools parserTools = new PascalParserTools(Errors, Warnings, ValidDirectives, + buildTreeForFormatter, false, + Path.GetFullPath(fileName), CompilerDirectives); // контекст сканера и парсера + Scanner scanner = new Scanner(Text, parserTools, Keywords, definesList); - Scanner scanner = new Scanner(Keywords); - scanner.SetSource(Text, 0); - scanner.parserTools = parserTools; // передали parserTools в объект сканера - if (definesList != null) - scanner.Defines.AddRange(definesList); - - GPPGParser parser = new GPPGParser(scanner); - parserTools.buildTreeForFormatter = buildTreeForFormatter; - parser.parserTools = parserTools; // передали parserTools в объект парсера + GPPGParser parser = new GPPGParser(scanner, parserTools); if (!parser.Parse()) if (Errors.Count == 0) diff --git a/Parsers/PascalABCParserNewSaushkin/SemanticRulesForYacc.cs b/Parsers/PascalABCParserNewSaushkin/SemanticRulesForYacc.cs index a6540fc38..acd2a2053 100644 --- a/Parsers/PascalABCParserNewSaushkin/SemanticRulesForYacc.cs +++ b/Parsers/PascalABCParserNewSaushkin/SemanticRulesForYacc.cs @@ -396,27 +396,25 @@ namespace Languages.Pascal.Frontend.Core return lcl; } - public expression ParseExpression(string Text, int line, int col) + /// + /// Создает вторую версию парсера с целью применения части грамматики, связанной с нетерминалом expr. + /// + public expression ParseExpression(string Text) { - PascalParserTools parserTools = new PascalParserTools(this.parserTools.ParserRef); // контекст сканера и парсера - parserTools.errors = new List(); - parserTools.warnings = new List(); - parserTools.currentFileName = System.IO.Path.GetFullPath(this.parserTools.currentFileName); - parserTools.buildTreeForFormatterStrings = true; - Scanner scanner = new Scanner(this.parserTools.ParserRef.Keywords); - scanner.SetSource("<>"+Text, 0); - scanner.parserTools = parserTools;// передали parserTools в объект сканера - GPPGParser parser = new GPPGParser(scanner); - parserTools.buildTreeForFormatter = false; - parser.lambdaHelper = this.lambdaHelper; - parser.parserTools = parserTools; + PascalParserTools parserTools = new PascalParserTools(new List(), new List(), + this.parserTools.ValidDirectives, false, true, this.parserTools.currentFileName); // контекст сканера и парсера + + Scanner scanner = new Scanner("<>" + Text, parserTools, ((Scanner)this.scanner).keywords); + + GPPGParser parser = new GPPGParser(scanner, parserTools); + parser.lambdaHelper = lambdaHelper; + if (!parser.Parse()) if (parserTools.errors.Count == 0) parserTools.AddError("Неопознанная синтаксическая ошибка!", null); - foreach (Error err in parserTools.errors) - { - this.parserTools.errors.Add(err); - } + + this.parserTools.errors.AddRange(parserTools.errors); + return parser.root as expression; } @@ -510,7 +508,10 @@ namespace Languages.Pascal.Frontend.Core for (int i = 0; i < vars.Count; i++) { string s = vars[i]; - var expr = ParseExpression(new string('\n', str.source_context.begin_position.line_num - 1) + new string(' ', str.source_context.begin_position.column_num + var_offsets[i] + 2) + s, str.source_context.begin_position.line_num, str.source_context.begin_position.column_num + var_offsets[i] + 2); + + // Применяем здесь еще одну версию парсера вследствие ручной реализации разбора интерполированной строки + var expr = ParseExpression(new string('\n', str.source_context.begin_position.line_num - 1) + new string(' ', str.source_context.begin_position.column_num + var_offsets[i] + 2) + s); //, str.source_context.begin_position.line_num, str.source_context.begin_position.column_num + var_offsets[i] + 2); + if (expr == null) { var err = parserTools.errors[0] as LocatedError;