Лекции по построению компилятора на Pascal
Когда Никлаус Вирт разработал Паскаль, его желанием было ограничить количество уровней
приоритета (меньше подпрограмм синтаксического анализа, в конце концов). Так операторы
OR и исключающее OR рассматриваются просто как Addop и обрабатываются на уровне
математического выражения. Аналогично AND рассматривается подобно Mulop и
обрабатывается с Term. Уровни приоритета:
Уровень Синтаксический элемент Оператор
0 factor literal, variable
1 signed factor unary minus, NOT
2 term *, /, AND
3 expression +, -, OR
Заметьте, что имеется только один набор синтаксических правил, применимый к обоим
видам операторов. Тогда согласно этой грамматике выражения типа:
#### x + (y AND NOT z) DIV 3
являются совершенно допустимыми. И, фактически, они таковыми являются... настолько,
насколько синтаксический анализатор в этом заинтересован. Паскаль не позволяет
смешивать арифметические и логические переменные, и подобные вещи скорее
перехватываются на семантическом уровне, когда придет время генерировать для них код,
чем на синтаксическом уровне.
Авторы C взяли диаметрально противоположный метод: они обрабатывают операторы как
разные и C имеет что-то гораздо более похожее на наши семь уровней приоритета.
Фактически, в C имеется не менее 17 уровней! Дело в том, что C имеет также операторы '=',
'+=' и их родственников '<<', '>>', '++', '--' и т.д. Как ни странно, хотя в C арифметические и
булевы операторы обрабатываются раздельно, то переменные нет... в C нет никаких булевых
или логических переменных, так что логическая проверка может быть сделана на любом
целочисленном значении.
Мы сделаем нечто среднее. Я склонен обычно придерживаться Паскалевского подхода, так
как он кажется самым простым с точки зрения реализации, но это приводит к некоторым
странностям, которые я никогда очень сильно не любил, как например в выражении:
#### IF (c >= 'A') and (c <= 'Z') then ...
скобки обязательны. Я никогда не мог понять раньше почему, и ни мой компилятор, ни
любой человек также не объясняли этого достаточно хорошо. Но сейчас мы все можем
видеть, что оператор "and", имеющий приоритет как у оператора умножения, имеет более
высокий приоритет, чем у операторов отношения, поэтому без скобок выражение
эквивалентно:
#### IF c >= ('A' and c) <= 'Z' then
что не имеет смысла.
В любом случае, я решил разделить операторы на различные уровни, хотя и не столько
много как в C.
#### <b-expression> ::= <b-term> [<orop> <b-term>]*
#### <b-term>###### ::= <not-factor> [AND <not-factor>]*
#### <not-factor>## ::= [NOT] <b-factor>
#### <b-factor>#### ::= <b-literal> | <b-variable> | <relation>
#### <relation>#### ::= | <expression> [<relop> <expression]
#### <expression>## ::= <term> [<addop> <term>]*
#### <term>######## ::= <signed factor> [<mulop> factor]*
#### <signed factor>::= [<addop>] <factor>
#### <factor>###### ::= <integer> | <variable> | (<b-expression>)
Эта грамматика приводит к тому же самому набору семи уровней, которые я показал ранее.
Действительно, это почти та же самая грамматика... я просто исключил заключенное в