Каков общий способ реализации приоритета операторов в Python? - PullRequest
2 голосов
/ 23 ноября 2011

Предположим, я хотел бы написать довольно простой язык программирования и реализовать такие операторы, как 2 + 3 * 2 = 8

Каков общий способ реализации подобных вещей?

Ответы [ 2 ]

11 голосов
/ 23 ноября 2011

Я не уверен, насколько подробно вы интересуетесь, но звучит так, будто вы пытаетесь реализовать парсер.Обычно есть два шага:

Лексер читает текст и преобразует его в токены.Например, он может прочитать «2 + 3 * 2» и преобразовать его в INTEGER PLUS INTEGER STAR INTEGER

Синтаксический анализатор читает в токенахи пытается сопоставить их с правилами.Например, у вас могут быть следующие правила:

Expr := Sum | Product | INTEGER;
Sum := Expr PLUS Expr;
Product := Expr STAR Expr;

Он читает токены и пытается применить правила таким образом, чтобы правило запуска сопоставлялось с токенами, в которых он прочитан. В этом случае он может выполнить:

Expr := Sum
Expr := Expr PLUS Expr
Expr := INTEGER(2) PLUS Expr
Expr := INTEGER(2) PLUS Product
Expr := INTEGER(2) PLUS Expr STAR Expr
Expr := INTEGER(2) PLUS Integer(3) STAR Expr
Expr := INTEGER(2) PLUS Integer(3) STAR Integer(2)

Существует много типов синтаксических анализаторов.В этом примере я читал слева направо и начинал с начального выражения, работая до тех пор, пока не заменил все токеном, так что это будет LL-парсер .Выполняя эту замену, он может генерировать абстрактное синтаксическое дерево 1023 *, которое представляет данные.Дерево для этого может выглядеть примерно так:

Снимок экрана AST http://so.mrozekma.com/parser1.png

Вы можете видеть, что правило Product является дочерним по отношению к правилу Sum, поэтому в конечном итоге оно произойдет первым: 2 + (3 * 2).Если бы выражение было проанализировано по-другому, мы могли бы получить это дерево:

Снимок экрана AST http://so.mrozekma.com/parser2.png

Теперь мы вычисляем (2 + 3) * 2.Все сводится к тому, как синтаксический анализатор генерирует дерево


Если вы действительно хотите анализировать выражения, скорее всего, вы не хотите писать анализатор вручную.Существуют генераторы синтаксического анализатора , которые принимают конфигурацию (называемую грамматика ), аналогичную той, которую я использовал выше, и генерируют фактический код синтаксического анализатора.Генераторы синтаксических анализаторов позволят вам указать, какое правило должно иметь приоритет, например:

Expr := Sum | Product | INTEGER;
Sum := Expr PLUS Expr; [2]
Product := Expr STAR Expr; [1]

Я пометил правило Product как приоритет 1, а Sum как приоритет 2, поэтому, учитывая выбор, сгенерированный синтаксический анализатор предпочтет Product,Вы также можете создать саму грамматику так, чтобы приоритет был встроенным (это более распространенный подход).Например:

Expr := Sum | INTEGER;
Sum := Expr PLUS Product;
Product := Term STAR INTEGER;

Это приводит к тому, что продукты находятся под суммами в AST.Естественно, эта грамматика очень ограничена (например, она не будет соответствовать 2 * 3 + 2), но можно написать всеобъемлющую грамматику, которая по-прежнему автоматически включает порядок операций

4 голосов
/ 23 ноября 2011

Вам нужно написать парсер для вашего довольно простого языка программирования. Если вы хотите сделать это в Python, начните с чтения сообщения в блоге Неда Батчелдера Инструменты разбора Python .

...