Помощь - Поиск - Пользователи - Календарь
Полная версия: Интерпретатор арифметико-логических выражений
Форум «Всё о Паскале» > Pascal, Object Pascal > Задачи
Olya
Ещё у меня вот с чем возникла проблемка:
В общем вот такая вот задача:
>>>На основе стекового арифметико-логического устройства (стекового процессора), используя метод Дейкстры, разработать интерпретатор арифметико-логических выражений, содержащих числа в произвольном формате, квадратные скобки, знаки операций
+ (1) – (1) | * / | ^ | + (2) – (2) | < > = # | ~ | & | !
<------------- ------> -----> ---------> ----------> <----- ------> ----->


и указатели функций exp(<формула>), ln(<формула>).

Сама программа фактически написана, но всё равно какие-то косяки вылезают:
1. Расставление приоритетов не является правильным.
2. В приоритетах не учавствует унарый + и -.
3. При полной проверке (которая на мой взгляд не нужна) происходит недозапись в файл результат.
4. Не считается ln и exp.
5. Не понятное обращение с квадратными скобками.
6. В ОПЗ включаются не все знаки операций.
{Этот модуль нужен для формирования начальной строки с которой нам предстоит работать}
Unit AStream;
Interface
{входной поток значащих символов на основе текстового файла}
Type
PFStreamTxt = ^CFStreamTxt;
CFStreamTxt = Object
public
constructor Create(DataName:String); {создать и открыть поток}
destructor Destroy; virtual; {разрушить поток}
{основные операции}
function GetChar:Char; {текущий значащий символ}
function IsAfterSpace:Boolean; {после символа форматирования?}
procedure Skip;{перейти к следующему значащему символу}
function IsEnd:Boolean; {конец потока?}
{дополнительные и служебные функции}
private
{фиксация/обработка ошибок}
procedure Failure(n:Byte); {завершить аварийно}
{вспомогательные функции}
procedure SkipSpaces; {перейти к следующему значащему символу
или встать в конец потока}
private
{основные поля для одного из вариантов реализации}
DN:String; {имя набора данных}
F:Text;
CharBufer:Char;
AfterSpaceBufer:Boolean;
EndOfStream:Boolean;
{дополнительные и служебные поля}
end;
{другие входные потоки значащих символов}

Implementation
Uses Crt;
{!символы форматирования в кодировке ASCII!}
Const SetOfSpaces:Set of Char=[#9,' ',#255];

{основные операции потока из текстового файла}
constructor CFStreamTxt.Create(DataName:String);
begin
DN:=DataName; EndOfStream:=true;
{$I-} {отключить обработку ошибок ввода-вывода}
Assign(F,DN); Reset(F);
{$I+} {включить обработку ошибок ввода-вывода}
if IOResult <> 0 then
Failure(1)
else
begin
EndOfStream:=false;
SkipSpaces; {пропустить символы форматирования из начала файла}
end;
end;

destructor CFStreamTxt.Destroy; {Убираем мусор после работы програмы}
begin
Close(F); EndOfStream:=true; DN:='';
end;

function CFStreamTxt.GetChar:char;
begin
if EndOfStream then
Failure(2)
else
GetChar:=CharBufer;
end;

function CFStreamTxt.IsAfterSpace:boolean; {свободное место, и еще сразу отрабатываются ошибки}
begin
if EndOfStream then
Failure(3)
else
IsAfterSpace:=AfterSpaceBufer;
end;

unit compil;
interface

uses
crt,astream,mystack;

const
ops: set of char = ['-','+','*','/','^','<','>','=','#','~','&','!','[',']']; {массив знаков которые встречаются в формуле}
digits: set of char = ['0'..'9'];

type
ERRORS=(ERROROFTYPE,
NOTANUMBER_OR_NOTCORRECTIDENTIFIER,
NOT_INITIONALIZED_VARIABLE,
DIVISION_BY_ZERO,
UNKNOWNERROR);

enterpretator=object
procedure error(e:ERRORS); {процедура отвечает за вывод сообщений об ошибках}
function isCorrectNumberOrVariable(t:string):boolean; {проверяет корректность входных параметров}
function getPriority(op:string):integer; {функция отвечает за расстановку приоритетов, т.е. в какой
последовательности они должны выполняться}
function isLeftAssociativity(op:string):boolean; {эта процедура отвечает за проверку ассоциативности, тобищь левая
или правая
причем она будет левой только когда все знаки в уровнении будут расставлены
как положено, в соответствии с заданием}
function typeOp(op:string):integer; {эта функия делает определение типа того как будут выполняться, ведь работа
ведется со стеком}
function getToken(ast: PFStreamTxt):string; {эта шняга проверяет много всего, ну такое как что стоит следующим,
число или ничего,
а еще она перемещает цказатель на нужный элемент}
function IsIt(t:string):integer; {Эта функция работает со стеком знаков}
{ Обработка типа выполняемой опреации и проверка типов операндов}
procedure HandleType(op:string; var st_type,st_value:stack); {}
function compileFormula(ast:PFstreamtxt):string; {функция оформляет файл и содержит в себе все необходимые данные}
function doOperation2(x,y:real;op:string):real; {выполнение группы команд}
function doOperationBool2(x,y:boolean;op:string):boolean; {выполнение логических опраций, таких как or, and}
function doOperation2Bool(x,y:real;op:string):boolean; {выполнение логических операций, типа <,>, = и т.д.}
function doOperation1(x:real;op:string):real; {выполнение унарных операций}
function doOperation1bool(x:boolean;op:string):boolean; {унарная логическая функия}
end;

var g:text; {переменная нужна для создания файла}

implementation

procedure enterpretator.error(e:ERRORS);
begin
case e of
ERROROFTYPE: writeln('Ошибка типа');
NOTANUMBER_OR_NOTCORRECTIDENTIFIER: writeln('Не правильный идентификатор или формат числа');
NOT_INITIONALIZED_VARIABLE: writeln('Переменная не инициализирована');
UNKNOWNERROR: writeln('Неизвестная ошибка');
DIVISION_BY_ZERO: writeln('Деление на ноль');
end;
halt(integer(e));
end;


function enterpretator.isCorrectNumberOrVariable(t:string):boolean;
var r:real; code:integer;
begin
isCorrectNumberOrVariable:=true; {Эта переменная с длинным названием нужна для проверки того что
мы встретили число или знак}
if t[1] in Digits then {Проверка на то, является ли встреченный элемент числом}
begin
val(t, r, Code); {Функция преобразования элемента в нужный тип для работы (из строки в число)}
if code<>0 then isCorrectNumberOrVariable:=false; {Если code не равно 0, значит функция перевода строки
в число не сработала и значит это знак}
end
end;

{
+ (1) - (1)| * / | ^ |+ (2) - (2) | < > = # | ~ | & | !
<----------- ------> --> ---------> ----------> <-- --> ----->

~ ^ * / & ! < > = # een az zi 'salihcumzi eju asv ano ot a ,ugorp ute aladz ib 'toh
}

function enterpretator.getPriority(op:string):integer; {функция расстановки приоритетов, здесь черт ногу сломает, что и куда
и как, но оно вроде правильное!}
begin
getPriority :=-1;
if (op='[') then getPriority := 0 else
if (op=']') then getPriority := 1 else
if (op='!') then getPriority := 2 else
if (op='&') then getPriority := 3 else
if (op='~') then getPriority := 4 else
if (op='#') or (op='=') or (op='>') or (op='<') then getPriority:=5 else
if (op='-') or (op='+') then getPriority:=6 else
if (op='^') then getPriority:=7 else
if (op='/') or (op='*') then getPriority:=8;
if (op='exp') or (op='ln') then getPriority := 9;
end;

function enterpretator.isLeftAssociativity(op:string):boolean;
begin
case op[1] of
'-','+','*','/','^','<','>','=','#','~','&','!': {Эта функция определит где начало счета}
isLeftAssociativity:=false;
else
isLeftAssociativity:=true;
end;
end;

function enterpretator.typeOp(op:string):integer;
begin
typeOp:=-1;
{ R+R=R }
if (op='+') or (op='-') or (op='*') or (op='/') or (op='^') then typeOp:=0 else {переменная нужная для определения перехода,
для правильного вычисления операций}
{ RB>RB=B }
if (op='>') or (op='<') or (op='=') or (op='#') or (op='&') or (op='!') then typeOp:=1 else
{ ~B=B }
if (op='~') then typeOp:=2 else
{ exp(x) }
if (op='+') or (op='-') or (op='exp') or (op='ln') then typeOp:=3;
end;


function enterpretator.getToken(ast: PFStreamTxt):string; {ast это переменная стекового типа, ведь мы работаем со стеком,
она нам нужна для того чтобы мы могли работать со стеком}
var s:string; k:integer; ch:char; {}
begin
s:='';
if (not ast^.IsEnd) then
begin
ch:=ast^.getchar; {ch - это переменная отвечающая за сохранение промежуточного значения числового типа}
if (ch in ops) then {ops - это массив символов описанный выше}
begin
s:=s+ch; {s - это строка в которую мы формируем для работы с несколькими элементами сразу}
if (not ast^.IsEnd) then ast^.skip;
end
else
begin
repeat
if (not ast^.IsEnd) then begin
s:=s+ch;
ast^.skip;
end;
if (not ast^.IsEnd) then ch:=ast^.getchar;
until (ch=' ') or (ch in ops) or (ast^.IsEnd);
end;
end;
getToken:=s;
end;

{
+ (1) - (1)| * / | ^ |+ (2) - (2) | < > = # | ~ | & | !
<----------- ------> --> ---------> ----------> <-- --> ----->
}
function enterpretator.IsIt(t:string): integer; {функция определяет какой из знаком может быть нажат для вычисления}
begin
IsIt:=1;
if (t='[') or (t=']') then isit:=2;
if (t='-') or (t='+') or (t='*') or (t='/') or (t='^') or
(t='&') or (t='!') or (t='>') or (t='<') or (t='=') or
(t='#') or (t='~') or (t='exp') or (t='ln') then IsIt:=0;
end;


function enterpretator.doOperation2(x,y:real;op:string):real; {Следующие несколько функций показываю как и какую
операцию надо выполнять}
begin
case op[1] of
'+': doOperation2:=x+y;
'-': doOperation2:=x-y;
'*': doOperation2:=x*y;
'/': if y<>0 then doOperation2:=x/y else error(DIVISION_BY_ZERO);
{ '!': doOperation2:=x or y;
'&': doOperation2:=x and y; }
'^': doOperation2:=exp(y*ln(x));
end;
end;

function enterpretator.doOperation2Bool(x,y:real;op:string):boolean;
begin
case op[1] of
'>': doOperation2bool:=x>y;
'<': doOperation2bool:=x<y;
'=': doOperation2bool:=x=y;
'#': doOperation2bool:=x<>y;
end;
end;


function enterpretator.doOperationBool2(x,y:boolean;op:string):boolean;
begin
case op[1] of
'!': doOperationBool2:=x or y;
'&': doOperationBool2:=x and y;
end;
end;

function enterpretator.doOperation1(x:real;op:string):real;
begin
case op[1] of
'-': doOperation1:=-x;
'+': doOperation1:=x;
{ '~': doOperation2:=x;}
end;
if op='exp' then doOperation1:=exp(x);
if op='ln' then doOperation1:=ln(x);
end;

function enterpretator.doOperation1bool(x:boolean;op:string):boolean;
begin
case op[1] of
'~': doOperation1bool:=not x;
end;
end;


{ Обработка типа выполняемой опреации и проверка типов операндов}
procedure enterpretator.HandleType(op :string; var st_type,st_value:stack);
var t_type,p_type,t_value,p_value,s: string; x,y,z:real; code:integer; {code - это к какому типу будут приводиться значения}
xb,yb,zb:boolean; {нужны для вывода результата такого как например true или false, которые получаются в результате
выполнения лочических операций}
{x,y,z:real- нужны на самом деле для того же, они используются на выводе и при передаче параметра
в другие функции}

begin
case typeOp(op) of
0:
begin
t_type:=st_type.pop; {stek tipa}
p_type:=st_type.pop; {simvol na vdode}
t_value:=st_value.pop; {rezultat operaciy}
p_value:=st_value.pop; {cislo v vihodnoy potok}
if (t_type[1]<>'R') or (p_type[1]<>'R') then error(ERROROFTYPE);
st_type.push('R');
val(t_value,y,code); if code<>0 then error(NOT_INITIONALIZED_VARIABLE);
val(p_value,x,code); if code<>0 then error(NOT_INITIONALIZED_VARIABLE);
z:=doOperation2(x,y,op);
writeln(g,'Вычисляем: ', x,op,y);
writeln(g,'Результат ',z,' кладем в стек');
str(z,s);
st_value.push(s);
end;
1: {!!!!!!!!!!!!!!!!!!!!!!!}
begin
t_type:=st_type.pop;
p_type:=st_type.pop;
t_value:=st_value.pop;
p_value:=st_value.pop;
if ((t_type<>'R') or (p_type<>'R')) and
((t_type<>'B') or (p_type<>'B')) then error(ERROROFTYPE);
st_type.push('B');
if ((t_type='R') and (p_type='R')) then
begin
val(t_value,y,code); if code<>0 then error(NOT_INITIONALIZED_VARIABLE);
val(p_value,x,code); if code<>0 then error(NOT_INITIONALIZED_VARIABLE);
zb:=doOperation2Bool(x,y,op);
if zb then s:='TRUE' else s:='FALSE';
st_value.push(s);
writeln(g,'Вычисляем: ', x,op,y);
writeln(g,'Результат ',zb,' кладем встек');
end
else
begin
yb:=(t_value='TRUE');
xb:=(p_value='TRUE');
if ((t_value<>'TRUE') and (t_value<>'FALSE')) then error(NOT_INITIONALIZED_VARIABLE);
if ((p_value<>'TRUE') and (p_value<>'FALSE')) then error(NOT_INITIONALIZED_VARIABLE);
zb:=doOperationBool2(xb,yb,op);
if zb then s:='TRUE' else s:='FALSE';
st_value.push(s);
writeln(g,'Вычисляем: ', xb,op,yb);
writeln(g,'Результат ',zb,' кладем встек');
end
end;
2:
begin
t_type:=st_type.pop;
t_value:=st_value.pop;
if (t_type<>'B') then error(ERROROFTYPE);
st_type.push('B');
if ((t_value<>'TRUE') and (t_value<>'FALSE')) then error(NOT_INITIONALIZED_VARIABLE);
xb:=(t_value='TRUE');
zb:=doOperation1Bool(xb,op);
if zb then s:='TRUE' else s:='FALSE';
st_value.push(s);
writeln(g,'Вычисляем: ', op,xb);
writeln(g,'Результат ',zb,' кладем в стек');
end;
3:
begin
t_type:=st_type.pop;
t_value:=st_value.pop;
if (t_type<>'R') then error(ERROROFTYPE);
st_type.push('R');
val(t_value,x,code); if code<>0 then error(NOT_INITIONALIZED_VARIABLE);
z:=doOperation1(x,op);
str(z,s);
st_value.push(s);
writeln(g,'Вычисляем: ', op,'(',x,')');
writeln(g,'Результат ',z,' кладем в стек');
end
end;
end;

function enterpretator.compileFormula(ast:PFstreamtxt):string;
var
inpstr: string;
outstr: string;
st: Stack; {-- Стек операций --}
st_type: Stack; {-- Стек типов --}
st_value:Stack; {-- Стек значений --}
t,p,s: string;
i,code:integer;
r:real;

begin
writeln(g,'Протокол дейсвтий:');
writeln('Протокол дейсвтий смотри в файле результатов');
outstr:='';
st.init;
st_type.init;
st_value.init;
{ ch:=ast^.getchar;}
t:=getToken(ast);
while length(t)>0 do
begin
case IsIt(t) of
0: { Операция }
begin
p:=st.viewtop;
if p='(' then st.push(t)
else
begin
p:=st.viewtop;
if (getPriority(p)<getPriority(t))or
((getPriority(p)= getPriority(t))and(not isLeftAssociativity(t)))
then
begin
st.push(t);
end
else
begin
while ((getPriority(p)>getPriority(t))or
((getPriority(p)=getPriority(t))and
(isLeftAssociativity(t)))) do
begin
p:=st.pop;
HandleType(p,st_type,st_value);
{--------------}
outstr:=outstr+p+' ';
p:=st.viewtop;
end;
st.push(t);
end;
end;

end;
1: { Число или Переменная }
begin
if isCorrectNumberOrVariable(t) then
begin
outstr:=outstr+t+' ';
st_type.push('R');
st_value.push(t);
end
else
Error(NOTANUMBER_OR_NOTCORRECTIDENTIFIER);
end;
2: { Скобка }
begin
if t='(' then st.push(t)
else
begin
p:=st.pop;
while (p<>'(') do
begin
HandleType(p,st_type,st_value);
outstr:=outstr+p+' ';
p:=st.pop;
end
end;
end;
end;
Writeln(g,'Получаем очередную лексему для разбора. Это -- ',t);
t:=getToken(ast);
writeln(g,'------- Состояния стеков --------');
writeln(g,'Cтек операций:');
st.printfile(g);
writeln(g);
writeln(g,'Cтек типов:');
st_type.printfile(g);
writeln(g);
writeln(g,'Cтек значений:');
st_value.printfile(g);
writeln(g);
end;
p:=st_type.pop;
s:=st_value.pop;
{ if (not st_type.isEmpty) or (not st.isEmpty) then Error(UNKNOWNERROR); zakomentirovat'}
writeln('Тип результата: ', p);
writeln(g,'Тип результата: ', p);
if p='R' then
begin
val(s,r,code);
writeln('Результат: ', r:14:9);
writeln(g,'Результат: ', r:14:9);
end
else
begin
writeln('Результат: ', s);
writeln(g,'Результат: ', s);
end;
compileFormula:=outstr;
end;

end.




{$A+,B-,D+,E+,F-,G-,I+,L+,N-,O-,P+,Q-,R-,S+,T-,V+,X+}
{$M 16384,0,655360}

unit myStack;
interface
type
pelement=^element;
element=record
data: string;
next: pelement;
end;

Stack=object
top: pelement;
constructor init;
function isEmpty: boolean;
function pop: string;
procedure print;
procedure printfile(var g:text);
procedure push(a: string);
function viewtop: string;
end;

implementation
constructor Stack.init; {- фєьр¦ Tv фюурфрышё№ ¤Єю шэшЎшрышчрЎш ёЄхър}
begin
top:=nil;
end;

function Stack.isEmpty:boolean; {ёЄхъ ўшёЄ ъръ ьырфхэхЎ}
begin
isEmpty:=(top=nil);
end;

function Stack.pop: string; {ЇєэъЎш тvЄрыъштрэш шч ёЄхър}
var temp:pelement; s:string;
begin
if not Stack.IsEmpty then
begin
s :=top^.data;
temp :=top;
top :=top^.next;
if (temp <> nil) then
dispose(temp);
pop :=s;
end;
end;

function Stack.viewtop: string; {ЇєэъЎш юяЁхфхыхэш ёыхфє¦•хую ¤ыхьхэЄр}
begin
viewtop:=top^.data;
end;

procedure Stack.print;
var temp:pelement;
begin
temp:=top;
while (top<>nil) do
begin
write(top^.data,' ');
top:=top^.next;
end;
top:=temp;
end;

procedure Stack.printfile(var g:text);
var temp:pelement;
begin
temp:=top;
while (top<>nil) do
begin
write(g,top^.data,' ');
top:=top^.next;
end;
top:=temp;
end;

procedure Stack.push(a:string); {яЁюЎхфєЁр фюсртыхэш т ёЄхъ чэрўхэшщ}
var temp:pelement;
begin
new(temp);
temp^.data:=a;
temp^.next:=top;
top:=temp;
end;
end.

{Стандартный интерфейс для пользователя}
uses
crt,astream,mystack,compil;

var
ast: PFStreamTxt;
fname,gname:string;
ch:char;
c:enterpretator;
outstr:string;

begin
clrscr;
writeln('Введите имя входного файла: ');
readln(fname);
writeln('Введите имя файла результата: ');
readln(gname);
assign(g,gname);
rewrite(g);
new(ast,create(fname));
writeln('Формула на входе: ');
writeln(g,'Формула на входе: ');
while(not ast^.isEnd)do
begin
write(ast^.getChar);
write(g,ast^.getChar);
ast^.skip;
end;
writeln; writeln(g);
dispose(ast,destroy);
new(ast,create(fname));
outstr:=c.compileFormula(ast);
writeln('ОПЗ с учетом ассоциативности и приоритетов:');
writeln(g,'ОПЗ с учетом ассоциативности и приоритетов:');
writeln(outstr);
writeln(g,outstr);
dispose(ast,destroy);
close(g);
readkey;
end.



volvo
Olya, во-первых, первый модуль (AStream) приведен не полностью, из-за чего программа просто не компилируется. А во-вторых, почему в "Другие языки"? Это ж Паскаль...
Olya
Вот модуль до конца
{Этот модуль нужен для формирования начальной строки с которой нам предстоит работать}
Unit AStream;
Interface
{входной поток значащих символов на основе текстового файла}
Type
PFStreamTxt = ^CFStreamTxt;
CFStreamTxt = Object
public
constructor Create(DataName:String); {создать и открыть поток}
destructor Destroy; virtual; {разрушить поток}
{основные операции}
function GetChar:Char; {текущий значащий символ}
function IsAfterSpace:Boolean; {после символа форматирования?}
procedure Skip;{перейти к следующему значащему символу}
function IsEnd:Boolean; {конец потока?}
{дополнительные и служебные функции}
private
{фиксация/обработка ошибок}
procedure Failure(n:Byte); {завершить аварийно}
{вспомогательные функции}
procedure SkipSpaces; {перейти к следующему значащему символу
или встать в конец потока}
private
{основные поля для одного из вариантов реализации}
DN:String; {имя набора данных}
F:Text;
CharBufer:Char;
AfterSpaceBufer:Boolean;
EndOfStream:Boolean;
{дополнительные и служебные поля}
end;
{другие входные потоки значащих символов}

Implementation
Uses Crt;
{!символы форматирования в кодировке ASCII!}
Const SetOfSpaces:Set of Char=[#9,' ',#255];

{основные операции потока из текстового файла}
constructor CFStreamTxt.Create(DataName:String);
begin
DN:=DataName; EndOfStream:=true;
{$I-} {отключить обработку ошибок ввода-вывода}
Assign(F,DN); Reset(F);
{$I+} {включить обработку ошибок ввода-вывода}
if IOResult <> 0 then
Failure(1)
else
begin
EndOfStream:=false;
SkipSpaces; {пропустить символы форматирования из начала файла}
end;
end;

destructor CFStreamTxt.Destroy; {Убираем мусор после работы програмы}
begin
Close(F); EndOfStream:=true; DN:='';
end;

function CFStreamTxt.GetChar:char;
begin
if EndOfStream then
Failure(2)
else
GetChar:=CharBufer;
end;

function CFStreamTxt.IsAfterSpace:boolean; {свободное место, и еще сразу отрабатываются ошибки}
begin
if EndOfStream then
Failure(3)
else
IsAfterSpace:=AfterSpaceBufer;
end;

procedure CFStreamTxt.Skip;
begin
if EndOfStream then
Failure(4)
else
SkipSpaces;
end;

function CFStreamTxt.IsEnd:boolean; {процедура проверяет является ли позиция концом стека}
begin
IsEnd:=EndOfStream;
end;

{дополнительные и служебные операции потока из текстового файла}
{фиксация/обработка ошибок потока из текстового файла}
procedure CFStreamTxt.Failure(n:Byte);
begin
writeln; writeln('Ошибка CFStreamTxt # ',n:1);
case n of
1: writeln('Метод Create: набор данных ',DN,' не найден');
2: writeln('Метод GetChar: конец потока ');
3: writeln('Метод IsAfterSpace: конец потока ');
4: writeln('Метод Skip: конец потока ');
end;
Halt(1); {выход в операционную среду}
end;
{вспомогательные функции потока из текстового файла}

procedure CFStreamTxt.SkipSpaces;
begin
AfterSpaceBufer:=false;
while true do
begin
if Eof(F) then
begin
EndOfStream:=true; break;
end;
if Eoln(F) then
readln(F)
else
begin
read(F,CharBufer);
if not(CharBufer in SetOfSpaces) then break;
end;
AfterSpaceBufer:=true;
end;
end;

end.


smile.gif
Olya
Вот я выложила модуль, ну и написала какие косяки вылезают, помогите пожалуйста доработать. wub.gif
Это текстовая версия — только основной контент. Для просмотра полной версии этой страницы, пожалуйста, нажмите сюда.