Министерство образования Российской Федерации ОРЕНБУРГСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ
Кафедра программного обеспечения...
46 downloads
170 Views
638KB Size
Report
This content was uploaded by our users and we assume good faith they have the permission to share this book. If you own the copyright to this book and it is wrongfully on our website, we offer a simple DMCA procedure to remove your content from our site. Start by pressing the button below!
Report copyright / DMCA form
Министерство образования Российской Федерации ОРЕНБУРГСКИЙ ГОСУДАРСТВЕННЫЙ УНИВЕРСИТЕТ
Кафедра программного обеспечения и автоматизированных систем
Д.Л. Домашова В.А.Стенюшкина
МЕТОДИЧЕСКИЕ УКАЗАНИЯ к лабораторным работам по курсу “Теория вычислительных процессов и структур”
Оренбург 2000 4
К 32.9730181Я7 91 УДК 681.3(07)
Meтодические указания для выполнения лабораторных работ по курсу «Теория вычислительных процессов и структур» для студентов 3-го курса специальности 220400 Введение Перевод программы, написанной на языке программирования, на машинный язык осуществляется программой, которая называется транслятором. В методических указаниях рассматриваются общие подходы к построению компиляторов и интерпретаторов, дано описание модельного языка MPL и построены лексический, синтаксический и семантический анализаторы для языка MPL. Далее рассмотрены перевод программы в польскую инверсионную запись (ПОЛИЗ) и построение интерпретатора ПОЛИЗа для модельных языков MPL и SOL. Приведены примерные варианты заданий для курсовых работ по построению транслятора для модельного языка MPL, а также интерпретаторов ПОЛИЗа и модельного языка SOL.
5
1 Основы теории 1.1 Нормальные формы Бэкуса Нормальные формы Бекуса, или металингвистические формулы, являются наиболее распространенным метасинтаксическим языком, используемым для описания многих языков программирования. Каждая металингвистическая формула описывает правила построения некоторой конструкции языка и состоит из двух частей: в левой части находится металингвистическая переменная, обозначающая соответствующую конструкцию; далее следует металингвистическая связка ": : = " ,имеющая смысл "по определению равно"; в правой части указывается один или несколько вариантов построения конструкции, обозначенной в левой части. Для того, чтобы построить определяемую формулой конструкцию, нужно выбрать некоторый вариант построения правой части формулы и подставить вместо каждой металингвистической переменной соответствующие цепочки основных символов. Варианты правой части формулы разделяются металингвистической связкой "|"., имеющей значение "или". Металингвистическая переменная обозначается словами языка разработчика, заключенными в угловые скобки. БНФ используются для описания формальных языков. Пример : <имя>::=<буква>|<имя><буква>|<имя><цифра> И::=Б|ИБ|ИЦ И,Б,Ц – метапеременные или нетерминальные символы (нетерминалы) Терминальные символы (терминалы) – символы из алфавита языка. Цепочка (строка)- любая последовательность из терминальных и нетерминальных символов. Терминальная цепочка – цепочка из терминальных символов Формальный язык – некоторое множество из терминальных цепочек. 1.1.1 Описание модельного языка MPL P::=program Д';Д. Д':: = var Д{,Д} Д :: = I{,I}: [int, bool] В :: = begin S {; S} end S :: = I:=E |if E then S else S| while E do S| B| read (I)| write (E) E :: = E1|E1[=,≠,<,≤,>,≥] El El :: = T|T+E1|T-E1|T El T :: = F|F*T|F/T| F∩T F :: = I|N|L|¬F|(E) L :: = true | false 6
I :: = Б|IБ | IЦ N:: = Ц| NЦ Б:: = a | b | … | z Ц::= 0 | 1 | … | 9 Правила: 1) любая переменная должна быть описана 2) в операторе присваивания типы должны совпадать 3) Е в условном операторе и в цикле while только логического типа 4) Е1 в выражениях – только числового типа Пример program var k, sum :int; begin k:=l; sum:=0; while k < 10 do begin sum:=sum+k; k:=k+l end; write(sum) end. 1.1.2 Описание модельного языка SOL Алфавит содержит заглавные русские и латинские буквы, арабские цифры от 1 до 9 и ограничители: <ограничитель> :: =; |/|*|=|(|)|, Данные - строки : <строка> :: = `[<буква>]...` <имя _ строки> ::= <буква>[<буква>|<цифра>]... Говорят, что последовательность букв, образующих строку (без ковычек), является значением этой строки или что имя ссылается на эту строку. Условие: любое имя, используемое в программе, своим начальным значением имеет пустую строку. Программа SOL задает набор и порядок операций над строками; каждой операции соответствует оператор языка. Синтаксис программы: <программа> :: =({<оператор>;)...). Выполнение программы начинается с первого оператора. Если очередной оператор не указал своего преемника, то далее выполняется следующий за ним оператор. Выполнение программы прекращает оператор останова. Операторы: <оператор>::={[метка>|<правило>|<переход>]|<специальный оператор>} <метка>::=<число> <число>::=<целое число без знака> <правило>::=<левая часть>[=[<правая часть>]] <левая часть>::=<имя>[<образец>] <образец>::={<строка>|<имя>|<переменная с длиной>|<произвольная 7
переменная > }... (переменная с длиной>::=*<имя>|<число>* <произвольная переменная>::=*<имя>* <правая часть>::={<строка>|<имя>}… Выполнение неспециального оператора заключается в анализе и преобразовании какой-нибудь одной строки: берется строка, на которую ссылается имя из левой части (основной строки), в ней ищется подстрока, соответствующая образцу; если такая строка есть, она заменяется на строку, сформированную из правой части и становится новым значением имени из левой части. Кроме обработки основной строки оператор может означать переход к другому (помеченному) оператору, указанному в альтернативе "переход": <переход>::={<безусловный переход>|<переход по успеху>|<переход по неуспеху>} <безусловный переход>::=/(<метка>) <переход по успеху>::=/s(<метка>) <переход по неуспеху>::=/F(<метка>). При безусловном переходе следующим всегда выполняется оператор, метка которого указана в круглых скобках. Остальные переходы - условные. Если задан "переход по успеху", то переход по указанной метке происходит только тогда, когда в данном операторе подстрока, соответствующая образцу, найдена в основной строке; в противном случае преемником данного оператора является следующий по порядку оператор программы. "Переход по неуспеху" определяется противоположным образом. Операции над строками: образование строки, поиск по образцу, замена части строки. Образование новой строки выполняется последовательной записью произвольно данных строк; присвоить полученную строку некоторому имени можно по правилу: <имя>=[<правая часть>] Поиск по образцу означает выделение из основной строки подстроки образца в соответствии с правилом: <имя><образец> Исходы поиска: успех (если вхождение найдено (если вхождений несколько, берется левое)); неуспех (вхождение не найдено). Замена части строки определяется правилом: <имя><образец>=[<правая часть>] По этому правилу часть основной строки, соответствующая образцу, выделенному по предыдущему правилу, заменяется на строку, образованную из правой части. Специальные операторы: <специальный оператор>::=<оператор печати>|<оператор останова> <оператор печати>::=[<метка>]=РRINТ=[<строка>|<имя>] 8
<оператор останова>::=[<метка>]=SТОР=[<строка>]. Первый из этих операторов выводит на печать строку (без кавычек), явно заданную по имени, а второй печатает символ конца и строку, если она есть. Примечание |В | ...| Z} эквивалентно А|В|... |Z; [А |B | ... |Z] эквивалентно <пусто> A|B|…|Z . Пример (стр.1 = `АВСАВВАВС`; стр.2 = `ВС`; стр.3 = `АВА`; стр.1*стp.4*стp.2*стp.5*|S(2); 1 = STOP = "F" 2 = PRINT = стр.4 = PRINT = стр.5; стр.5 стр.З/F(1); = STOP = `S`;)
1.2 Порождающие грамматики Порождающая грамматика есть система G={VT,VN,S,P},VT ∩ VN =∅ где VT – словарь термин символов ; VN – словарь нетермин символов VT ∩ VN = ∅; S – начальный символ , S∈VN ; P – набор правил вида α::=β, α,β-любые цепочки Разбор по грамматике Задача разбора – обратная задача прохождению , т.е. дана цепочка, нужно найти ее вывод (рисунок 1.1): 1) нисходящий метод разбора {S::=T|T+S,T::=a|b} Дана : терминальная цепочка a+b+a Найти ее вывод: SÆ T+S Æ T+T+S Æ T+T+T Æ a+T+T Æ a+b+T Æ a+b+a М.б. левосторонним и правосторонним Недостаток : ненаглядность 2) восходящий метод разбора : a+b+a Æ a+b+T Æ a+T+T Æ T+T+T Æ T+T+S Æ T+S Æ S Недостаток : ненаглядность 3) разбор с помощью синтаксических деревьев
9
S
T
S T
S T
a
+
b +
a
Рисунок 1.1 – Синтаксическое дерево цепочки а+b+c Будем изображать правило в соответствии с рисунком 1.2: S:=α1|α2|…|αn S
α1
α2
. . .
αn
Рисунок 1.2 – Синтаксическое дерево
1.3 Классификация грамматик по Хомскому ТИП 0. Правила вывода на имеют ограничений. ТИП 1.Контекстно-зависимые (КЗ) грамматики - правила вывода имеют вид: αUβ::=αχβ, U∈VN; α,χ,β - любые цепочки ТИП 2. Контекстно-свободные (КС) грамматики с правилами: U::= χ , U∈VN, - любая цепочка КС∈КЗ {если α,β=Λ } ТИП 3. Регулярные (Р) грамматики - все правила имеют вид N::=t или N::=Mt, N,M∈VN, t∈VT P∈KC∈KЗ∈ТИП0 Определение. Язык называется языком типа К, если порождается грамматикой типа К Обозначения: малые латинские буквы - символы терминального алфавита; большие латинские буквы - символы нетерминального алфавита; греческие буквы - цепочки в алфавите ; Пример S::=aSBC|Q 10
CB::=BC QB::=bQ порождает язык C::=c L1={anbncn|n>0} Q::=Λ SÆaSBCÆaaSBCBCÆaaQBCBCÆaaQBBCCÆaabQBCCÆaabbQCCÆa abbCCÆ aabbcCÆaabbcc L1={anbncn|n=>1}- КЗ язык, но не КС L2={anbn|n=>1}- КС язык, но не Р L3={an|n=>0} – Р язык
1.4 Трансляция языков программирования
Перевод программы, написанной на языке программирования, на машинный язык осуществляется программой, которая называется транслятором. Типы трансляторов: а) компиляторы - переводят всю программу, которая затем записывается в память ЭВМ и лишь потом реализуется; б) интерпретаторы, выполняющие перевод пооператорно, так что программа выполняется частями; в) ассемблеры работают с программами на автокоде (языке ассемблере), переводя их в систему команд ЭВМ. Транслятор решает две задачи: а) анализирует транслируемую программу (в частности, определяет правильна ли она); б) генерирует выходную программу (или, как ее называют, объектную) на язык команд ЭВМ (в некоторых случаях транслятор генерирует выходную программу на промежуточном языке, например, языка ассемблера).
1.5 Этапы компиляции Процесс трансляции начинается с чтения исходного текста (рисунок 1.3) Процедура чтения текста входной программы или программы на промежуточном языке со всей последующей обработкой называется проходом транслятора. По числу проходов трансляторы делятся на одно-, двух- и многопроходные.
11
Исходная программа Компилятор Лексический анализатор Пр-ма в виде лексем Синтаксис и семантич. анализ
Т А Б Л
Пр-ма во внутреннем представлении
И
Подготовка к генерации
1)Таблицы служебных слов ТСС 2)Таблицы ограничит ТО 3)Таблицы чисел ТЧ 4)Таблицы идентифик аторов ТИ
Ц Ы
Объектная Рисунок.1.3 - Трехпроходной транслятор
2 Лексический анализ 2.1 Основные сведения Лексема - минимальная единица текста (число, идентификатор и тп.), несущая смысловую нагрузку.. Задача лексического анализа - выделить лексемы и преобразовать их к виду, удобно для последующей обработки. В процедурных языках лексемы делятся на классы: 1 - служебные слова; 2 - ограничители; 3 - числа; 4 - идентификаторы и помещаются в таблицы с соответствующими номерами. Так что лексема представляется парой чисел (n,k), где n - номер таблицы, k - номер лексемы в таблице. Анализ текста проводится путем разбора по Р - грамматике. 12
Лексический анализатор (ЛА) - программа, проводящая лексический анализ. Входные данные ЛА - текст транслируемой программы. Выходные данные ЛА - файл лексем в числовом представлении.
2.2 Лексический анализатор языка MPL Переменные: СН - символ; В - буфер для накапливания лексемы; CS - текущее состоянии накопления с возможными значениями: H начало, I - идентификатор, N - число, С - комментарий, DV - двоеточие, О ограничитель, V - выход, ER -ошибка, t - таблица с возможными значениями :TW - таблица служебных слов, TI- таблица идентификаторов, TNчисел, TL – ограничителей; Z номер лексемы В таблице t (если лексемы нет, z=0). Процедуры: GC считывание очередного символа текста в переменную СН; let СН - буква? digit CH - цифра?; NULL очистка буфера; ADD добавление очередного символа в конец буфера; LOOK(t) поиск лексемы в таблице t; PUT(t) запись лексемы В в таблицу t (если там не было этой лексемы); OUT(n,k) запись пары чисел в файл лексем TW 1) program-1 end-6 do-11 1 program 2 var-2 if-7 read-12 var int-3 then-8 write-13 bool-4 else-9 true-14 15 false begin-5 while-10 false-15 2).- 1 ;- 2 ,- 3 :- 4 := - 5
(- 6 )- 7 +- 8 -- 9 * -10
/- 11 ∪- 12 ∩- 13 ¬- 14 = -15
= - 16 > - 17 ≥ - 18 < - 19 ≤ - 20
!- 21 !F- 22 R- 23 W- 24
TL 1 2
24
. ; w
13
Пример program var k,sum :int; begin k:=0; (1,1)(1,2)(4,1)(2,3)(4,2)(2,4)(1,3)(2,2)(1,5) (4,1)(2,5)(3.1)(2,2) function scanner: boolean; var CS: (H,I,N,C,DV,O,V.ER);
1 2
TI K sum
TN begin GC;CS:=H; 1 repeat case CS of H:if CH:=:` ` then GC else If let then begin NULL;ADD;GC;CS:=:I end else If digit then begin B:=ord(CH)-ord(10); GC; CS:= N end else If CH= `:` then begin GC;CS:=:d end else If CH=`.` then begin OUT (2,1); CS:=V end else CS:=0; I:if let or digit then begin ADD;GС end else begin LOOK (TW) If Z<>0 then begin OUT(l,z); CS:=H end else begin PUT(TI); OUT(4,z);CS:=Hend end; N:if dogit then begin B:=10*B+ord(CH)-ord('O');GC end else begin PUT(TN);OUT(3,z); CS:=H end; C:if CH=:`}` then begin GC;CS:=H end else if CH=:`.` then CS:=ER else GC; DV:if CH=`=` then begin GC;OUT(2,5); CS:=H end else begin OUT(2,4); CS:=h end; O:begin NULL;ADD; LOOK(TL); if Z<>0 then begin GC;OUT(2,z);CS:=H end else CS:=ER end end{case} until (CS=V) or (CS=ER); . SCANNER :=CS=V end;
0
Лексемы можно записать с помощью регулярных грамматик (N::=t, N::=Mt) I::=a|b|…|z|Ia|Ib|…|Iz|I0\I1|…|I9 Пусть l-любая буква, d-любая цифра: I::=l|Il|Id P-грамматика N::=d|Nd Лексический анализ – программа разбора по Р-грамматике. Задача разбора- обратная задаче порождения (дана цепочка – найти вывод )
14
2.3 Разбор по Р-грамматике S::=C⊥ C::=Ab|Ba A::=a|Ca B::=b|Cb
Описывает язык L={Sn⊥|n≥1}=,{ab⊥,ba⊥,abab⊥,abba⊥,…}
Произведем разбор : цепочки abba⊥. Выясним, принадлежит ли она языку. Для этого построим синтаксическое дерево. Используем восходящий способ разбора (снизу-вверх) Получим символ S Æ цепочка выводится Æ она принадлежит языку. Пример – Рисунок 2.1 S
C
B
C
A a
b
b
a
⊥
Рисунок 2.1 –Синтаксическое дерево цепочки abba
2.4 Диаграмма состояний Наша задача : по грамматике построить анализатор. Для облегчения этой задачи сначала построим диаграмму состояний, а по ней – анализатор. Грам.Æ анализатор Грам.ÆДСÆанализатор Обозначим: Н-начало, кружочки состояния Изображения правил: 1) M::=t t Н
2) N::=Mq M
М
q
H
15
Диаграмма состояний для нашей грамматики : a
H
A
b
a
b b
B
C
a
⊥
S
Выведем цепочки abba⊥,ba,aa⊥ 1) HÆAÆCÆBÆCÆS >> цепочка выводится 2) HÆBÆC - казались не в том состоянии >>цепочка не выводится 3) HÆAÆ? – перехода нет >> цепочка не выводится
3 Синтаксический анализ 3.1 Основные сведения Задача СиА - провести разбор текста программы, сопоставив его с эталоном, данным в описании языка. Для синтаксического разбора используются КС-грамматика. Синтаксический анализатор (СиА) - программа, производящая синтаксический анализ. Входные данные СиА - файл лексем. Выходные данные - заключение о синтаксической правильности программы или предупреждение об имеющихся ошибках. Разбор по КС-грамматикам происходит методом рекурсивного спуска S::=AB⊥ -КС грамматика A::=a|cA B::=bA Выведем саbа⊥ (рисунок 3.1) S
A
B A
c
a
A b
a ⊥
Рисунок 3.1 - Синтаксическое дерево цепочки caba⊥
16
Синтаксический анализатор для этой грамматики Procedure S; Begin A; {распознать А} B; {распознать B} If CH <> `⊥` then ER End; Procedure A; Begin if CH=`a` then GC else If CH=`c` then begin GC; A end else ER Procedure B; Begin If CH=`b` then begin GC; A end else ER End; End;
3.2 Синтаксический анализатор для языкa MPL П е р е м е н н а я: LEX лексема. П р о ц е д у р ы: GL считывание очередной лексемы в переменную LEX; ERR(rule) обнаружение синтаксической ошибки. Логические ф у н к ц и и: ID LEX - идентификатор? NUM. LEX -число? EQ(S) LEX - лексема для S? Процедуры, проверяющие выполнение правил, описывающих MPL и составляющие синтаксический анализатор: 1) Р:: program D ; В. procedure Р; begin if EQ(`program`) then GL else ERR (rpl); D1; if EQ(`.`) then GL else ERR (rp2); B; if not EQ(`.`) then ERR (rp3); end; 2) D`::=var D{,D} procedure D1; begin if EQ(`var`) then GL else ERR (rdl) D; While EQ(`.`)do begin GL; D end
язык
17
End; Int 3) D::=I{,I}: bool procedure D; begin I; while EQ(`,`) do begin GL; I end; if EQ(`:`) then GL else ERR (rd2) if EQ (`int`) or EQ (`bool`) then GL else ERR (rd3) end; 4) F::=I|N|L|¬ F|(E) procedure F; begin if ID or NUM or EQ (`true`) or EQ (`false`) then GL else if EQ (` `) then begin GL; F end else if EQ (`(`) then begin GL; E; if EQ (`)`) then GL else ERR (rfl) end else ERR (rf2) end; 5) I::=Б|IБ|I Ц procedure I; begin if ID then GL else ERR (ri1) end; Написание процедур будет продолжено в последующих пунктах. Синтаксис в значительной степени определяет семантину текста: "Глокая куздра...", но очевидно, недостаточен для установления точного его смысла. Поэтому синтаксический анализ дополняется семантическим, хотя тоже - увы! - не гарантирующим полного успеха.
18
4 Семантический анализ 4.1 Основные понятия Задачи семантического анализа – проверка правильности описания переменных и проверка соответствия типов переменных в выражениях и операторах. Семантический анализ проводится с помощью КЗ - грамматик. Семантический анализатор (СеА) - программа, производящая семантический анализ. В оптимизированном варианте СиА и СеА совмещены и дополняют друг друга.
4.2 Семантический анализатор для языкa MPL О6работка описаний Задача - проверить, все ли переменные описаны., причем один раз. Эта задача решается следующим образом. Таблица идентификаторов, введенная на этапе лексического анализа, расширяется, приобретая вид: Таблица 4.1 1 2 Ее описание:
идентификатор K Sum
описан 1 0
тип Int …
адрес … …
Type TABID = record ID : string descrid : byte; typid : string [4]; addrid : word end; var TI : array [1.. n] of TABID Поле "описан" на этапе лексического анализа заполняется нулем; при правильном описании переменных на этапе семантического анализа заменяется единицей. При выполнении процедуры D вводится стековая переменная-массив, в которую заносится контрольное число 0, а затем, по мере успешного выполнения процедуры I заносятся номера считываемых из файла лексем, которые эти лексемы имеют в таблице идентификаторов. Var k,zum: int (1,2) (4,1) (2,3) (4,2) 0
1
2
19
Как только при считывании лексем встречается ":",то записанные в стек номера выводятся и по ним в таблице идентификаторов проставляется в поле "описан" 1 (к этому моменту там должен быть 0). Если очередная лексема есть "int" или "bool", то попутно в таблице идентификторов поле "тип" заполняется соответствующим типом. П е р е м е н н ы е: LEXO лексема; {лексема -двумерные числовые массивы LEX очередная лексема (п,к)} П р о ц е д у р ы: QL LEXO: = LEX; LEX:= очередная лексема; inst(l) запись в стек числа 1; outst(l) вывод из стека числа 1; instl inst (LEXO[2]); dec(t) вывод всех чисел из стека; вызов decid (1,t); decid(l,t) проверка и заполнение поля "описан" и заполнение поля "тип" в таблице идентификаторов для лексемы с номером l и типа t. procedure decid (1:..; t:...); begin if TI [1].descrid =1 then ERR (decl) else begin TI[l].descrid : = 1; TI[l].typid := t end; procedure dec(t: ...); begin outst (e); while l<>0 do begin decid (1,t); outst (1) end end; Правило Д принимает вид: Д::=inst(0)>I<{,I}:[int<dee(int)>,bool<dee(bool)>] procedure D; begin inst(0);I;instl; while EQ(`,`)do begin Gl;I;instl end; if EQ(`:`) then Gl else ERR(dsl); if EQ(`int`)then begin GL; dec `int` end else if EQ (`bool`) then begin GL; dec (bool) end else ERR(ds2) end;
20
4.3 Семантический анализ выражений Задачи - проверить описаны ли переменные, встречающиеся в выражениях, соответствуют ли типы операндов друг другу и операции. Вводится таблица 4.2 двуместных операций. Таблица 4.2 Операция + > …
Тип 1 Int Int
Тип 2 Int Int
Тип результата Int Bool
и стек, в который в соответствии с разбором выражения E заносятся типы операндов и знаки операции, а после семантической проверки в стеке оставляется только тип результата. После разбора всего выражения в стеке остается тип этого выражения. П е р е м е н н а я: LEX очередная лексема - пара (n,k). П р о ц е д у р ы работы со стеком: inst(l) запись в стек строка 1; ontst(l) вывод из стека строки 1; instl inst (LEX). П р о ц e д у р ы семантического анализа: checkid если LEX - идентификатор, то по TI проверяется, описан ли он, и , если описан, его тип помещается в стек; checkop вывод из стека типов операндов, знака операции, вызов процедуры gettype (op, tl, t2, t), проверка соответствия типов и запись в стек типа результата; dettype (ор, t1, t2, t) - с помощью TOP по операции ор дает тип t результата и типы t1,t2 операндов; cnecknot проверка типа в случае одноместной операции "¬". procedure checkid; begin k:=LEX [2]; if TI[k]*descrid = 0 then ERR(chl); inst(TI[k]*typid) end; procedure checkop; begin
21
outst (kop2); outst(op); outst(topl); gettype(op,tl,t2,t); if(topl< >tl)or (top2< >t2)then ERR(ch2); inst(t) end; procedure checknot; begin outst(t); if t< > bool then ERR(ch3); inst(t) end; Правила, расширенные семантическим анализом, принимают вид: Е:: = Е1 | El [ - ]
El
El:: = Т {[ ∪ ] T } T:: = F {[ ∩ ] F} F:: = I | N | [false,true] < inst ¬F | (E) Проверим правильность порядка операций x+5*y в соответствии с рисунком 4.1. E
int
+
int
E1
int
+
int
TT F X
(bool)>|
*
int
int
T F
F
5
y
Рисунок 4.1 – Семантическое дерево выражения x+5*y
4.4 Пpовeрка типов операторах В операторе присваивания проверяется одинаковость типов слева и справа от символа ":=",а в операторах условном и цикла проверяется булевость выражения Е. Это достигается включением в правило S процедур: 22
procedure eqtype; begin outst (t2); outst(tl) if tl<>t2 then ERR(egl) end; procedure eqbool; begin ontst(t); if t<>bool then ER(eg2) end; а также ранее рассмотренной процедуры checkid;после анализа oператора стек пуст. Правило S теперь имеет вид: S::= I:=E<eqtype>| if E <eqbool> then S else S|while E <egbool> do S
5 Перевод программы в ПОЛИЗ Польская инверсная запись (ПОЛИЗ)- постфиксная запись используется для внутреннего представления программы на MPL, готового к интерпретации.
5.1 Перевод выражений При считывании файла лексем параллельно с синтаксическим и аналитическим анализом проводится запись в массив П (ПОЛИЗ). При этом, в соответствии с синтаксическим разбором двуместной операции, первый операнд записывается в ПОЛИЗ, знак операции временно считывается в стек, а после записи в ПОЛИЗ второго операнда туда же заносится знак операции. Пример. х+у——>ху+ П е р е м е н н ы е: Р-номер первого свободного элемента массива П; l - очередная лексема; LEXO - предыдущая лексема. Процедуры ЗП(1) П(р):=1; р:=р+1 - запись лексемы в П; ЗПЛ ЗП(LEXO) - запись предыдущей лексемы в П; ЗПЛ5 запись LEXO с заменой 4-ого класса на 5-ый (см.перевод операторов присваивания); ЗПОР ЗР(ОР) - запись в П того знака операции, который считывает процедура checkop. Правила описания языка, дополненное переводом в ПОЛИЗ принимает вид: Е:: = Е1 | El [ ≤ ] El 23
El:: = Т {[ ∪ ] T } T:: = F {[ ∩ ] F} F:: = I | N | [false,true] < inst(bool)>| ¬F | (E) Напомним, что ранее в эти правила были внесены элементы синтаксического и семантического анализа.
5.2 Перевод операторов Для перевода в полиз оператора присваивания используется правило: S::I:=:E<eqtype;ЗП(`:=`)> При этом для обозначения имени переменной, стоящей в левой части оператора, вводится 5-ый класс лексем. Так что лексема, например, х = (4,8) переводится в х = ( 5,8). Пример х ;=e------> xe:= В стек записывается не значение х, а имя х; после вычисления оператора в стеке ничего не остается. Пример - -а:= а аа:= ; a=false. a
false
a
true
:=
Для перевода в полиз циклических и условных операторов используются аналогичные правила. Кроме того, в этом случае вводятся обозначения р! - переход на клетку с номером р; p!F - переход по false на клетку с номером р: if B then S1 else S2; ---> BP2!FS1P3!S2; while B do S; ——> BP1FSP0!P P2 P3 | | P0 P1 Пример if x>0 then x:=x+l else x:=5
24
X 11
0 12
> 13
23 14
:F 15
X 16
X 17
1 18
+ 19
:+ 20
26 21
! 22
X 23
5 24
Для. меток вводится нулевой класс лексем, т.е. используется обозначение р (0,р). Составной оператор переводится в полиз по схеме: begin S1; S2;...;Sn end ——> S1 S2... Sn Пример begin read(a); write(a+l) end ——> aRal+W Операторы ввода-вывода используют символы R и W, которые относятся к ограничителям: read(x) ——> xR write(x) ——> xW Чтобы в конце ПОЛИЗа была точка, правило Р переписывается в виде: P::=program D`;B <ЗП(`.`)>
5.3 Хранение польской записи в памяти Польская запись представляет собой массив из лексем (n,k),где n - номер класса лексем, k - номер лексемы внутри класса.
П
(1,1)
(2,1)
Классы : n=0 – метки, n=1 – служебные слова, n=2 - знаки операций , n=3 – числа, n=4 - идентификаторы (запись значений), n=5 -имена (запись обозначений). Польская запись очищена от всех служебных слов, кроме true и false; от ограничителей остались лишь знаки операций и знаки `:=`,`.`.
5.4 Интерпретатор ПОЛИ3а П р о ц е д у р ы: адр(1) функция выдает адрес ячейки, отведенной для лексемы l; сод(А) функция выдает содержимое ячейки с адресом А; присв(А,х) в ячейку с адресом А заносится значение х; inst(x) запись в стек; ontst(x) считывание из стека. Т е л о и н т е р п р е т а т о р а:
25
:= 25
26
р:=l; {на начало П} 100: l:=П(р); {очередная лексема] n:=l[1]; k:=l[2]; case n of 0: inst (k); {метка - в стек} 5: inst (agp(l)); {адрес - в стек} 1,3,4: inst (cog(agp(l))); {значение -- в стек} 2: {знак операции} case k of 1{ .}: goto 999 {на конец} 8{ +}: begin ontst (у); ontst (x); inst(x+y) end; 9{ -}: begin ontst (у); ontst (x); inst(x-y) end; …{аналогично для *,/ и других операций} 14{ }: begin ontsk (x); inst (notx) end; 5{:=} begin ontst (x); ontst (А); присв (А,х) end; 21{ !}:begin ontst (р); goto 100 end; 22{!F}:begin ontst (pl); ontst (B); if B=false then begin p:=pl; goto 100 end end; 23{ R}:begin outst(A); read(x); присв(А,х) end; 24{ w}:begin outst (x); writeln(x) end; end end p:=p+1; goto 100; 999;
6 Интерпретация SOL Как известно, интерпретатор анализирует исходную программу каждый раз, когда она должна быть выполнена. При этом, как правило, процесс интерпретации разделяют на два этапаНа первом этапе интерпретатор просматривает всю программу (как, примерно, компилятор) и представляет ее в форме ,удобной для последующей обработки. На втором этапе выполняется это внутреннее представлением В соответствии с этим интерпретатор для SOL должен состоять из двух блоков: блока анализа и блока интерпретации.
6.1 Внутреннее представление программы и ее объектов Построение блока анализа ориентировано на списковые языки. Каждый SOL-оператор во внутреннем представлении имеет 26
форму списка; при отсутствии необязательных элементов - метки и перехода - в соответствующих позициях помещается символ *; списком (операторов) является и программа, причем ограничители ";" удаляется: <программа>::=(<оператор>…) <оператор>::=({<метка>| *}<правило>{<переход>| <переход>::=(S<метка>)| (F<метка>)|(<метка>)*}) Таким же образом преобразуются в списки и другие конструкции языка: <левая часть>::=<<имя>[<образец>]) <правая часть>::=({<строки>|<имя>}…) <переменная с длиной>::=(*<имя><число>) <произвольная переменная>::=(*<имя>) Строки с помощью подходящих функций переводятся в списки однолитерных атомов; при этом кавычки (первые и последние элементы полученных списков) удаляются. После указанных преобразований левая и правая части оператора приобретают вид списков, состоящих на первом уровне из атомов ("имен"строк) и списков ("строк" и "переменных"). На втором этапе работы интерпретатора связь строки именем осуществляется с помощью ассоциативного списка, элементами которого являются пары (<имя>.<строка>) и полученного с помощью функции CONS. (Имена пустых строк заносить в ассоциативный список не следует, так что строки с именем Х считается пустой, если в ассоциативном списке нет пары (Х,<строка>).
6.2 Структура интерпретатора Основная программа выполняет действия: вводит программу на SOL; обращается к блоку анализа и печатает сообщение о результатах его работы при (отладке интерпретатора должна также распечатать внутреннее представления исходной SOLпрограммы) ;.при отсутствии ошибок в программе обращается к блоку интерпретации; отпечатывает сообщение об окончании интерпретации программы. В блоке анализа (осуществляющем анализ исходной программы и ее трансляцию во внутреннее представление) должны выявляться все имеющиеся в исходной программе ошибки. Пример Во внутреннем представлении программа, рассмотренная ранее, имеет вид:
27
((*(СТР1)=(АВСАВВАВС)*) (*(СТР2)=(ВС)*) (*(СТРЗ)=(АВА)*) (*(CTP1)(*CTP4)CTP2(*CTP5))(S2)) (1=STOP=(F)) (2=PRINT=CTP) (*=PPINT=CTP5) (*(CTP5 CTP3)(F1)) (*=STOP=(S))) При интерпретации данной программы отпечатано А АВВАВС =КОНЕЦ= F
должно
быть
7 Варианты заданий 7.1 Построение компилятора Разработать и реализовать на ЯП Паскаль элементы компилятора для MPL. Составить 2-3 программы на MPL, отражающие возможности языка. Выполнить выделенный этап обработки программы вручную и с помощью разработанного элемента компилятора (создать при этом файлы входных и выходных данных). 1) Лексический анализатор. Дать описание переменных СН, В, ТС, огических функций let, digit, процедур GC, NULL, ADD, PUT(t), OUT(n.k), LOOK. 2) Диаграмма состояний. В графическом режиме проиллюстрировать выполнение лексического анализа программ на MPL. 3) Разбор по Р-грамматике. В графическом режиме провести построение деревьев восходящего разбора терминальных цепочек. 4) Синтаксический анализатор. Дать описание переменных LEX, LEXO, логических функций ID, NUM, EQ(S), ER, процедур GL, P, D1, D, I, F, 5) Разбор по КС-грамматике. В графическом режиме провести построение синтаксических деревьев нисходящего разбора цепочек алфавита V V . 6) Семантический анализатор. Дать описание переменных l, TI, процедур inst(l), outst(l), GL, dec(t), decid(l,t). Обработка
28
описаний- Расширенное правило D. 7) Семантический анализатор. Дать описание переменной ТОР, процедур checkid, checkop, gettype, checknot. Обработка выражений. Расширенные правила Е, El, T, F. 8) Семантический анализатор. Проверка типов в операторах. Процедуры eqtype, eqbool. Правило S. Работа со стеками. Построение семантических деревьев. 9) Работа в графическом режиме со стеками на этапе семантического анализа. Разбор по КЗ-грамматике. Проверка правильности порядка выполнения операций путем построения семантических деревьев. 10) Бэкуса-Наура форма (БНФ). Описание модельного языка программирования MPL. Автоматическое конструирование программ. 11) Польская инверсная запись (ПОЛИЗ). Перевод в полиз программ на MPL. 12) Работа в графическом режиме со стеками при переводе в ПОЛИЗ. Графическое представление полиза программы на MPL. 13) Перевод в ПОЛИЗ Программ на MPL. Правила Е, Е1, Т, F, Р, дополненные действиями по переводу в ПОЛИЗ. 14) Интерпретатор ПОЛИЗа. Классы лексем. Процедуры адр(l), сод(А), присв(А.х). 15) Графическое представление перевода в полиз и работы интерпретатора. 16) Сборка компилятора и его отладка.
7.2 Построение интерпретатора Разработать реализовать на ЯП типа Лисп интерпретатор для конкретного подмножества SOL,определяемого типами операторов и типами элементами образца, которые разрешается использовать в дан ном подмножестве. Операторы присваивания и оба специальных оператора включаются в каждое подмножество: а) рассматриваемые типы операторов. 1) Поиск по образцу и замена: <имя><образец>=[<правая часть>] 2) Поиск по образцу и переход: [<метка>]<имя><образец>[<переход>] б) рассматриваемые элементы образцов. 1) <строка> и <имя> 2) <строка> и <произвольная переменная> 3) <строка> и <переменная с длиной> 4) <имя> и <произвольная переменная> 29
5) <имя> и <переменная с длиной>
Список использованных источников 1 Вирт Н. Алгоритмы и структуры данных.-М.: Мир,1989.360c. 2 Рейуорд-Смит В. Дж. Т.Формальные языки и грамматики.М.: Радио и связь, 1988,-128c.
30