Add constructors to scanner, parser and parserTools (#3185)

* Add constructors to scanner, parser and parserTools

Добавил конструкторы, чтобы код был почище

* Change type of keywords in Scanner

* Make cast explicit

* Rebuild ABCPascal.cs
This commit is contained in:
AlexanderZemlyak 2024-07-21 13:36:15 +03:00 committed by GitHub
parent ca141804c7
commit 35c7bc5877
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 127 additions and 101 deletions

View file

@ -25,7 +25,7 @@ namespace PascalABCCompiler.ParserTools
}
}
// Класс глобальных описаний и статических методов
// Класс глобальных описаний и общих методов
// для использования различными подсистемами парсера и сканера
public abstract class BaseParserTools
{
@ -38,13 +38,21 @@ namespace PascalABCCompiler.ParserTools
public string currentFileName;
public List<compiler_directive> compilerDirectives;
public static Dictionary<string, string> tokenNum; // строки, соответствующие терминалам, для вывода ошибок - SSM
public abstract Dictionary<string, string> TokenNum { get; protected set; } // строки, соответствующие терминалам, для вывода ошибок - SSM
public IParser ParserRef { get; private set; }
public Dictionary<string, DirectiveInfo> ValidDirectives { get; private set; }
protected BaseParserTools(IParser parserRef)
protected BaseParserTools(List<Error> errors, List<CompilerWarning> warnings,
Dictionary<string, DirectiveInfo> validDirectives, bool buildTreeForFormatter, bool buildTreeForFormatterStrings,
string currentFileName, List<compiler_directive> 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
/// </summary>
public void ValidateDirectiveParams(string directiveName, List<string> directiveParams, SourceContext loc)
{
var directiveInfo = ParserRef.ValidDirectives[directiveName];
var directiveInfo = ValidDirectives[directiveName];
if (directiveInfo.checkParamsNumNeeded)
{

View file

@ -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<string> Defines = new List<string>();
private Stack<BufferContext> buffStack = new Stack<BufferContext>();
private Stack<string> fNameStack = new Stack<string>();
private Stack<bool> IfDefInElseBranch = new Stack<bool>();
private Stack<string> IfDefVar = new Stack<string>();
public List<string> Defines = new List<string>();
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<string> 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 == "") // Ñ<EFBFBD>лÑ?Ñ?ай пÑ?Ñ<>Ñ?ой диÑ?екÑ?ивÑ?
if (directiveName == "") // сл<EFBFBD>?<3F>?ай п<>?с<>?ой ди<D0B4>?ек<D0B5>?ив<D0B8>?
break;
directiveName = directiveName.ToUpper();
@ -2284,7 +2290,7 @@ BEGIN(INITIAL);
parserTools.ParseDirective(yytext, CurrentLexLocation, out directiveName, out directiveParams);
orgDirectiveName = directiveName;
if (directiveName == "") // Ñ<EFBFBD>лÑ?Ñ?ай пÑ?Ñ<>Ñ?ой диÑ?екÑ?ивÑ?
if (directiveName == "") // сл<EFBFBD>?<3F>?ай п<>?с<>?ой ди<D0B4>?ек<D0B5>?ив<D0B8>?
break;
directiveName = directiveName.ToUpper();

View file

@ -1,18 +1,24 @@
%{
public PascalParserTools parserTools;
private PascalABCCompiler.Parsers.BaseKeywords keywords;
public PascalABCKeywords keywords;
public List<string> Defines = new List<string>();
private Stack<BufferContext> buffStack = new Stack<BufferContext>();
private Stack<string> fNameStack = new Stack<string>();
private Stack<bool> IfDefInElseBranch = new Stack<bool>();
private Stack<string> IfDefVar = new Stack<string>();
public List<string> Defines = new List<string>();
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<string> defines = null)
{
this.parserTools = parserTools;
this.keywords = (PascalABCKeywords)keywords;
if (defines != null)
this.Defines.AddRange(defines);
SetSource(text, 0);
}
%}
%namespace Languages.Pascal.Frontend.Core

View file

@ -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<PascalABCCompiler.ParserTools.Union, LexLocation> scanner) : base(scanner) { }
public GPPGParser(AbstractScanner<PascalABCCompiler.ParserTools.Union, LexLocation> scanner, PascalParserTools parserTools) : base(scanner)
{
this.parserTools = parserTools;
}
%}
%output=ABCPascalYacc.cs

View file

@ -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<var_def_statement> pascalABCVarStatements;
public List<type_declaration> pascalABCTypeDeclarations;
static PascalParserTools()
public override Dictionary<string, string> TokenNum { get; protected set; }
private void InitializeTokenNum()
{
tokenNum = new Dictionary<string, string>();
TokenNum = new Dictionary<string, string>()
{
["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<Error> errors, List<CompilerWarning> warnings,
Dictionary<string, DirectiveInfo> validDirectives, bool buildTreeForFormatter = false, bool buildTreeForFormatterStrings = false,
string currentFileName = null, List<compiler_directive> compilerDirectives = null)
: base(errors, warnings, validDirectives, buildTreeForFormatter, buildTreeForFormatterStrings, currentFileName, compilerDirectives)
{
NodesStack = new System.Collections.Stack();
pascalABCLambdaDefinitions = new List<function_lambda_definition>();
pascalABCVarStatements = new List<var_def_statement>();
pascalABCTypeDeclarations = new List<type_declaration>();
InitializeTokenNum();
}
protected override string ExtractDirectiveTextWithoutSpecialSymbols(string directive)

View file

@ -63,11 +63,14 @@ public partial class GPPGParser: ShiftReduceParser<PascalABCCompiler.ParserTools
public syntax_tree_node root; // <20>?о<>?невой <20>?зел син<D0B8>?акси<D181>?еского де<D0B4>?ева
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<PascalABCCompiler.ParserTools.Union, LexLocation> scanner) : base(scanner) { }
public GPPGParser(AbstractScanner<PascalABCCompiler.ParserTools.Union, LexLocation> scanner, PascalParserTools parserTools) : base(scanner)
{
this.parserTools = parserTools;
}
// End verbatim content from ABCPascal.y
#pragma warning disable 649

View file

@ -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)

View file

@ -396,27 +396,25 @@ namespace Languages.Pascal.Frontend.Core
return lcl;
}
public expression ParseExpression(string Text, int line, int col)
/// <summary>
/// Создает вторую версию парсера с целью применения части грамматики, связанной с нетерминалом expr.
/// </summary>
public expression ParseExpression(string Text)
{
PascalParserTools parserTools = new PascalParserTools(this.parserTools.ParserRef); // контекст сканера и парсера
parserTools.errors = new List<Error>();
parserTools.warnings = new List<CompilerWarning>();
parserTools.currentFileName = System.IO.Path.GetFullPath(this.parserTools.currentFileName);
parserTools.buildTreeForFormatterStrings = true;
Scanner scanner = new Scanner(this.parserTools.ParserRef.Keywords);
scanner.SetSource("<<expression>>"+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<Error>(), new List<CompilerWarning>(),
this.parserTools.ValidDirectives, false, true, this.parserTools.currentFileName); // контекст сканера и парсера
Scanner scanner = new Scanner("<<expression>>" + 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;