Directives fixes (#3110)
* Unify directive errors * Add new quotesAreSpecialSymbols field to DirectifeInfo * Rewrite directive parsing and checks * Delete R+ directive from pascal tests
This commit is contained in:
parent
edf3358b39
commit
acb1be8c92
|
|
@ -9,6 +9,7 @@ using System.Text.RegularExpressions;
|
|||
using QUT.Gppg;
|
||||
using PascalABCCompiler.Parsers;
|
||||
using PascalABCCompiler.ParserTools.Directives;
|
||||
using System.Text;
|
||||
|
||||
namespace PascalABCCompiler.ParserTools
|
||||
{
|
||||
|
|
@ -106,19 +107,96 @@ namespace PascalABCCompiler.ParserTools
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Проверка директивы с помощью проверок из Parser.ValidDirectives
|
||||
/// Обычный разбор параметров директивы (кавычки - не спецсимволы)
|
||||
/// </summary>
|
||||
protected List<string> SplitDirectiveParamsOrdinary(string parameters)
|
||||
{
|
||||
List<string> words;
|
||||
|
||||
words = parameters.Split(new char[] { ' ', '\t', '\v', '\f', '\u00A0' }, StringSplitOptions.RemoveEmptyEntries).ToList();
|
||||
|
||||
return words;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Разбор параметров директивы, который воспринимает кавычки как спецсимволы (все символы внутри кавычек добавляются)
|
||||
/// </summary>
|
||||
protected List<string> SplitDirectiveParamsWithQuotesAsSpecialSymbols(string parameters)
|
||||
{
|
||||
List<string> words = new List<string>();
|
||||
|
||||
bool isInQuotes = false;
|
||||
StringBuilder currentWord = new StringBuilder();
|
||||
|
||||
for (int i = 0; i < parameters.Length; i++)
|
||||
{
|
||||
char c = parameters[i];
|
||||
|
||||
if (c == '\'' && !isInQuotes)
|
||||
{
|
||||
isInQuotes = true;
|
||||
}
|
||||
else if (c == '\'' && isInQuotes)
|
||||
{
|
||||
isInQuotes = false;
|
||||
}
|
||||
else if (char.IsWhiteSpace(c) && !isInQuotes)
|
||||
{
|
||||
if (currentWord.Length != 0)
|
||||
{
|
||||
words.Add(currentWord.ToString());
|
||||
currentWord.Clear();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
currentWord.Append(c);
|
||||
}
|
||||
}
|
||||
|
||||
if (isInQuotes)
|
||||
currentWord.Insert(0, '\'');
|
||||
|
||||
if (currentWord.Length != 0)
|
||||
{
|
||||
words.Add(currentWord.ToString());
|
||||
}
|
||||
|
||||
return words;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Получение имени директивы из строки с именем и параметрами
|
||||
/// </summary>
|
||||
protected string GetDirectiveName(string directiveText)
|
||||
{
|
||||
string directiveTrimmed = directiveText.Trim();
|
||||
string directiveName = "";
|
||||
|
||||
for (int i = 0; i < directiveTrimmed.Length; i++)
|
||||
{
|
||||
char c = directiveTrimmed[i];
|
||||
|
||||
if (char.IsWhiteSpace(c))
|
||||
{
|
||||
directiveName = directiveTrimmed.Substring(0, i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (directiveName == "")
|
||||
directiveName = directiveTrimmed;
|
||||
|
||||
return directiveName;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Проверка парамтеров директивы с помощью проверок из Parser.ValidDirectives
|
||||
/// </summary>
|
||||
public void CheckDirectiveParams(string directiveName, List<string> directiveParams, SourceContext loc)
|
||||
{
|
||||
BaseParser parserNeeded = ParserCached;
|
||||
|
||||
// проверка имени директивы
|
||||
if (!parserNeeded.ValidDirectives.ContainsKey(directiveName))
|
||||
{
|
||||
AddWarningFromResource("UNKNOWN_DIRECTIVE{0}", loc, directiveName); // предупреждение для совместимости с Delphi
|
||||
return;
|
||||
}
|
||||
|
||||
var directiveInfo = parserNeeded.ValidDirectives[directiveName];
|
||||
|
||||
// случай директивы, переданной без параметров
|
||||
|
|
|
|||
|
|
@ -16,11 +16,13 @@ namespace PascalABCCompiler.ParserTools.Directives
|
|||
|
||||
public int[] paramsNums = new int[1] { 1 }; // по умолчанию один параметр
|
||||
public bool checkParamsNumNeeded;
|
||||
public bool quotesAreSpecialSymbols;
|
||||
|
||||
// по умолчанию никаких проверок параметров, но включена проверка их кол-ва
|
||||
public DirectiveInfo(ParamChecksCollection paramChecks = null, bool checkParamsNumNeeded = true, int[] paramsNums = null)
|
||||
public DirectiveInfo(ParamChecksCollection paramChecks = null, bool quotesAreSpecialSymbols = false, bool checkParamsNumNeeded = true, int[] paramsNums = null)
|
||||
{
|
||||
this.checks = paramChecks;
|
||||
this.quotesAreSpecialSymbols = quotesAreSpecialSymbols;
|
||||
if (paramsNums != null)
|
||||
this.paramsNums = paramsNums;
|
||||
this.checkParamsNumNeeded = checkParamsNumNeeded;
|
||||
|
|
@ -110,7 +112,7 @@ namespace PascalABCCompiler.ParserTools.Directives
|
|||
|
||||
public override bool CheckParam(string param)
|
||||
{
|
||||
return Regex.IsMatch(param, @"^[\p{L}_][\p{L}0-9_]*$");
|
||||
return Regex.IsMatch(param, @"^[\p{L}_][\p{L}0-9_]*$", RegexOptions.Compiled);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -216,6 +218,11 @@ namespace PascalABCCompiler.ParserTools.Directives
|
|||
{
|
||||
return new ParamChecksCollection(new IsValidIdentifierCheck(1));
|
||||
}
|
||||
|
||||
public static ParamChecksCollection IsValidVersionCheck()
|
||||
{
|
||||
return new ParamChecksCollection(new FuncCheck(s => Regex.IsMatch(s, @"^\d+\.\d+\.\d+$"), ParserErrorsStringResources.Get("INVALID_VERSION")));
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -107,41 +107,35 @@ namespace PascalABCSavParser
|
|||
/// </summary>
|
||||
public void ParseDirective(string directive, QUT.Gppg.LexLocation location, out string directiveName, out List<string> directiveParams)
|
||||
{
|
||||
directiveName = null;
|
||||
// текст без спецсимволов {$}
|
||||
string directiveText = directive.Substring(2, directive.Length - 3);
|
||||
directiveName = GetDirectiveName(directiveText);
|
||||
directiveParams = new List<string>();
|
||||
|
||||
List<string> words = Regex.Split(directive, @"('.*?')|\s+").Where(word => word != "").ToList();
|
||||
|
||||
// подсоединяем } к последнему слову
|
||||
if (words.Last() == "}")
|
||||
{
|
||||
words[words.Count - 2] += "}";
|
||||
words.RemoveAt(words.Count - 1);
|
||||
}
|
||||
|
||||
// пустая директива - ошибка
|
||||
if (words[0] == "{$}")
|
||||
if (directiveName == "")
|
||||
{
|
||||
AddErrorFromResource("EMPTY_DIRECTIVE", location);
|
||||
return;
|
||||
}
|
||||
|
||||
// подсоединяем первое слово к {$
|
||||
if (words[0] == "{$")
|
||||
|
||||
// проверка имени директивы
|
||||
if (!ParserCached.ValidDirectives.ContainsKey(directiveName))
|
||||
{
|
||||
words[0] += words[1];
|
||||
words.RemoveAt(1);
|
||||
AddErrorFromResource("UNKNOWN_DIRECTIVE{0}", location, directiveName);
|
||||
return;
|
||||
}
|
||||
|
||||
if (words.Count == 1)
|
||||
// подстрока с параметрами
|
||||
string paramsString = directiveText.Substring(directiveText.IndexOf(directiveName) + directiveName.Length);
|
||||
|
||||
if (ParserCached.ValidDirectives[directiveName].quotesAreSpecialSymbols)
|
||||
{
|
||||
directiveName = words[0].Substring(2, words[0].Length - 3);
|
||||
directiveParams = SplitDirectiveParamsWithQuotesAsSpecialSymbols(paramsString);
|
||||
}
|
||||
else
|
||||
{
|
||||
directiveName = words[0].Substring(2, words[0].Length - 2);
|
||||
words[words.Count - 1] = words[words.Count - 1].TrimEnd('}');
|
||||
directiveParams = words.Skip(1).Select(word => DeleteQuotesFromDirectiveParam(word)).ToList();
|
||||
directiveParams = SplitDirectiveParamsOrdinary(paramsString);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ using GPPGParserScanner;
|
|||
using GPPGPreprocessor3;
|
||||
using PascalABCCompiler.ParserTools.Directives;
|
||||
using static PascalABCCompiler.ParserTools.Directives.DirectiveHelper;
|
||||
using System.Text.RegularExpressions;
|
||||
|
||||
namespace PascalABCCompiler.PascalABCNewParser
|
||||
{
|
||||
|
|
@ -129,8 +130,8 @@ namespace PascalABCCompiler.PascalABCNewParser
|
|||
ValidDirectives = new Dictionary<string, DirectiveInfo>(StringComparer.CurrentCultureIgnoreCase)
|
||||
{
|
||||
[StringConstants.compiler_directive_apptype] = new DirectiveInfo(SingleAnyOfCheck("console", "windows", "dll", "pcu")),
|
||||
[StringConstants.compiler_directive_reference] = new DirectiveInfo(), // нет параметров - никаких проверок
|
||||
[StringConstants.compiler_directive_include_namespace] = new DirectiveInfo(),
|
||||
[StringConstants.compiler_directive_reference] = new DirectiveInfo(quotesAreSpecialSymbols: true),
|
||||
[StringConstants.compiler_directive_include_namespace] = new DirectiveInfo(quotesAreSpecialSymbols: true),
|
||||
[StringConstants.compiler_directive_savepcu] = new DirectiveInfo(SingleAnyOfCheck("true", "false")),
|
||||
[StringConstants.compiler_directive_zerobasedstrings] = new DirectiveInfo(SingleAnyOfCheck("on", "off"), paramsNums: new int[2] { 0, 1 }),
|
||||
[StringConstants.compiler_directive_zerobasedstrings_ON] = null, // от null, скорее всего, придется избавиться, это не лучший подход EVA
|
||||
|
|
@ -139,7 +140,7 @@ namespace PascalABCCompiler.PascalABCNewParser
|
|||
[StringConstants.compiler_directive_nullbasedstrings_OFF] = null,
|
||||
[StringConstants.compiler_directive_initstring_as_empty_ON] = null,
|
||||
[StringConstants.compiler_directive_initstring_as_empty_OFF] = null,
|
||||
[StringConstants.compiler_directive_resource] = new DirectiveInfo(),
|
||||
[StringConstants.compiler_directive_resource] = new DirectiveInfo(quotesAreSpecialSymbols: true),
|
||||
[StringConstants.compiler_directive_platformtarget] = new DirectiveInfo(SingleAnyOfCheck("x86", "x64", "anycpu", "dotnet5win", "dotnet5linux", "dotnet5macos", "native")),
|
||||
[StringConstants.compiler_directive_faststrings] = null,
|
||||
[StringConstants.compiler_directive_gendoc] = new DirectiveInfo(SingleAnyOfCheck("true", "false")),
|
||||
|
|
@ -151,16 +152,16 @@ namespace PascalABCCompiler.PascalABCNewParser
|
|||
[StringConstants.compiler_directive_else] = new DirectiveInfo(SingleIsValidIdCheck(), paramsNums: new int[2] { 0, 1 }),
|
||||
[StringConstants.compiler_directive_undef] = new DirectiveInfo(SingleIsValidIdCheck()),
|
||||
[StringConstants.compiler_directive_define] = new DirectiveInfo(SingleIsValidIdCheck()),
|
||||
[StringConstants.compiler_directive_include] = new DirectiveInfo(),
|
||||
[StringConstants.compiler_directive_include] = new DirectiveInfo(quotesAreSpecialSymbols: true),
|
||||
[StringConstants.compiler_directive_targetframework] = new DirectiveInfo(),
|
||||
[StringConstants.compiler_directive_hidden_idents] = null,
|
||||
[StringConstants.compiler_directive_version_string] = new DirectiveInfo(),
|
||||
[StringConstants.compiler_directive_product_string] = new DirectiveInfo(),
|
||||
[StringConstants.compiler_directive_company_string] = new DirectiveInfo(),
|
||||
[StringConstants.compiler_directive_trademark_string] = new DirectiveInfo(),
|
||||
[StringConstants.compiler_directive_main_resource_string] = new DirectiveInfo(),
|
||||
[StringConstants.compiler_directive_title_string] = new DirectiveInfo(),
|
||||
[StringConstants.compiler_directive_description_string] = new DirectiveInfo(),
|
||||
[StringConstants.compiler_directive_version_string] = new DirectiveInfo(IsValidVersionCheck()),
|
||||
[StringConstants.compiler_directive_product_string] = new DirectiveInfo(quotesAreSpecialSymbols: true),
|
||||
[StringConstants.compiler_directive_company_string] = new DirectiveInfo(quotesAreSpecialSymbols: true),
|
||||
[StringConstants.compiler_directive_trademark_string] = new DirectiveInfo(quotesAreSpecialSymbols: true),
|
||||
[StringConstants.compiler_directive_main_resource_string] = new DirectiveInfo(quotesAreSpecialSymbols: true),
|
||||
[StringConstants.compiler_directive_title_string] = new DirectiveInfo(quotesAreSpecialSymbols: true),
|
||||
[StringConstants.compiler_directive_description_string] = new DirectiveInfo(quotesAreSpecialSymbols: true),
|
||||
[StringConstants.compiler_directive_omp] = new DirectiveInfo(SingleAnyOfCheck("critical", "parallel"), checkParamsNumNeeded: false)
|
||||
};
|
||||
#endregion
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
{$R+}
|
||||
|
||||
var
|
||||
var
|
||||
b : byte:=1;
|
||||
sh : shortint:=2;
|
||||
sm : smallint:=3;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,4 @@
|
|||
{$R+}
|
||||
|
||||
var
|
||||
var
|
||||
b : byte:=1;
|
||||
sh : shortint:=2;
|
||||
sm : smallint:=3;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
unit u_set7;
|
||||
{$R+}
|
||||
unit u_set7;
|
||||
|
||||
var
|
||||
b : byte:=1;
|
||||
|
|
|
|||
|
|
@ -17,7 +17,7 @@ DUPLICATE_DIRECTIVE{0}=Duplicate directive {0}
|
|||
FILE_{0}_NOT_FOUND=File '{0}' not found
|
||||
NAMESPACE_CAN_BE_COMPILED_ONLY_IN_PROJECTS=Files with namespaces can be compiled only inside projects
|
||||
NAMESPACE_CANNOT_HAVE_IN_SECTION=Namespace cannot have 'in' section
|
||||
APPTYPE_DLL_IS_ALLOWED_ONLY_FOR_LIBRARIES= {$apptype dll} directive is allowed only for libraries
|
||||
APPTYPE_DLL_IS_ALLOWED_ONLY_FOR_LIBRARIES=Parameter 'dll' in 'apptype' directive is allowed only for libraries
|
||||
USES_IN_WRONG_NAME=Unit name in uses-in ({0}) must be same as file name ({1})
|
||||
UNSUPPORTED_TARGETFRAMEWORK_{0}=TargetFramework '{0}' is not supported
|
||||
UNSUPPORTED_TARGET_PLATFORM{0}=Platform '{0}' is not supported
|
||||
|
|
|
|||
|
|
@ -13,6 +13,7 @@ BAD_SOURCEFILE{0}_EXT=Can not choose parser for file '{0}'
|
|||
COMPILATION_ERROR{0}{1}{2}={0}{1} Compilation error: {2}
|
||||
|
||||
EXPECTED_IDENTIFIER=Expected identifier
|
||||
INVALID_VERSION=The version format should be MAJOR.MINOR.PATCH
|
||||
AVAILABLE_PARAM_VARIANTS{0}=Possible values are: {0}
|
||||
AVAILABLE_EXT_VARIANTS{0}=Possible file extensions: {0}
|
||||
SEE_THE_HELP_FOR_VARIANTS=You can find the possible values in the language documentation
|
||||
|
|
|
|||
|
|
@ -27,12 +27,11 @@ UNNECESSARY_DIRECTIVE_PARAM{0}=Directive '{0}' is used without parameters
|
|||
INCORRECT_DIRECTIVE_PARAM{0}{1}{2}=Invalid parameter '{0}' passed to directive '{1}'. {2}
|
||||
EMPTY_DIRECTIVE=Empty directive is not allowed
|
||||
DIRECTIVE_WRONG_NUMBER_OF_PARAMS{0}{1}=Directive '{0}' must have {1}
|
||||
INCLUDE_COULDNT_OPEN_FILE{0}=Compiler directive $include: can't open file '{0}'
|
||||
INCLUDE_EMPTY_FILE=Compiler directive $include: file name is absent
|
||||
RECUR_INCLUDE=Compiler directive $include: recursive include
|
||||
UNNECESSARY $endif=Extra $endif
|
||||
ENDIF_ABSENT=Not closed directive $ifdef or $ifndef - $endif is absent
|
||||
UNNECESSARY $else=Extra $else
|
||||
INCLUDE_COULDNT_OPEN_FILE{0}=Compiler directive 'include': can't open file '{0}'
|
||||
RECUR_INCLUDE=Compiler directive 'include': recursive include
|
||||
UNNECESSARY $endif=Extra 'endif'
|
||||
ENDIF_ABSENT=Not closed directive 'ifdef' or 'ifndef' - 'endif' is absent
|
||||
UNNECESSARY $else=Extra 'else'
|
||||
TYPE_NAME_EXPECTED=Type expected
|
||||
MULTILINE_STRING_CONTAINS_INCONSISTENT_INDENTS=Multiline string contains inconsistent indents
|
||||
NON_WHITESPACE_CHARACTERS_BEFORE_CLOSING_QUOTES_OF_MULTILINE_STRING=There should be no non-whitespace characters before the closing quotes of the multiline string
|
||||
|
|
|
|||
|
|
@ -9,7 +9,7 @@ UNIT_{0}_NOT_FOUND=Модуль '{0}' не найден
|
|||
SOURCE_FILE_{0}_NOT_FOUND=Файл '{0}' не найден
|
||||
NO_ACCESS_TO_FILE{0}=Не могу получить доступ к файлу '{0}'
|
||||
CYCLIC_UNIT_REFERENCE_WITH_UNIT_{0}=Циклическая связь с модулем '{0}'
|
||||
UNDEFINED_SEMANTIC_ERROR{0}=Неопределенная семантическая ошибка : {0}
|
||||
UNDEFINED_SEMANTIC_ERROR{0}=Неопределенная семантическая ошибка : {0}
|
||||
RESOURCEFILE_{0}_NOT_FOUND=Файл '{0}' не найден
|
||||
DUPLICATE_USES_UNIT{0}=Повторное подключение модуля {0} в секции uses
|
||||
MAINRESOURCE_NOT_ALLOWED=Недопустимо совместное использование директивы mainresource и директив product, version, company, trademark, title, description, copyright
|
||||
|
|
@ -17,7 +17,7 @@ DUPLICATE_DIRECTIVE{0}=Повторное объявление директив
|
|||
NAMESPACE_CAN_BE_COMPILED_ONLY_IN_PROJECTS=Компиляция файлов с пространствами имен допустима только в проектах
|
||||
FILE_{0}_NOT_FOUND=Файл '{0}' не найден
|
||||
NAMESPACE_CANNOT_HAVE_IN_SECTION=Для пространства имен не может указываться секция in
|
||||
APPTYPE_DLL_IS_ALLOWED_ONLY_FOR_LIBRARIES=Директива {$apptype dll} возможна только для библиотек
|
||||
APPTYPE_DLL_IS_ALLOWED_ONLY_FOR_LIBRARIES=Параметр 'dll' директивы 'apptype' разрешается только для библиотек
|
||||
USES_IN_WRONG_NAME=Имя модуля в uses-in ({0}) должно совпадать с именем файла ({1})
|
||||
UNSUPPORTED_TARGETFRAMEWORK_{0}=TargetFramework '{0}' не поддерживается
|
||||
UNSUPPORTED_TARGET_PLATFORM{0}=Платформа '{0}' не поддерживается
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ BAD_SOURCEFILE{0}_EXT=Не могу выбрать подходящий парс
|
|||
COMPILATION_ERROR{0}{1}{2}={0}{1} Ошибка компиляции: {2}
|
||||
|
||||
EXPECTED_IDENTIFIER=Ожидался идентификатор
|
||||
INVALID_VERSION=Формат версии должен соответствовать шаблону MAJOR.MINOR.PATCH
|
||||
AVAILABLE_PARAM_VARIANTS{0}=Допустимые значения: {0}
|
||||
AVAILABLE_EXT_VARIANTS{0}=Допустимые расширения файла: {0}
|
||||
SEE_THE_HELP_FOR_VARIANTS=Уточните допустимые значения в документации языка
|
||||
|
|
@ -26,12 +26,11 @@ UNNECESSARY_DIRECTIVE_PARAM{0}=Директива '{0}' не допускает
|
|||
INCORRECT_DIRECTIVE_PARAM{0}{1}{2}=Недопустимый параметр '{1}' для директивы '{0}'. {2}
|
||||
EMPTY_DIRECTIVE=Пустая директива недопустима
|
||||
DIRECTIVE_WRONG_NUMBER_OF_PARAMS{0}{1}=Директива '{0}' должна иметь {1}
|
||||
INCLUDE_COULDNT_OPEN_FILE{0}=Директива компилятора $include: нельзя открыть файл '{0}'
|
||||
INCLUDE_EMPTY_FILE=Директива компилятора $include: не указано имя файла
|
||||
RECUR_INCLUDE=Директива компилятора $include: рекурсивное включение файла
|
||||
UNNECESSARY $endif=Лишний $endif
|
||||
ENDIF_ABSENT=Незакрытая директива $ifdef или $ifndef - отсутствует $endif
|
||||
UNNECESSARY $else=Лишний $else
|
||||
INCLUDE_COULDNT_OPEN_FILE{0}=Директива компилятора 'include': нельзя открыть файл '{0}'
|
||||
RECUR_INCLUDE=Директива компилятора 'include': рекурсивное включение файла
|
||||
UNNECESSARY $endif=Лишний 'endif'
|
||||
ENDIF_ABSENT=Незакрытая директива 'ifdef' или 'ifndef' - отсутствует 'endif'
|
||||
UNNECESSARY $else=Лишний 'else'
|
||||
TYPE_NAME_EXPECTED=Ожидался тип
|
||||
MULTILINE_STRING_CONTAINS_INCONSISTENT_INDENTS=Мультистрочная строка содержит несовместимые отступы
|
||||
NON_WHITESPACE_CHARACTERS_BEFORE_CLOSING_QUOTES_OF_MULTILINE_STRING=Перед закрывающими кавычками многострочной строки не должно быть непробельных символов
|
||||
|
|
|
|||
Loading…
Reference in a new issue