program Parser; {adapted to Turbo Pascal by Glenn Brooke 5/6/86 from a program by Herbert Shcildt. this program reads an expression and returns the result. It can handle up to 26 one letter (A-Z) variables and real numbers. Supports +,-,*,/,and powers. Not bad! Speed isn't too bad, either. This kind of a program is really best as a function in your own program, so that the user can enter an expression, and the program can compute the result. For example, a function plotting program can simply ask for a function like 2*X + (3.14/X^4)/1.23, and plot the curve from -5 to +5. Quite powerful! } type str80 = string[80]; Ttype = (Delimiter, Variable, Number); var token, prog : str80; TokType : Ttype; code, t : integer; result : real; vars : array[0..25] of real; {26 variables} function IsAlpha(ch : char) : boolean; {true if ch is letter in alphabe} begin IsAlpha := (Upcase(ch) in ['A'..'Z']) end; function IsWhite(ch : char) : boolean; {true if newline, space or tab} begin IsWhite := (ch= ' ') or (ch=chr(9)) or (ch=chr(13)); end; function IsDelim(ch : char) : boolean; begin if pos(ch,' +-/*%^=()$')<>0 then IsDelim := true else IsDelim := false end; function Isdigit(ch : char) : boolean; begin Isdigit := ch in ['0'..'9'] end; procedure GetToken; var temp : str80; begin token := ''; while (IsWhite(prog[t])) do t := succ(t); if prog[t]='$' then token := '$'; if pos(prog[t],'+-*/%^=()')<>0 then begin TokType := Delimiter; token := prog[t]; {is an operator} t := succ(t); end else if IsAlpha(prog[t]) then begin while (not IsDelim(prog[t])) do begin token := token + prog[t]; {build token} t := succ(t) end; TokType := Variable; end else if IsDigit(prog[t]) then begin while (not IsDelim(prog[t])) do begin token := token + prog[t]; {build number} t := succ(t); Toktype := number; end; end; end; {GetToken} procedure PutBack; {put back unused token} begin t := t - length(token) end; procedure Serror(i : integer); {print error msg} begin case i of 1 : writeln('Syntax error'); 2 : writeln('Unbalanced parentheses'); 3 : writeln('No expression Present') end; end; function Pwr(a,b : real) : real; {raise a to the b power} var t : integer; temp : real; begin if a= 0 then pwr := 1 else begin temp := a; for t := trunc(b) downto 2 do a := a * temp; Pwr := a end end; function FindVar(s : str80) : real; var t : integer; begin FindVar := vars[ord(upcase(s[1]))-ord('A')] end; procedure Arith(op : char; var result, operand : real); begin case op of '+' : result := result + operand; '-' : result := result - operand; '*' : result := result * operand; '/' : result := result / operand; '^' : result := Pwr(result,operand); end end; {*********** Expression Parser w/ variables and assignment ********} procedure Level2(var result : real); forward; procedure Level1(var result : real); forward; procedure Level3(var result : real); forward; procedure Level4(var result : real); forward; procedure Level5(var result : real); forward; procedure Level6(var result : real); forward; procedure Primitive(var result : real); forward; procedure GetExp(var result: real); begin GetToken; if length(token) <> 0 then Level1(result) else Serror(3) end; procedure Level1; var hold : real; temp : Ttype; slot : integer; TempToken : str80; begin if Toktype = Variable then begin {save old token} temptoken := token; temp := toktype; slot := ord(upcase(token[1]))-ord('A'); GetToken; {see if there is an = for assignment} if token[1] <> '=' then {restore} begin Putback; token := temptoken; toktype := temp; level2(result) end else {is assignment} begin Gettoken; Level2(result); vars[slot] := result; end; end else Level2(result) end; {Level1} procedure Level2; var op : char; hold : real; begin Level3(result); op := token[1]; while ((op='+') or (op='-')) do begin Gettoken; Level3(hold); arith(op, result, hold); op := token[1] end; end; {Level2} procedure Level3; var op : char; hold : real; begin Level4(result); op := token[1]; while ((op='*') or (op='/')) do begin Gettoken; level4(hold); arith(op, result, hold); op := token[1] end; end; {Level3} procedure Level4; var hold : real; begin Level5(result); if token[1] = '^' then begin GetToken; Level4(hold); arith('^',result, hold); {exponent} end end; procedure Level5; var op : char; begin op := ' '; if ((tokType=Delimiter) and ((token[1]='+') or (token[1]= '-'))) then begin {unary plus or minus} op := token[1]; Gettoken end; Level6(result); if op='-' then result := -result end; {level5} procedure Level6; begin if (token[1]='(') and (Toktype=Delimiter) then begin {parenthesized expression} GetToken; Level2(result); if token[1]<>')' then Serror(2); {unbalanced} GetToken; end else Primitive(result); end; {Level6} procedure Primitive; begin if TokType=Number then val(token, result, code) else if TokType=Variable then result := FindVar(token) else serror(1); GetToken end; {Primitive} {************************** Main Test body ******************} begin for t := 0 to 25 do vars[t] := 0; {initialize variables} repeat t := 1; write(' Enter an expression (quit to stop) : '); readln(prog); prog := prog + '$'; GetExp(result); writeln(result); until prog = 'quit$'; end.