``````{\$S-}
{\$M 65520,0,655360}
{\$N+}

{ Cal.pas by Colin Lamarre, 1991
Email: lamarre@vir.com

This program calculates a formula using recursion.

}

const
digits : set of char = ['0'..'9', '.', 'E'];

var
rcal : string;
print : boolean;
i : integer;

procedure error(cal : string; var i : integer);
begin
if print then
begin
writeln(copy(cal, i - 5, 10) + ' error.');
print := false;
end;
i := length(cal) + 1;
end;

function clean(var toupper : string) : boolean;
var
i, l, r : integer;
t : string;
begin
print := true;
t := '';
l := 0;
r := 0;
for i := 1 to length(toupper) do
if toupper[i] <> ' ' then
begin
t := t + upcase(toupper[i]);
if toupper[i] = '(' then
l := l + 1;
if toupper[i] = ')' then
r := r + 1;
end;
if r <> l then
begin
writeln('Missing brackets');
clean := false;
end
else
begin
if t = '' then
toupper := '0'
else
toupper := t;
clean := true;
end;
end;

function fstr(x : extended) : string;
var
s : string;
begin
str(x:1:9, s);
if s[1] = ' ' then
delete(s, 1, 1);
fstr := s;
end;

function fval(s : string) : extended;
var
x : extended;
code : integer;
begin
val(s, x, code);
fval := x;
end;

function prevnum(var temp : string; i : integer) : extended;
var
oldi : integer;
begin
oldi := i;
while ((temp[i] in digits) or ((temp[i - 1] = 'E') and (temp[i] in ['+', '-']))) and (i >= 1) do
dec(i);
if (temp[i] in ['+', '-']) and ((i = 1) or (temp[i - 1] in ['+', '-', '*', '/'])) then
dec(i);
prevnum := fval(copy(temp, i + 1, oldi - i));
delete(temp, i + 1, oldi - i);
end;

function signs(cal : string; var i : integer) : integer;
var
sign : integer;
begin
sign := 1;
repeat
if cal[i] = '-' then
begin
sign := sign * -1;
inc(i);
end
else
if cal[i] = '+' then
inc(i);
until not(cal[i] in ['-', '+']);
signs := sign;
end;

function nextnum(cal : string; var i : integer) : extended;
var
temp : string;
sign : integer;
begin
temp := '';
sign := signs(cal, i);
while (cal[i] in digits) and (i <= length(cal)) do
begin
temp := temp + cal[i];
inc(i);
if (cal[i - 1] = 'E') and (cal[i] in ['+', '-']) then
begin
temp := temp + cal[i];
inc(i);
end;
end;
nextnum := sign * fval(temp);
end;

function getbrackets(cal : string; var i : integer) : string;
var
count : integer;
temp : string;
begin
count := 1;
temp := '';
repeat
inc(i);
if cal[i] = '(' then
count := count + 1;
if cal[i] = ')' then
count := count - 1;
temp := temp + cal[i];
until (cal[i] = ')') and (count = 0);
delete(temp, length(temp), 1);
inc(i);
getbrackets := temp;
end;

function doadd(temp : string) : extended;
var
i : integer;
tot : extended;
begin
i := 1;
tot := nextnum(temp, i);
repeat
inc(i);
case temp[i - 1] of
'+' : tot := tot + nextnum(temp, i);
'-' : tot := tot - nextnum(temp, i);
end;
until i > length(temp);
end;

function domuls(cal : string) : extended;
var
i, sign : integer;
temp, s : string;
begin
i := 1;
temp := '';
repeat
case cal[i] of
'+', '-' : begin
temp := temp + cal[i];
inc(i);
end;

'*' : begin
inc(i);
sign := signs(cal, i);
if cal[i] in digits then
begin
s := fstr(sign * prevnum(temp, length(temp)) * nextnum(cal,i));
temp := temp + s;
end
else
if cal[i] = '(' then
begin
s := fstr(sign * prevnum(temp, length(temp)) * domuls(getbrackets(cal, i)));
temp := temp + s;
end
else
error(cal, i);
end;

'/' : begin
inc(i);
sign := signs(cal, i);
if cal[i] in digits then
begin
s := fstr(sign * prevnum(temp, length(temp)) / nextnum(cal, i));
temp := temp + s;
end
else
if cal[i] = '(' then
begin
s := fstr(prevnum(temp, length(temp)) / (sign * domuls(getbrackets(cal, i))));
temp := temp + s;
end
else
error(cal, i);
end;

'0'..'9', '.' : while (cal[i] in digits) and (i <= length(cal)) do
begin
temp := temp + cal[i];
inc(i);
if (cal[i - 1] = 'E') and (cal[i] in ['+', '-']) then
begin
temp := temp + cal[i];
inc(i);
end;
end;

'(' : temp := temp + fstr(domuls(getbrackets(cal, i)));

else
error(cal, i);
end;
until i > length(cal);
end;

function dopowers(cal : string) : string;
var
i, c : integer;
x, f : extended;

function fcnt(var cal : string; var i : integer) : integer;
var
j : integer;
begin
j := 0;
while cal[i] = '!' do
begin
inc(j);
dec(i);
end;
inc(i);
delete(cal, i, j);
fcnt := j;
end;

function fact(x : extended) : extended;
var
k, n : word;
ans : extended;
begin
ans := 1;
if x < 0 then
fact := ans / (x - x);
n := trunc(x);
for k := 2 to n do
ans := k * ans;
fact := ans;
end;

function getprev(var cal : string; var i : integer) : extended;
var
oldi, count : integer;
begin
dec(i);
oldi := i;
if cal[i] <> ')' then
begin
while ((cal[i] in digits) or ((cal[i - 1] = 'E') and (cal[i] in ['+', '-']))) and (i >= 1) do
dec(i);
if (cal[i] in ['+', '-']) and ((i = 1) or (cal[i - 1] in ['+', '-', '*', '/'])) then
dec(i);
getprev := fval(copy(cal, i + 1, oldi - i));
delete(cal, i + 1, oldi - i);
end
else
begin
count := 1;
while (cal[i] <> '(') and (count <> 0) and (i >= 1) do
begin
dec(i);
if cal[i] = ')' then
count := count + 1;
if cal[i] = '(' then
count := count - 1;
end;
getprev := domuls(dopowers(copy(cal, i + 1, oldi - i - 1)));
delete(cal, i, oldi - i + 1);
dec(i);
end;
end;

function getnext(var cal : string; i : integer) : extended;
var
oldi, sign, count : integer;
temp : string;
begin
oldi := i;
inc(i);
temp := '';
sign := signs(cal, i);
if cal[i] <> '(' then
begin
while (cal[i] in digits) and (i <= length(cal)) do
begin
temp := temp + cal[i];
inc(i);
if (cal[i - 1] = 'E') and (cal[i] in ['+', '-']) then
begin
temp := temp + cal[i];
inc(i);
end;
end;
getnext := sign * fval(temp);
delete(cal, oldi, i - oldi);
end
else
begin
count := 1;
temp := '';
repeat
inc(i);
if cal[i] = '(' then
count := count + 1;
if cal[i] = ')' then
count := count - 1;
temp := temp + cal[i];
until (cal[i] = ')') and (count = 0);
delete(temp, length(temp), 1);
getnext := sign * domuls(dopowers(temp));
delete(cal, oldi, i - oldi + 1);
end;
end;

begin
i := length(cal);
repeat
case cal[i] of
'^' : begin
x := getnext(cal, i);
if cal[i - 1] = '!' then
begin
dec(i);
c := fcnt(cal, i);
f := getprev(cal, i);
for c := 1 to c do
f := fact(f);
insert(fstr(exp(x * ln(f))), cal, i + 1);
end
else
insert(fstr(exp(x * ln(getprev(cal, i)))), cal, i + 1);
end;

'!' : begin
c := fcnt(cal, i);
f := getprev(cal, i);
for c := 1 to c do
f := fact(f);
insert(fstr(f), cal, i + 1);
end;

else
dec(i);
end;
until i < 1;
dopowers := cal;
end;

function dofuncs(cal : string) : string;
var
i : integer;
temp : string;

function next3 : string;
begin
next3 := cal[i + 1] + cal[i + 2] + cal[i + 3];
end;

function asin(ratio : extended) : extended;
begin
asin := arctan(ratio / sqrt((1 - ratio) * (1 + ratio)));
end;

function acos(ratio : extended) : extended;
begin
acos := arctan(sqrt((1 - ratio) * (1 + ratio)) / ratio);
end;

function atan(ratio : extended) : extended;
begin
atan := arctan(ratio);
end;

function tan(angle : extended) : extended;
begin
tan := sin(angle) / cos(angle);
end;

function cot(angle : extended) : extended;
begin
cot := cos(angle) / sin(angle);
end;

function log(x : extended) : extended;
begin
log := ln(x) / 2.302585093;
end;

begin
i := 1;
temp := '';
repeat
case cal[i] of
'+', '-',
'*', '/',
'(', ')',
'^', '!' : begin
temp := temp + cal[i];
inc(i);
end;

'S' : begin
if next3 = 'IN(' then
begin
inc(i, 3);
temp := temp + fstr(sin(domuls(dopowers(dofuncs(getbrackets(cal, i))))));
end
else
if next3 + cal[i + 4] = 'QRT(' then
begin
inc(i, 4);
temp := temp + fstr(sqrt(domuls(dopowers(dofuncs(getbrackets(cal, i))))));
end
else
error(cal, i);
end;

'C' : begin
if next3 = 'OS(' then
begin
inc(i, 3);
temp := temp + fstr(cos(domuls(dopowers(dofuncs(getbrackets(cal, i))))));
end
else
if next3 = 'OT(' then
begin
inc(i, 3);
temp := temp + fstr(cot(domuls(dopowers(dofuncs(getbrackets(cal, i))))));
end
else
error(cal, i);
end;

'T' : begin
if next3 = 'AN(' then
begin
inc(i, 3);
temp := temp + fstr(tan(domuls(dopowers(dofuncs(getbrackets(cal, i))))));
end
else
error(cal, i);
end;

'A' : begin
if next3 + cal[i + 4] = 'TAN(' then
begin
inc(i, 4);
temp := temp + fstr(atan(domuls(dopowers(dofuncs(getbrackets(cal, i))))));
end
else
if next3 + cal[i + 4] = 'COS(' then
begin
inc(i, 4);
temp := temp + fstr(acos(domuls(dopowers(dofuncs(getbrackets(cal, i))))));
end
else
if next3 + cal[i + 4] = 'SIN(' then
begin
inc(i, 4);
temp := temp + fstr(asin(domuls(dopowers(dofuncs(getbrackets(cal, i))))));
end
else
if next3 = 'BS(' then
begin
inc(i, 3);
temp := temp + fstr(abs(domuls(dopowers(dofuncs(getbrackets(cal, i))))));
end
else
error(cal, i);
end;

'L' : begin
if next3 = 'OG(' then
begin
inc(i, 3);
temp := temp + fstr(log(domuls(dopowers(dofuncs(getbrackets(cal, i))))));
end
else
if cal[i + 1] + cal[i + 2] = 'N(' then
begin
inc(i, 2);
temp := temp + fstr(ln(domuls(dopowers(dofuncs(getbrackets(cal, i))))));
end
else
error(cal, i);
end;

'E' : if next3 = 'XP(' then
begin
inc(i, 3);
temp := temp + fstr(exp(domuls(dopowers(dofuncs(getbrackets(cal, i))))));
end;

'P' : if cal[i + 1] = 'I' then
begin
inc(i, 2);
temp := temp + fstr(pi);
end
else
error(cal, i);

'0'..'9', '.' : while (cal[i] in digits) and (i <= length(cal)) do
begin
temp := temp + cal[i];
inc(i);
if (cal[i - 1] = 'E') and (cal[i] in ['+', '-']) then
begin
temp := temp + cal[i];
inc(i);
end;
end;

else
error(cal, i);
end;
until i > length(cal);
dofuncs := temp;
end;

begin
rcal := '';
for i := 1 to paramcount do
rcal := rcal + paramstr(i);

if clean(rcal) then
begin