Транслятор.

Транслятор для входного языка, порождаемого грамматикой предшествования можно построить по классической схеме, в которой чётко выделяются 3 части: лексический анализатор, распознаватель (синтаксический анализатор) и генератор (семантический анализатор);

 

 

 

Цель лексического анализа состоит в переводе исходной программы на стандартный входной язык компилятора и преобразовании её к виду, удобному для дальнейшей обработки на этапах синтаксического и семантического анализа.

В процессе лексического анализа обычно собираются из отдельных знаков (букв и цифр) простые синтаксические конструкции – лексемы. Лексемы – минимальные единицы информации, наделённые смыслом (идентификаторы, цифры, служебные слова и т.д.). При дальнейшей обработке такие простые конструкции рассматриваются как неделимые, поэтому оставлять их распознавание и сборку до этапа синтаксического анализа невыгодно.

В общем случае, в процессе лексического анализа необходимо выполнить следующее:

1) Перекодировать исходную программу, рассматриваемую как входная строка, и привести её к стандартному входному языку.

2) Выделить и собрать из отдельных знаков основные символы языка – лексемы.

Распознаватель решает задачу разбора. Алгоритм для грамматик предшествования уже рассмотрен. В процессе синтаксического анализа распознаватель использует матрицу предшествования (или функции предшествования) и таблицу порождающих правил грамматики входного языка. Каждая запись этой таблицы содержит одно из порождающих правил и ( для некоторых правил) имя семантической подпрограммы, которую нужно выполнить, когда это правило применяется для редукции.

Результат работы распознавателя – разбор входной программы.

Генератор получает на вход разбор и, используя семантические подпрограммы, отвечающие применённым при разборе правилам, генерируют машинные команды или предложения другого входного языка.

Возможны 2 схемы работы транслятора.

Первая – использует блочный принцип, при котором части транслятора вызываются в последовательности: лексический анализатор, распознаватель, генератор. Каждая часть обрабатывает всю программу от начала до конца и только после этого работает следующая часть.

Во второй схеме используется принципы подпрограмм, когда все части транслятора работают совместно, каждый очередной входной символ лексического анализатора немедленно обрабатывается распознавателем, а каждый элемент разбора, если нужно, тут же вызывает требуемую семантическую подпрограмму генератора. Первую схему применяют, когда все части транслятора одновременно не умещаются в быстрой памяти машины, а вторую когда весь транслятор можно разместить в быстрой памяти.

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

Описываемый транслятор можно использовать для перевода с входного языка, грамматика которого является грамматикой предшествования. Для этого нужно прежде всего стандартизировать лексику входного языка, т.е. правила записи служебных слов, идентификаторов, констант и алфавита. Тогда алгоритм лексического анализатора будет определяться только особенностями устройств, применяемых для подготовки и ввода программ, и принятым стандартам ввода программ, и принятым стандартам входного языка распознавателя. Алгоритм распознавателя универсален в классе грамматик предшествования. Алгоритм генератора предельно прост – генератор вызывает требуемую семантическую подпрограмму и передаёт ей аргумент, определяемые элементом разбора.

Может быть предложена следующая структура данных грамматик простого предшествования для быстрой работы.

Таблица терминалов:

 

Число терминалов 255 длинна терминала не >31, но неограниченна

 

 

Таблица нетерминалов:

 

Начальный нетерминальный символ найти и поставит первым. После этого создать таблицу правил и правых частей и расширив таблицу нетерминалов.

Таблица нетерминалов:

Адрес нетерминала Индекс в таблице правил Количество правил

 

 


Таблица правил

Где число =(+) код терминала (индекс в таблице терминалов), =(-) код нетерминала (-индекс в таблице - нетерминалов). Таблица правил сортируется в порядке возрастания кодов нетерминалов.

А программа распознавателя с известным алгоритмом с помощью приведённых таблиц, матрицы предшествования и цифровой свёртки терминальной цепочки лексическим анализатором может построить дерево разбора, из которого выброшены терминальные элементы, а метки вершин «нетерминалы» заменены на соответствующие номера правил. Дерево разбора может быть представлено матрицей, каждая строка которой хранит следующую информацию:

Номер правила Левая часть количество отец Сын 1 Сын 2

23.11.Синтаксис входного языка задается таблицей порождающих правил. Используя эту таблицу, матрица предшествования строится автоматически.

Семантика входного языка в терминах выходного языка отражена в семантических подпрограммах, которые составляются в ручную. В принципе, описываемый транслятор пригоден для перевода с нескольких входных языков, грамматики которых – грамматики простого предшествования, на несколько выходных языков. За универсальность транслятора в классе грамматик предшествования приходится платить невысокой эффективностью алгоритмов трансляции.

Рассмотрим применение метода предшествования для преобразования в польскую обратную запись предложения языка, порождаемые грамматикой G'1. Чтобы язык был более реалистичен, будем считать, что в качестве идентификаторов в языке может использоваться строчная латинская буква. Каждая такая буква воспринимается распознавателем, как идентификатор И.

Составим таблицу порождающих правил, дополнив её семантическими подпрограммами для перевода её в польскую обратную запись:

Номер правила Порождающее правило Семантическая подпрограмма для перевода.
      П → B B→B' B'→T B'→B'+T   T→T' T'→M T'→T'xM   M→И   M→ (B)   «Записать символ '+' в выходную строку»     «Записать символ 'х' в выходную строку» «Записать идентификатор в выходную строку»

 

Трансляции a + bxc в польскую обратную запись, используя распознаватель предшествования, таблицу порождающих правил и семантических подпрограмм и матрицу предшествования, получаем:

 

Запись в выходную строку Стек распознавателя Отношение предшествования Входная строка N правила Семантическая подпрограмма
  а   a+bxc - -
а +bxc uв выходную строку
М +bxc -
Т' +bxc -
Т +bxc -
В' +bxc - -
В' bxc - -
В'b xc uв выходную строку
    b B'+M B'+T' B'+T'X B'T'XC xc xc c - - - - - uв выходную строку
c B'+T'X   xв выходную строку
x B'+T' B'+'T   - xв выходную строку
+ B' B - -
  M        

Если последовательно выписать символы, записываемые в ходе анализа в стек распознавателя и при успешном разборе дополнить полученную строку парой П, то получим (,-разделитель):
⊥,а, М, T',T,B',+,b,M,T',x,c,M,T’,T, ,П – которая представляет собой ОПЗ разбора, полученную обходом дерева разбора:

 

Cтроку можно записать короче, если заменить нетерминал номерами правил, применяемых для их получения: ,a,8,+,b,8,x,c,8,7,4.

Запись разбора в таком виде поступает на вход генератора кода. (см. схему)

Этап лексического анализа подготавливает исходную программу к синтаксическому анализу: убирает из текста программы комментарии, распознаёт и отделяет трансляционные директивы, выделяет и осуществляет свёртку лексем входного языка, что существенно влияет на выбор алгоритмов синтаксического анализа, который осуществляется не для входного языка L(G), а для преобразованного L(G’). Лексемы, наиболее часто выделяемые в языках программирования:

<идентификатор>, <служебные слова>, <целое число>, <вещественное число>, <одномерные разделители>, <двумерные разделители>, <комментарии>, <трансляционные дерективы> и т.п.

Если класс лексем L(Gk)(автоматный язык) бесконечен(например –идентификатор) или конечен, но достаточно велик, то выделяемые в программе лексемы tkL(Gk), заполняются в специальной таблице к, они являются элементами справочника транслятора и могут обслуживаться в зависимости от реализации специальными программами обслуживания таблиц, либо стандартными программами обслуживания справочника (метод хеширования).

Лексический анализатор – это следующие отображение:

lex:→ (V'T)* - преобразование, реализуемое сканером для входного языка L(G). На входе сканер lex воспринимает цепочку хVT*, а на входе выдаёт цепочку лексем у(V'T)*

Построение сканера осуществляется за несколько шагов:

1) Выделить во входном языке L(G) на основании описания его синтаксиса с помощью КС – грамматики G множество классов лексем Lk, 1≤k≤i, i1.

2) Видоизменить КС – грамматику G входного языка L(G), так чтобы она удовлетворяла следующим требованиям:

а) подмножество {U1,U2,…,Ui}VN (множество нетерминалов) i1, такое что, каждому, нетерминалу Uk можно поставить в соответствие автоматную грамматику Gk=(,, Pk, Uk), порождающую автоматный язык фраз L(Gk)={t­k|tk,Uk=>*tk}.

б) Языки L(Gk) (k=1,…,i)попарно не пересекаются. Т.е. k,j[1,i],ki, L(Gk)L(Gi)=.

в) Каждая цепочка xоднозначно представляется как конкатенация подцепочек из языков L(Gk), т.е. x=tk1,tk2,…, tkn,n1 tkjL(Gkj) 1≤j≤n, 1≤kj≤i.

Определим новую КС – грамматику G'=(VT', VN', P',S'), где VN'=VN \{U1,…,Ui}. VT'={V1,…,Vi}, P'=P\

Очевидно, что для каждого предложения xнайдётся !-ная цепочка yz;

b) S'=>*B->xαy;

c) Fk(y)=Fk(z)

Следует x'Ay=B, т.е. x'=,A=B,=y,VT*.

В определении отображено требование детерминированности выделения правой границы основы α, её однозначности и однозначности выбора А→α, для «свёртки» основы в анализируемой части х=x'α цепочки wi+1 =xy. Решение принимаемое на основании информации о правостороннем выводе цепочки x=x'и префиксе U цепочки y=Uy', U=Fk(u).

LR(k) грамматика впервые была изучена Кнутом, который нашёл для них эффективный метод построения детерминированных алгоритмов анализа.

Поведение МП автомата определяется верхним символом Tj магазина и k первыми символами (префикс u) непроанализированной части у цепочки wi+1.