Синтаксический анализатор для уравнений с неизвестной
Необходимо на pascal сделать анализатор для произвольного выражения, вводимого в ручную пользователем, и содержащего одну неизвестную. Результатом работы данного анализатора должно быть значение введённого выражения. Например, пользователь вводит sqrt(x)-1 при x = 1. В результате мы получаем 0
В интернете я нашёл код анализатора для калькулятора. Я долго старался изменить его под свои нужды, но знаний паскаля мне не хватает. Вот сам код:
program Calculator;
var
ans : real;
S : string;
ErrPos : integer;
Mess : string;
procedure Calc(S: string;
var V: real;
var ErrPos: integer;
var ErrMess: string
);
const
EOT = #0;
type
Functions = (ABSOLUTE, SQUARE, TRUNCATE,
ROUNDING, SINUS, COSINUS, ARC,
LOG, EXPONENT, SQUAREROOT,
DUMMY
);
const
FirstFunc = ABSOLUTE;
LastFunc = SQUAREROOT;
FuncNames: array[Functions] of string[6] =
('ABS', 'SQR', 'TRUNC', 'ROUND',
'SIN', 'COS', 'ARCTAN', 'LN',
'EXP', 'SQRT', ''
);
var
i : integer;
Ch : char;
procedure Error(Message: string);
begin
if ErrPos = 0 then begin
ErrMess := Message;
ErrPos := i;
Ch := EOT;
end;
end;
procedure NextChar;
begin
if ErrPos <> 0 then
Ch := EOT
else
repeat
i := i + 1;
if i <= length(S) then
Ch := UpCase(S[i])
else
Ch := EOT;
until Ch <> ' ';
end;
procedure Number(var V: real);
var
NumStr : string; {Текст числа}
Err : integer; {Номер неверного символа}
procedure IntNumber;
begin
if not(Ch in ['0'..'9']) then
Error('Число начинается не с цифры');
while Ch in ['0'..'9'] do begin
NumStr := NumStr + Ch;
NextChar;
end;
end;
begin
NumStr := '';
IntNumber;
if Ch = '.' then begin
NumStr := NumStr + Ch;
NextChar;
IntNumber;
end;
if Ch = 'E' then begin
NumStr := NumStr + Ch;
NextChar;
if Ch in ['+','-'] then begin
NumStr := NumStr + Ch;
NextChar;
end;
IntNumber;
end;
Val(NumStr, V, Err);
if Err <> 0 then
Error('Ошибка в числе');
end;
procedure Name(var F: Functions);
var
NameStr : string;
begin
if Ch in ['A'..'Z'] then begin
NameStr := Ch;
NextChar;
end
else
Error('Ожидается буква');
while Ch in ['A'..'Z', '0'..'9'] do begin
NameStr := NameStr + Ch;
NextChar;
end;
F := FirstFunc;
while (F <= LastFunc) and (NameStr <> FuncNames[F]) do
F := succ(F);
if F = DUMMY then
Error('Неправильное имя функции');
end;
function Func(F: Functions; ans: real) : real;
begin
Func := ans;
case F of
ABSOLUTE : Func := abs(ans);
SQUARE : Func := sqr(ans);
TRUNCATE : Func := trunc(ans);
ROUNDING : Func := round(ans);
SINUS : Func := sin(ans);
COSINUS : Func := cos(ans);
ARC : Func := arctan(ans);
LOG :
if ans > 0 then
Func := ln(ans)
else
Error('Логарифм неположительного числа');
EXPONENT : Func := exp(ans);
SQUAREROOT :
if ans >= 0 then
Func := sqrt(ans)
else
Error('Корень из отрицательного числа');
end;
end;
procedure Expression(var V: real); forward;
procedure Multiplier(var V: real);
var
F : Functions;
begin
if Ch in ['0'..'9'] then
Number(V)
else if Ch in ['A'..'Z'] then begin
Name(F);
if Ch <> '(' then
Error('Ожидается ''(''')
else begin
NextChar;
Expression(V);
V := Func(F, V);
if Ch = ')' then
NextChar
else
Error('Ожидается '')''')
end
end
else if Ch = '(' then begin
NextChar;
Expression(V);
if Ch <> ')' then
Error('Ожидается '')''')
else
NextChar
end
else
Error('Ожидается число, функция или ''(''');
end;
procedure Addend(var V: real);
var
Op : char; {Знак операции}
X : real; {Значение операнда}
begin
Multiplier(V);
while Ch in ['*','/'] do begin
Op := Ch;
NextChar;
Multiplier(X);
if Op = '*' then
V := V * X
else if X <> 0 then
V := V / X
else
Error('Деление на ноль');
end;
end;
procedure Expression(var V: real);
var
Op : char;
X : real;
begin
Op := '+';
if Ch in ['+','-'] then begin
Op := Ch;
NextChar;
end;
Addend(V);
if Op = '-' then
V := -V;
while Ch in ['+','-'] do begin
Op := Ch;
NextChar;
Addend(X);
if Op = '+' then
V := V + X
else
V := V - X
end;
end;
begin
ErrPos := 0;
i := 0;
NextChar;
Expression(V);
if Ch <> EOT then
Error('Ожидается конец выражения');
end;
begin
WriteLn('Формульный калькулятор');
repeat
Write('?');
ReadLn(S);
Calc(S, ans, ErrPos, Mess);
if ErrPos > 0 then begin
WriteLn('^':ErrPos + 1);
WriteLn(Mess);
end
else if abs(ans) > 0.0001 then
WriteLn(ans:15:6)
else
WriteLn(ans);
until S = '';
end.