
- •Структура компилятора. Типы транслирующих программ.
- •Определение языка. Синтаксис и семантика.
- •Порождающие грамматики Хомского. Примеры порождающих грамматик.
- •Контекстно-свободные грамматики.
- •Деревья вывода. Канонические выводы. Двусмысленные порождающие грамматики
- •Любой язык может быть порожден бесконечным числом грамматик.
- •Лексический анализ.
- •Пример структуры программы сканирования
- •Ll(n) и lr(n) – грамматики.
- •Ll(k)-грамматики
- •Lr(k) грамматики
- •Построение синтаксического графа.
- •Восходящий синтаксический анализ.
- •Пример:
- •Работа с таблицей символов.
- •Реализация в виде массива
- •Реализация в виде цепочной структуры (связанного списка)
- •2. Дополнительные затраты памяти, поскольку хранятся ссылки на последующий и, возможно, предыдущий элемент На практике также встречается комбинация этих подходов.
- •Восстановление при синтаксических ошибках.
- •Постфиксная запись.
- •Методы генерирования кода.
Методы генерирования кода.
Обычно одинаковые фрагменты внутренней записи кода (операция в постфиксной записи, четверка и пр.) формируют одни и те же команды машинного языка. Например, четверка PLUS_OP в случае, если все операции в процессоре, для которого генерируется код, выполняются над регистром- аккумулятором, всегда генерирует следующий код:
LOAD регистр, операнд 1, ADD регистр, операнд 2, STORE регистр, результат
Эта последовательность машинных команд является всегда корректной, но не обязательно оптимальной. Например, предложение X := X+Y*Z реализуется шестью командами:
LOAD регистр, Y (четверка (MULT_OP,Sy,Sz,T1)), MUL регистр, Z, STORE регистр,T1
LOAD регистр, X (четверка (ADD_OP,Sx,T1,Sx)), ADD регистр,T1, STORE регистр, X
в то время как можно построить более кототкую программу, дающую тот же результат:
LOAD регистр, Y, MUL регистр, Z, ADD регистр, X, STORE регистр, X
Отметим, что код, который генерируется непосредственным образом, является всегда правильным, но не всегда оптимальным. Поэтому желательно иметь средства, позволяющие изменить код, не влияя на
корректность вычислений.
Так как каждой четверке (или другому элементу промежуточной записи) в большинстве случаев соответствует единственная последовательность машинных команд, генератор кода обычно представлен набором подпрограмм, по одной на каждую четверку.
Грамматики арифметических выражений. Перевод арифметических выражений в ПОЛИЗ.
Ограничение типов правил, которые могут появляться в грамматике позволяет определить ряд специальных классов грамматик. Одна из стандартных классификаций известна как иерархия Хомского. Ее описывают
следующим образом:
1. Любая грамматика определенного ранее вида – грамматика типа 0.
2. Если для всех правил вида α → β, |α| ≤ |β|, где |α| и |β| – длина, т.е. число символов соответственно α и β, то грамматика называется грамматикой типа 1, или контекстно-зависимой (КЗ).
3. Если все левые части правил грамматики состоят из одного нетерминального символа, то это грамматика типа 2, или контекстно-свободная (КС).
4. Грамматика называется грамматикой типа 3, или регулярной, если каждое правило грамматики имеют одну из следующих форм.
Контекстно-свободная грамматика (КС-грамматика, бесконтекстная грамматика) — частный случай формальной грамматики (тип 2 по иерархии Хомского), у которой левые части всех продукций являются нетерминалами. Смысл термина «контекстно-свободная» заключается в том, что возможность применить продукцию к нетерминалу, в отличие от общего случая грамматики Хомского, не зависит от контекста этого нетерминала.
Язык, который может быть задан КС-грамматикой, называется контекстно-свободным языком или КС-языком.
Типы КС грамматик
LL-грамматика
LALR-грамматика (см.: LALR(1))
LR-грамматика
SLR-грамматика (см.: SLR(1)
Арифметическое выражение
Терминалы: '+', '-', '*', '/', '(', ')', 'x'
нетерминалы: <выражение>, <слагаемое>, <множитель>
начальный нетерминал: <выражение>.
Этой грамматикой задаётся арифметическое выражение, содержащее простейшие арифметические действие над переменной x. Если заменить терминал 'x' на нетерминал <число> из предыдущего примера, то получится грамматика, задающая арифметическое выражение, состоящее из операций сложения, вычитания, умножение и деления над целыми числами.
Синтаксически управляемый перевод на примере перевода арифметического выражения в ПОЛИЗ.
Продолжая рассмотренный алгоритм, приведём реальный пример перевода выражения с языка Паскаль в обратную польскую запись.
Так как выражение присваивания обычно имеет вид <переменная>:= <выражение>, то приоритет операции присваивания должен быть менее приоритета скобок, а приоритет операций ссылки по указателю, и ссылки на структуру наивысший. Отдельно отметим, что операция адресации "@" прямо не является операцией, а лишь префиксом, который отменяет последнюю адресацию, хотя при соответствующем генераторе кода с возможностью отмены последней ссылки адресация может быть обработана как обычная операция в стеке.
Последний штрих - после конца строки мы выталкиваем оператор присваивания неким фиктивным оператором, приоритет которого менее приоритета оператора присваивания.
Для исполнения выражения, записаного в обратной польской записи необходима организация арифметического стека. Арифметический стек используется для хранения промежуточных результатов. Переменные (их значения), встречающиеся в правой части выражения заносятся на стек, операторы преобразовывают верхние два, три или одно число в результат, операнды снимаются со стека и туда помещается результат. Оператор присваивания снимает со стека адрес переменной и значение, которое надо поместить по этому адресу. Детальнее расмотрим алгоритм генерации кода через раздел.
Представление условных операторов, операторов цикла и оператора безусловного перехода в ПОЛИЗ.
Условные операторы, операторы цикла и операторы безусловного перехода довольно легко представляются в обратной польской записи. В любом случае внутри этих операторов лежат безусловный и условный переходы.