Разработка калькулятора на основе рекурсивного спуска



1)Цель работы:  Добавить в программу, модифицированную в предыдущей лабораторной работе, возможность вычисления простого арифметического выражения: реализовать сложение, вычитание, умножение и целочисленное деление.

Изменим процедуры обработки арифметического выражения следующим образом:

procedure ff(var resff:integer);

     begin

     scan(T,n);

     if (T='i') then

        begin

        if not ((ub-length(sl))=1) then bofl:=false;

        scan1(T,n);

        if ((T='r')and(n=8)) then oppr(mid);

        end

        else if (T='c') then

             begin

             resff:=num;

             end

             else if (T='k') then

                  begin

                  if (n=4) then {opw};

                  end

             else if (T='l') then

                  begin

                  end

             else if ((T='r')and(n=5)) then

                  begin

                  ee(resff);

                  scan(T,n);

                  if ((T='r')and(n=6)) then begin end

                     else err(0);

                  end

                  else err(2);

     end;

procedure tt(var restt:integer);

var rt:integer;

     begin

     ff(rt);

     scan1(T,n);

     while (not((T='r') and ((n=1) or (n=2) or (n=6) or (n=7)))) do

           begin

           scan(T,n);

           if ((T='r') and (n=3)) then

              begin

              ff(mid);

              restt:=rt*mid;

              end

              else

              if ((T='r') and (n=4)) then

                 begin

                 ff(mid);

                 restt:=rt div mid;

                 end

                 else

                 err(1);

           scan1(T,n);

           end;     end;

procedure ee(var resee:integer);

var re:integer;

      begin

     tt(re);

     While (not(((T='r') and (n=7))or((T='r') and (n=6)))) do

           begin

           scan(T,n);

           if ((T='r') and (n=1)) then

              begin

              tt(mid);

              resee:=re+mid;

              end

              else

              if ((T='r') and (n=2)) then

                 begin

                 tt(mid);

                 resee:=re-mid;

                 end

                 else

                 err(1);

           scan1(T,n);

           end;     end;

 

Содержимое файла: 19+(32/8)-(45*3)#

 

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

Строка правильная

158

Результат оказался верным, следовательно арифметический анализатор работает верно.


Лабораторная работа №11

Генерация кода на ассемблере для арифметического выражения

1)Цель работы:  Модифицировать «программу-калькулятор», созданную в прошлой лабораторной работе так, чтобы вместо в качестве семантических действий было не прямое вычисление результата, а генерация кода на ассемблере, с помощью которого после компиляции и компоновки новой программы, можно будет получить результат.

 

Изменим процедуры обработки арифметического выражения следующим образом:

procedure tt;

begin

ff;

scan1(t,n);

while not(((t='r')and((n=7)or(n=10)or(n=11)or(n=17)or(n=9)or(n=14)or(n=15)or(n=5)or(n=3)))or((t='R')and((n=4)or(n=5)or(n=6)))) do

begin

scan(t,n);

if (t='r') then

case n of

12: begin

    ff;

     writeln(final,'pop bx');

     writeln(final,'pop ax');

     writeln(final,'mul bx');

     writeln(final,'push ax');

     end;

13: begin

     ff;

     writeln(final,'pop bx');

     writeln(final,'pop ax');

     writeln(final,'div bx');

     writeln(final,'push ax');

     end;

else begin

      err('ожидалось арифметическое действие');

      end;

end

else err(' ожидалось арифметическое действие ');

scan1(t,n);

end;

end;

 

procedure ee;

begin

tt;

scan1(t,n);

while not(((t='r')and((n=7)or(n=17)or(n=9)or(n=14)or(n=15)or(n=5)or(n=3)))or((t='R')and((n=4)or(n=5)or(n=6)))) do

begin

scan(t,n);

if (t='r') then

case n of

10: begin

     tt;

     writeln(final,'pop bx');

     writeln(final,'pop ax');

     writeln(final,'add ax,bx');

     writeln(final,'push ax');

     end;

11: begin

     tt;

     writeln(final,'pop bx');

     writeln(final,'pop ax');

     writeln(final,'sub ax,bx');

     writeln(final,'push ax');

     end;

else begin

      err(ожидалось арифметическое действие ');

      end;

end

else err(ожидалось арифметическое действие ');

scan1(t,n);

end;

end;

 

procedure ff;

var temps:string;

k:integer;

begin

scan(t,n);

case t of

'c': begin

  writeln(final,'mov ax,',sl);

  writeln(final,'push ax');

  end;

'i': begin

       writeln(final,'mov ax,',sl);

       writeln(final,'push ax');

  end;

'r': begin

  if (n=6) then

    begin

    ee;

    scan(t,n);

    if not ((t='r')and(n=7)) then err('ожидалась закрывающая скобка');

    end

  else err('ожидалась открывающая скобка')

  end

else err('неожиданный символ');

end;

end;

 

Также изменим главный метод программы:

 

begin

prepare;

writeln(final,'.model tiny');

writeln(final,'.code');

writeln(final,'.386');

writeln(final,'org 100h');

writeln(final,'start:');

ee;

writeln(final,'pop ax');

writeln(final,'mov bx,10');

writeln(final,'mov di,0');

writeln(final,'mov si,ax');

writeln(final,'cmp ax,0');

writeln(final,'jns @a');

writeln(final,'neg si');

writeln(final,'mov ah,2');

writeln(final,'mov dl, "-"');

writeln(final,'int 21h');

writeln(final,'mov ax,si');

writeln(final,’@a:');

writeln(final,'mov dx,0');

writeln(final,'div bx');

writeln(final,'add dl, 30h');

writeln(final,'mov vivod [di],dl');

writeln(final,'inc di');

writeln(final,'cmp al,0');

writeln(final,'jnz @a');

writeln(final,'mov cx,di');

writeln(final,'dec di');

writeln(final,'mov ah,2');

writeln(final,'@b:');

writeln(final,'mov dl,vivod[di]');

writeln(final,'dec di');

writeln(final,'int 21h');

writeln(final,'loop @b');

writeln(final,'mov dl, " "');

writeln(final,'int 21h');

writeln(final,'ret');

writeln(final,'end start');

if (buf[ub]='(') then count:=count+1 else if (buf[ub]=')') then count:=count-1;

if (count<>0) then err(0);

writeln(' Строка правильная');

close(f);

assign(f,'D:\tab_i.txt');

append(f);

for i:=1 to z-1 do

writeln(f,tab_i[i]);

close(f);

end;

 

Содержание исходного файла: 19+(32/8)-(45*3)#

 

В результате сканирования исходного текста получим текстовый файл:

 

.model tiny

.code

.386

org 100h

start:

mov ax,19

push ax

mov ax,32

push ax

mov ax,8

push ax

pop bx

pop ax

div bx

push ax

pop bx

pop ax

add ax,bx

push ax


mov ax,45

push ax

mov ax,3

push ax

pop bx

pop ax

mul bx

push ax

pop bx

pop ax

sub ax,bx

push ax

pop ax

mov bx,10

mov di,0

mov si,ax

cmp ax,0

jns @met7

neg si

mov ah,2

mov dl, "-"

int 21h

mov ax,si

@met7:

mov dx,0

div bx

add dl, 30h

mov vivod [di],dl

inc di

cmp al,0

jnz @met7

mov cx,di

dec di

mov ah,2

@met8:

mov dl,vivod[di]

dec di

int 21h

loop @met8

mov dl, " "

int 21h

ret

end start

 

Скомпонуем и скомпилируем получившуюся программу на ассемблере. В результате запуска созданного нами .com-приложения получим сообщение:

 

158

 

Данный результат является верным, следовательно обе программы составлены и работают правильно.


Дата добавления: 2018-04-05; просмотров: 355; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!