У меня есть простая грамматика.На самом деле, грамматика, которую я использую, является более сложной, но это наименьшее подмножество, иллюстрирующее мой вопрос.
Expr ::= Value Suffix
| "(" Expr ")" Suffix
Suffix ::= "->" Expr
| "<-" Expr
| Expr
| epsilon
Value
соответствует идентификаторам, строкам, числам и так далее.Правило Suffix
предназначено для устранения левой рекурсии.Это соответствует выражениям, таким как:
a -> b (c -> (d) (e))
То есть график, где a
обращается к b
и результату (c -> (d) (e))
, а c
к d
и e
.Я пытаюсь создать абстрактное синтаксическое дерево для этих выражений, но я сталкиваюсь с трудностями, потому что все операторы могут принимать любое количество операндов на каждой стороне.Я бы предпочел сохранить логику для создания AST в методах синтаксического анализа рекурсивного спуска, так как это избавляет от необходимости дублировать логику извлечения выражения.Моя текущая стратегия такова:
Если появляется Value
, нажмите его на выходе.
Если From
илиTo
Появится:
Вывести разделитель.
Получить следующее Expr
.
Создание узла Link
.
Вставка первого набора операндов с выхода в Link
до появления разделителя.
Сотрите обнаруженный разделитель.
Вставьте второй набор операндов в Link
до разделителя.
Нажмите Link
к выводу.
Если я выполню это без выполнения шагов 2.3–2.7, я получу список значений и разделителей.Для приведенного выше выражения a -> b (c -> (d) (e))
результат должен быть следующим:
A sep_1 B sep_2 C sep_3 D E
Применение правила To
приведет к получению:
A sep_1 B sep_2 (link from C to {D, E})
И впоследствии:
(link from A to {B, (link from C to {D, E})})
Важно отметить, что sep_2
, крайне важный для разграничения левых операндов второго ->
, не появляется, поэтому синтаксический анализатор считает, что выражение действительно было записано:
a -> (b c -> (d) (e))
Чтобы решить эту проблему с моей текущей стратегией, мне нужен способ создать разделитель между смежными выражениями, но только если текущее выражение является выражением From
или To
, заключенным в скобки.Если это возможно, то я просто не вижу этого, и ответ должен быть простым.Однако, если есть лучший способ сделать это, пожалуйста, дайте мне знать!