Contributor: HARRY MARX
{
> Is there a standard of "best" algorithm used to convert algebraic format
> statements, such as a Pascal assignment statement, to a postfix format, such
> as usually used inside the compiler in preparation to generating machine
> language object file?
> Or, to put it another way, what is the best know way to convert
> X := 4*(Lastval + Curval)/3.0;
> to
> Lastval, Curval + 4 * 3.0 /
> ?
> Joel Lichtenwalner
I don't know about the best or standard, but I recently wrote a procedure
that does this without using any recursion or stacks. OK, it uses a few
array's to hold few WORD's.
What's nice about it is that it allows for only 4 temperary values to be
stored, which can be expanded to mean AX,BX,CX and DX. (You can increase this
to whatever you want) What's even nicer is that I have not been able to
write an infix expression complex enough to use more than 2 of the 4
temperary variables! It's very short, so I added it to the message (you may
flame me with your newest gem ... :)
{-----------------------------------------------------------------------}
const
OpChars = ['+','-','/','*']; {These two sets must be mutually exclusive}
SymbolChars=['a'..'z','A'..'Z','0'..'9','.','_'];
const
TempVars:string='adcb';{The 4 temporary variables (or registers)}
function GetTempResult(s:string):char;
{Returns the best place to store the temporary result}
var n,c:integer; p:array[1..5] of byte;
begin
c:=0;
for n:=1 to length(s) do if s[n] in ['a'..'d'] then begin
inc(c);
p[c]:=n;
end;
case c of
0:begin
GetTempResult:=TempVars[1];
delete(TempVars,1,1);
end;
1:GetTempResult:=s[p[1]];
else begin
for n:=2 to c do TempVars:=s[p[n]]+TempVars;
GetTempResult:=s[p[1]];
end;
end;
end;
function Priority(s:string):byte;
{Returns the oprator's priority}
begin
if length(s)=1 then
case s[1] of
'+','-':Priority:=0;
'*','/':Priority:=1;
end
else;
end;
procedure Error(S:string);
{Reports an error}
begin
writeln(';***Error***: ',S);
Halt;
end;
function PostFix(InFix:string):string;
var
Ops:array[1..255] of byte;{Allows only <=255 operators in one...}
Pri:array[1..255] of word;{...expression}
OC,n,L,R,Shell,MaxOp:integer;
LS,Op,RS:string;
begin
OC:=0;
Shell:=0;
MaxOp:=1;
n:=1;
while n<=length(InFix) do begin
if Infix[n] in OpChars then begin
R:=n;
while (R=Pri[MaxOp] then MaxOp:=OC;
n:=R-1;
end else
case InFix[n] of
'(':inc(Shell,100);{Allows for 100 levels of priorities...}
')':dec(Shell,100);{...for operators}
end;
inc(n);
end;
if Shell>0 then Error('Too few ")".');{Although I report this errors...}
if Shell<0 then Error('Too few "(".');{... the procedure still works...}
{...if you don't}
while OC>0 do begin
n:=Ops[MaxOp]-1; {Read Left Parameter}
while (n>0) and not(InFix[n] in SymbolChars) do dec(n);
L:=n;
while (L>0) and (InFix[L] in SymbolChars) do dec(L);
LS:=copy(InFix,L+1,n-L);
n:=Ops[MaxOp]+1; {Read Right Paramter}
while (n<=length(InFix)) and not(InFix[n] in SymbolChars) do inc(n);
R:=n;
while (R<=length(InFix)) and (InFix[R] in SymbolChars) do inc(R);
RS:=copy(InFix,n,R-n);
{PS. Only allows for 2 parameter ops.}
Op:=GetTempResult(LS+RS);
writeln(LS,RS,InFix[Ops[MaxOp]],' -> ',Op);
InFix[L+1]:=Op[1]; InFix[L+2]:=' ';
InFix[R-1]:=Op[1]; InFix[R-2]:=' ';
dec(OC);
for n:=MaxOp to OC do begin
Pri[n]:=Pri[n+1];
Ops[n]:=Ops[n+1];
end;
if MaxOp>OC then dec(MaxOp);
while (MaxOp>1) and (Pri[MaxOp-1]>Pri[MaxOp]) do dec(MaxOp);
end;
PostFix:=Op;
end;
var Infix:string;
begin
Infix:='(A+B)+(B/B+A*(C-D)+(E-F*G+H))';
writeln(InFix);
writeln(PostFix(InFix));
readln;
end.