Насколько я понимаю, большинство языков не содержат контекста с некоторыми исключениями. Например, a * b
может стоять за type * pointer_declaration
или умножать на C++. Что происходит, зависит от контекста, значения первого идентификатора. Другим примером является name
производство в VHDLКак преобразовать парсер PEG в двусмысленный?
enum_literal ::= char_literal | identifer
physical_literal ::= [num] unit_identifier
func_call ::= func_identifier [parenthized_args]
array_indexing ::= arr_name (index_expr)
name ::= func_call | physical_literal | enum_litral | array_indexing
Вы видите, что синтаксические формы различны, но они могут совпадать, если дополнительные параметры опущены, как f
, это подставка для func_call, physical_literal, как 1 метр с дополнительным количество 1 подразумеваемый или enum_literal.
Говоря о дизайнерах плагинов Scala, я получил образование, чтобы знать, что вы строите AST, чтобы переоценить его при изменении зависимостей. Нет необходимости повторно разбирать файл, если у вас есть его AST. AST также стоит отображать содержимое файла. Но AST недействителен, если грамматика является контекстно-зависимой (предположим, что f
была функцией, определенной в другом файле, но позже пользователь перепрофилировал ее в enum literal или undefined). AST изменяет в этом случае. AST изменяется при каждом изменении зависимостей. Другой вариант, который я прошу оценить и дать мне знать, как это сделать, заключается в создании неоднозначного АСТ.
Насколько я знаю, комбинаторы парсеров PEG kind. They hide the ambiguity by returning you the first matched production и f
будут соответствовать вызову функции, потому что это первая альтернатива в моей грамматике. Я прошу комбинатора, что вместо того, чтобы вернуться к первому успеху, он переходит к следующей альтернативе. В конце концов, он вернет мне список всех подходящих альтернатив. Это вернет мне двусмысленность.
Я не знаю, как бы вы отображали неоднозначное дерево содержимого файла для пользователя, но это устранило бы необходимость повторного анализа зависимых файлов. Я также был бы рад узнать, как современный дизайн языка решает эту проблему.
После того, как неоднозначный узел разобран и неоднозначность результатов возвращается, я хотел бы, чтобы синтаксический анализатор сходился, потому что я хотел бы продолжить синтаксический анализ за пределами name
, и я не хочу анализировать до конца файла после каждой двусмысленности. Ситуация осложняется такими ситуациями, как f(10)
, которая может быть вызовом функции с единственным аргументом или вызовом функции с нулевым значением, которые возвращают массив, который затем индексируется. Таким образом, f (10) может соответствовать названию двумя способами: либо func_call
напрямую, либо рекурсивно, как arr_indexing -> name ~ (expr)
. Таким образом, это не будет двусмысленно, как несколько параллельных правил, таких как fcall | literal
. Некоторые ветви могут быть длиннее 1 парсера до повторного схождения, например fcall ~ (expr) | fcall
.
Как бы вы решили его решить? Можно ли добавить неоднозначный комбинатор в PEG?
Гиперссылка теперь мертва и нуждается в обновлении. –