- •Пояснительная записка к курсовой работе по дисциплине "Теория языков программирования"
- •2005 Отчет по курсовой работе тяп.
- •1 Описание входного языка
- •1.1 Задание
- •1.2 Синтаксис и семантика языка
- •1.2.1 Словарь и представление
- •1.2.2 Описания и области действия
- •1.2.3 Описания констант
- •1.2.4 Описания типов
- •1.2.5 Описания переменных
- •1.2.6 Выражения
- •1.2.6.1 Операнды
- •1.2.6.2 Операции
- •1.2.7 Операторы
- •2. Лексический анализ
- •2.1 Типы лекскем.
- •2.2 Диаграммы переходов
- •2.3 Структуры данных
- •2.4 Тестирование лексического анализатора
- •3 Синтаксический анализ и перевод во внутреннюю форму
- •3.1 Кс-грамматика входного языка
- •3.1.1 Основная грамматика.
- •3.1.2 Грамматика описывающая составной оператор.
- •3.1.3 Грамматика описывающая выражение
- •3.2 Диаграмма переходов
- •3.3 Описание промежуточного языка
- •3.4 Описание перевода
- •3.4.1 Атг для программы
- •3.4.2 Атг для оператора
- •3.4.3 Атг для выражения
- •3.4.4 Описание конструкций языка при помощи триад
- •3.5 Алгоритм работы дмп-процессора
- •3.6 Тестирование синтаксического анализатора
- •4 Генерация кода
4 Генерация кода
Задача генератора кода - построение эквивалентной машинной программы по программе на входном языке. В качестве входного для генератора кода служит некоторое промежуточное представление программы, в данном случае – триады.
При генерации ассемблерного кода происходит статическое выделение памяти. Сначала выделяется память под стек приложения (16384 слова):
PROG_STACK SEGMENT STACK 'Stack' ; стек приложения
DW16384DUP(?)
PROG_STACKENDS
Затем в сегменте данных выделяется память под переменные, в завасимости от их типа. И задается начальное значение переменной:
DATASEGMENT; сегмент данных
StringWaitForKeydb13,10,'Pressanykeytoexit...',13,10,'$' ; строка для вывода в конце работы программы
number_stringdb'+00000','$' ; строка для вывода числа
;;; VAR v1,integer
_v1 DW 1
Здесь для переменной _v1 выделяется память размера word, и присваивается знаечение по умолчанию = 1.
string_0 DB 13,10,'$'
DATA ENDS
CODE SEGMENT ; сегмент кода
ASSUME CS:CODE, DS:DATA, SS:PROG_STACK ;Фунция конвертирования числа (в регистре AX) в строку и ;вывод на экран
WriteAX PROC NEAR
push bp
push cx
push dx
push bx
mov bp,5
movbx,1
cmpax,0
jgelabel_0 ; если число отрицательное
neg bx
neg ax
label_0:
movcx,10 ; первая цифра числа
movdx,0
div cx
mov dh,0
add dx,48
mov [number_string+bp],dl
sub bp,1
loop_1: ; вторая и последующие цифры
movdx,0
div cx
cmp dl,0
je label_1
mov dh,0
add dx,48
mov [number_string+bp],dl
sub bp,1
jmp loop_1
label_1:
cmp bx,-1
jne label_2
mov [number_string+bp],'-'
sub bp,1
label_2:
add bp,1
mov DX,OFFSET number_string
add dx,bp
mov AH,9
int 21H
pop bx
pop dx
pop cx
pop bp
RET
WriteAX ENDP
MainPROCFAR; Основная функция
pushDS; Сохранение адреса началаPSPв стеке
subAX,AX; для последующего восстановления по
pushAX; командеret, завершающей процедуру.
movAX,DATA; Загрузка сегментного
movDS,AX; регистра данных.
push CX
push DX
label_1_:
;;; EQU 10,v1
label_2_:
mov AX,10
mov _v1,AX
;;; WRITE v1,
label_3_:
mov AX,_v1
call WriteAX
;;; WRITE #13#10,
label_4_:
mov DX,OFFSET string_0
mov AH,9
int 21H
mov DX,OFFSET StringWaitForKey ; Вывод на экран строки
movAH,9
int21h; Вызов функцииDOSпо прерыванию
movAH,0
int16H; ожидаем нажатие клавиши
popDX
popCX
RET
MainENDP
CODEENDS
ENDMain
При переводе каждой триаде сопостовляется набор команд на ассемблере. Эти команды добавляются в сегмент кода.
Таблица триад и соответствующего им кода на ассемблере.
Триада |
Семантика триады |
Соответствующий ассемблерный код |
EQU B, A |
A:=BеслиAэлементboolmatr, то добавляетсяAGRX,Y(координаты ячейки матрицы) |
LinesProg.Add(' mov AX,'+TetCommand.Arg1); LinesProg.Add(' mov+TetCommand.Arg2+',AX'); |
DEFL L, - |
Описание метки L |
LinesProg.Add(TetCommand.Arg1+':'); |
JMPL L, - |
Безусловный переход на триаду с меткой L |
LinesProg.Add(' jmp '+TetCommand.Arg1); |
JMP m, - |
Безусловный переход на триаду с номером m |
LinesProg.Add(' jmp '+TetCommand.Arg1); |
WRITE X, - |
Выводит значение Xна консоль |
if (TetCommand.Arg1[1]='''') then begin TMPstr:='string_'+inttostr(LabelCounter); LinesData.Add(TMPstr+' DB '+TetCommand.Arg1+',''$'''); inc(LabelCounter); LinesProg.Add(' mov DX,OFFSET '+TMPstr); LinesProg.Add(' mov AH,9'); LinesProg.Add(' int 21H'); end; if (TetCommand.Arg1='#13#10') then begin TMPstr:='string_'+inttostr(LabelCounter); LinesData.Add(TMPstr+' DB 13,10,''$'''); inc(LabelCounter); LinesProg.Add(' mov DX,OFFSET '+TMPstr); LinesProg.Add(' mov AH,9'); LinesProg.Add(' int 21H'); end; if (TetCommand.Arg1[1]='_') then begin LinesProg.Add(' mov AX,'+TetCommand.Arg1); LinesProg.Add(' call WriteAX'); end; if (TetCommand.Arg1[1] in ['0'..'9','-','+']) then begin LinesProg.Add(' mov AX,'+TetCommand.Arg1); LinesProg.Add(' call WriteAX'); end; |
VAR V, T |
Объявляет переменную VтипаT. (если типboolmatr[M,N], то добавляетсяARGM,N) |
AddVariable(TetCommand.Arg1,16); LinesData.Add(TetCommand.Arg1+' DW 1'); |
ADD A, B |
Сложение A + B |
LinesProg.Add(' mov AX,'+TetCommand.Arg1); LinesProg.Add(' mov CX,'+TetCommand.Arg2); LinesProg.Add(' add AX,CX'); LinesProg.Add(' mov _'+inttostr(Number)+'_,AX'); LinesData.Add('_'+inttostr(Number)+'_ DW 1'); |
SUB A, B |
Вычитание A – B |
LinesProg.Add(' mov AX,'+TetCommand.Arg1); LinesProg.Add(' mov CX,'+TetCommand.Arg2); LinesProg.Add(' sub AX,CX'); LinesProg.Add(' mov _'+inttostr(Number)+'_,AX'); LinesData.Add('_'+inttostr(Number)+'_ DW 1'); |
DIV A, B |
Целочисленное деление AdivB |
LinesProg.Add(' mov AX,'+TetCommand.Arg1); LinesProg.Add(' mov CX,'+TetCommand.Arg2); LinesProg.Add(' mov DX,0'); LinesProg.Add(' div CX'); LinesProg.Add(' mov _'+inttostr(Number)+'_,AX'); |
MUL A, B |
Умножение A * B |
LinesProg.Add(' mov AX,'+TetCommand.Arg1); LinesProg.Add(' mov CX,'+TetCommand.Arg2); LinesProg.Add(' mul CX'); LinesProg.Add(' mov _'+inttostr(Number)+'_,AX'); LinesData.Add('_'+inttostr(Number)+'_ DW 1'); |
AND A, B |
Логическое-И AandB |
LinesProg.Add(' mov AX,'+TetCommand.Arg1); LinesProg.Add(' mov CX,'+TetCommand.Arg2); LinesProg.Add(' and AX,CX'); LinesProg.Add(' mov _'+inttostr(Number)+'_,AX'); LinesData.Add('_'+inttostr(Number)+'_ DW 1'); |
OR A, B |
Логическое-ИЛИ AorB |
LinesProg.Add(' mov AX,'+TetCommand.Arg1); LinesProg.Add(' mov CX,'+TetCommand.Arg2); LinesProg.Add(' or AX,CX'); LinesProg.Add(' mov _'+inttostr(Number)+'_,AX'); LinesData.Add('_'+inttostr(Number)+'_ DW 1'); |
NOT A, - |
Логическое отрицание A |
LinesProg.Add(' mov AX,'+TetCommand.Arg1); LinesProg.Add(' mov CX,1'); LinesProg.Add(' sub CX,AX'); LinesProg.Add(' mov _'+inttostr(Number)+'_,CX'); LinesData.Add('_'+inttostr(Number)+'_ DW 1'); |
SHL A, B |
Побитовый сдвиг влево A, наBбит, справа появляются 0 |
LinesProg.Add(' mov AX,'+TetCommand.Arg1); LinesProg.Add(' mov CX,'+TetCommand.Arg2); LinesProg.Add(' shl AX,CX'); LinesProg.Add(' mov _'+inttostr(Number)+'_,AX'); LinesData.Add('_'+inttostr(Number)+'_ DW 1'); |
SHR A, B |
Побитовый сдвиг вправо A, наBбит, слева появляются 0 |
LinesProg.Add(' mov AX,'+TetCommand.Arg1); LinesProg.Add(' mov CX,'+TetCommand.Arg2); LinesProg.Add(' shr AX,CX'); LinesProg.Add(' mov _'+inttostr(Number)+'_,AX'); LinesData.Add('_'+inttostr(Number)+'_ DW 1'); |
CE X, Y |
Вычисляет результат сравнения (X=Y) результат (true,false). |
TMPstr:='_'+inttostr(Number)+'_'; LinesData.Add(TMPstr+' DW 0'); LinesProg.Add(' mov '+TMPstr+',1'); LinesProg.Add(' mov AX,'+TetCommand.Arg1); LinesProg.Add(' mov CX,'+TetCommand.Arg2); LinesProg.Add(' cmp AX,CX'); LinesProg.Add(' je label_'+inttostr(Number)+'__'); LinesProg.Add(' mov '+TMPstr+',0'); LinesProg.Add('label_'+inttostr(Number)+'__:'); |
CNE X, Y |
Вычисляет результат сравнения (X<>Y) результат (true,false). |
TMPstr:='_'+inttostr(Number)+'_'; LinesData.Add(TMPstr+' DW 0'); LinesProg.Add(' mov '+TMPstr+',1'); LinesProg.Add(' mov AX,'+TetCommand.Arg1); LinesProg.Add(' mov CX,'+TetCommand.Arg2); LinesProg.Add(' cmp AX,CX'); LinesProg.Add(' jne label_'+inttostr(Number)+'__'); LinesProg.Add(' mov '+TMPstr+',0'); LinesProg.Add('label_'+inttostr(Number)+'__:'); |
CL X, Y |
Вычисляет результат сравнения (X<Y) результат (true,false). |
TMPstr:='_'+inttostr(Number)+'_'; LinesData.Add(TMPstr+' DW 0'); LinesProg.Add(' mov '+TMPstr+',1'); LinesProg.Add(' mov AX,'+TetCommand.Arg1); LinesProg.Add(' mov CX,'+TetCommand.Arg2); LinesProg.Add(' cmp AX,CX'); LinesProg.Add(' jl label_'+inttostr(Number)+'__'); LinesProg.Add(' mov '+TMPstr+',0'); LinesProg.Add('label_'+inttostr(Number)+'__:'); |
CG X, Y |
Вычисляет результат сравнения (X>Y) результат (true,false). |
TMPstr:='_'+inttostr(Number)+'_'; LinesData.Add(TMPstr+' DW 0'); LinesProg.Add(' mov '+TMPstr+',1'); LinesProg.Add(' mov AX,'+TetCommand.Arg1); LinesProg.Add(' mov CX,'+TetCommand.Arg2); LinesProg.Add(' cmp AX,CX'); LinesProg.Add(' jg label_'+inttostr(Number)+'__'); LinesProg.Add(' mov '+TMPstr+',0'); LinesProg.Add('label_'+inttostr(Number)+'__:'); |
CLE X, Y |
Вычисляет результат сравнения (X<=Y) результат (true,false). |
TMPstr:='_'+inttostr(Number)+'_'; LinesData.Add(TMPstr+' DW 0'); LinesProg.Add(' mov '+TMPstr+',1'); LinesProg.Add(' mov AX,'+TetCommand.Arg1); LinesProg.Add(' mov CX,'+TetCommand.Arg2); LinesProg.Add(' cmp AX,CX'); LinesProg.Add(' jle label_'+inttostr(Number)+'__'); LinesProg.Add(' mov '+TMPstr+',0'); LinesProg.Add('label_'+inttostr(Number)+'__:'); |
CGE X, Y |
Вычисляет результат сравнения (X>=Y) результат (true,false). |
TMPstr:='_'+inttostr(Number)+'_'; LinesData.Add(TMPstr+' DW 0'); LinesProg.Add(' mov '+TMPstr+',1'); LinesProg.Add(' mov AX,'+TetCommand.Arg1); LinesProg.Add(' mov CX,'+TetCommand.Arg2); LinesProg.Add(' cmp AX,CX'); LinesProg.Add(' jge label_'+inttostr(Number)+'__'); LinesProg.Add(' mov '+TMPstr+',0'); LinesProg.Add('label_'+inttostr(Number)+'__:'); |
JFL L, E |
Переход на метку LеслиE=false |
LinesProg.Add(' mov AX,'+TetCommand.Arg2); LinesProg.Add(' cmp AX,0'); LinesProg.Add(' je '+TetCommand.Arg1); |
JF M, E |
Переход на триаду с номером mеслиE=false |
LinesProg.Add(' mov AX,'+TetCommand.Arg2); LinesProg.Add(' cmp AX,0'); |
Пример
1. Входная программа:
program test;
const N=10;
var x:integer;
begin
x:=N;
writeln(x);
end.
2. Набор триад:
VAR v1,integer
EQU 10,v1
WRITE v1,
WRITE #13#10,
3. Сгенерированный код:
PROG_STACKSEGMENTSTACK'Stack' ; стек приложения
DW16384DUP(?)
PROG_STACKENDS
DATASEGMENT; сегмент данных
StringWaitForKey db 13,10,'Press any key to exit...',13,10,'$' ; строка для вывода в конце работы программы
number_string db '+00000','$' ; строка для вывода числа
;;; VAR v1,integer
_v1 DW 1
string_0 DB 13,10,'$'
DATA ENDS
CODE SEGMENT ; сегмент кода
ASSUME CS:CODE, DS:DATA, SS:PROG_STACK
;Фунция конвертирования числа (в регистре AX) в строку и вывод на экран
WriteAX PROC NEAR
push bp
push cx
push dx
push bx
mov bp,5
mov bx,1
cmp ax,0
jge label_0 ; если число отрицательное
neg bx
neg ax
label_0:
mov cx,10 ; первая цифра числа
mov dx,0
div cx
mov dh,0
add dx,48
mov [number_string+bp],dl
sub bp,1
loop_1: ; вторая и последующие цифры
mov dx,0
div cx
cmp dl,0
je label_1
mov dh,0
add dx,48
mov [number_string+bp],dl
sub bp,1
jmp loop_1
label_1:
cmp bx,-1
jne label_2
mov [number_string+bp],'-'
sub bp,1
label_2:
add bp,1
mov DX,OFFSET number_string
add dx,bp
mov AH,9
int 21H
pop bx
pop dx
pop cx
pop bp
RET
WriteAX ENDP
Main PROC FAR ; Основная функция
push DS ; Сохранение адреса начала PSP в стеке
sub AX,AX ; для последующего восстановления по
push AX ; команде ret, завершающей процедуру.
mov AX,DATA ; Загрузка сегментного
mov DS,AX ; регистра данных.
push CX
push DX
label_1_:
;;; EQU 10,v1
label_2_:
mov AX,10
mov _v1,AX
;;; WRITE v1,
label_3_:
mov AX,_v1
call WriteAX
;;; WRITE #13#10,
label_4_:
mov DX,OFFSET string_0
mov AH,9
int 21H
mov DX,OFFSET StringWaitForKey ; Вывод на экран строки
mov AH,9
int 21h ; Вызов функции DOS по прерыванию
mov AH,0
int 16H ; ожидаем нажатие клавиши
pop DX
pop CX
RET
Main ENDP
CODE ENDS
END Main
4. Результат выполнения сгнерированной программы: