Скачиваний:
17
Добавлен:
01.05.2014
Размер:
571.39 Кб
Скачать

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. Результат выполнения сгнерированной программы:

37