Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

How to evaluate string ?

31 views
Skip to first unread message

schroder

unread,
May 26, 1997, 3:00:00 AM5/26/97
to

HELP!!!! I'm trying to write a graphing program, using BP7.0 however, I've
hit one major stumbling block: how do you evaluate a string? I know that
with BBC Basic there is a command called EVAL, but is there any way of
doing a similar thing using pascal? To illustrate what I mean:
x is a integer, with a value of 5 graph is a string, with a value of "5*x +
3" now, EVAL(graph) gives the result of 28.
how can i do this in pascal???? i've tried writing my own procedure, but
the how do i work out the order of braces?
any help would be much appreciated!! please either reply to this thread, or
mail me at Ric...@mhs.kzn.school.za <=== preferred! :)


Mitch Mooney

unread,
May 26, 1997, 3:00:00 AM5/26/97
to

Greetings,
Unless I misunderstood your question, in TP7.0 for Dos theres a built
in procedure called, you guessed it,"VAL", BP7 probable has the same.
-mitch

Asbjørn

unread,
May 26, 1997, 3:00:00 AM5/26/97
to

No, this isn't what he want's. He has a string that is a formula, not a
number.
I guess you'll have to write some proc's, or search some archives to see
if there
are some units.

--
- Asbjørn / Lord Crc

http://home.sn.no/~bheid/
lor...@hotmail.com

Mitch Mooney

unread,
May 26, 1997, 3:00:00 AM5/26/97
to

Greetings LordCrc,
Hmmmm, you've lost me here, he said he wanted to evaluate a string,
basicly he wanted this (or so i understood),

var
graph:string;
answer,x,i,code: integer;

begin
x:=5;
graph:='5';
val(graph,i,code);
if code <> 0 then
writeln('Error of invalid string input');
else
answer:=(x*i)+3;
writeln(answer);
end.

However, your quite right that there is units out there that make
handling strings easier. The above code is untested but should work. Im
not a programmer, just a hobbiest,so you might explain yourself to what
he really wanted, for Im not sure of what you implied.

Cheers,
-mitch

Mitch Mooney

unread,
May 26, 1997, 3:00:00 AM5/26/97
to lor...@hotmail.com

> No, this isn't what he want's. He has a string that is a formula, not a
> number.
> I guess you'll have to write some proc's, or search some archives to see
> if there
> are some units.
Greetings Again,
Gave some thought to it and came up with this procedure:

Program Mult_Int_With_Str_Add_Int;

uses Dos,Crt;
var
InIntToMult,OutInt,InIntToAdd: integer;
InStrToMult: string;

Procedure compute_formula(InIntToMult:integer;InIntToAdd:integer;
InStrToMult: string;var OutInt: integer);
var i,code: integer;
begin
VAL(InStrToMult,i,code);
If code <> 0 then
writeln('Error...string input wrong!')
Else
OutInt:=(i * InIntToMult) + InIntToAdd;
end;
{time to test this}
Begin
ClrScr;
write('Enter a integer you want to multiply: ');
readln(InIntToMult);
write('Enter a string integer you want to multiply: ');
readln(InStrToMult);
write('Enter a integer you want added to the sum of above: ');
readln(InIntToAdd);
Compute_Formula(InIntToMult,InIntToAdd,InStrToMult,OutInt);
writeln('The Final answer is: ',OutInt);
delay(5000);
end.

Except for any typos that might have been made, this has been tested and
works.Hope its clear enough and that you might us it.

The Brutsche Family

unread,
May 26, 1997, 3:00:00 AM5/26/97
to

schroder wrote:
>
> HELP!!!! I'm trying to write a graphing program, using BP7.0 however, I've
> hit one major stumbling block: how do you evaluate a string? I know that
> with BBC Basic there is a command called EVAL, but is there any way of
> doing a similar thing using pascal? To illustrate what I mean:
> x is a integer, with a value of 5 graph is a string, with a value of "5*x +
> 3" now, EVAL(graph) gives the result of 28.
> how can i do this in pascal???? i've tried writing my own procedure, but
> the how do i work out the order of braces?
> any help would be much appreciated!! please either reply to this thread, or
> mail me at Ric...@mhs.kzn.school.za <=== preferred! :)
It sounds like you want to parse and analyze the string using postfix
(or infix) notation. If you're confused, don't worry. I'll try to get
some more information for you . . .

-Phil Brutsche

?

unread,
May 27, 1997, 3:00:00 AM5/27/97
to

In article <01bc69a5$ce1c1b00$589b...@www.icon.co.za>, "schroder" <schr...@icon.co.za> says:
>
>HELP!!!! I'm trying to write a graphing program, using BP7.0 however, I've
>hit one major stumbling block: how do you evaluate a string? I know that
>with BBC Basic there is a command called EVAL, but is there any way of
>doing a similar thing using pascal? To illustrate what I mean:
>x is a integer, with a value of 5 graph is a string, with a value of "5*x +
>3" now, EVAL(graph) gives the result of 28.
>how can i do this in pascal???? i've tried writing my own procedure, but
>the how do i work out the order of braces?
>any help would be much appreciated!! please either reply to this thread, or
>mail me at Ric...@mhs.kzn.school.za <=== preferred! :)
>

The procedure I would write would work like this (at the moment I don't
have the time to write pascal code - perhaps someone wants to code and
publish it):

Example: eval('((1-2)*3+4)+5*6-7')

1. Search the string for expressions in brackets, cut them out and
recurse:
'((1-2)*3+4)+5*6-7' -> eval('(1-2)*3+4') -> result: 1
Convert the result of the recursion into a string and replace the
expression in brackets with it:
'((1-2)*3+4)+5*6-7' -> '1+5*6-7'
2. Evaluate all multiplications and divisions:
'1+5*6-7' -> '5*6'
'5*6' -> ['5','*','6'] -> val('5')*val('6') -> result: 30
'1+5*6-7' -> '1+30-7'
3. Evaluate all additions and substractions:
'1+30-7' -> '1+30'
'1+30' -> ['1','+','30'] -> val('1')+val('30') -> result: 31
'1+30-7' -> '31-7'
'31-7' -> ['31','-','7'] -> val('31')-val('7') -> result: 24
'31-7' -> '24'
4. Convert the result into a real:
val('24')

To make it easier to understand (if my explanation is easy to understand
at all), I only included *,/,+,- and brackets. You can add all arithmetic
functions you want, but you have to ensure that the evaluations are
performed in the right order.

If you have found out a better way to evaluate strings, you're free to
correct me.

Hannes.

Osmo Ronkanen

unread,
May 28, 1997, 3:00:00 AM5/28/97
to

Just how does one use the abobve to calculate '2*x+(5*y)/z'

Basic is an interpreted language, so the EVAL can just use the
interpreter to do the job. Pascal on the other hand is compiled and
there is no way to use any interpreter. For example the compiled Pascal
program has no knowledge of variable names. One has to write the
procedures oneself.

A good way to do is to write a recursive parser. First begin with the
syntax of the expression, like:

expression = term {+ | - term }
term = factor {* | - factor }
factor = number | '(' expression ')'

Then the rest is just coding. Here is an example. To use it just set
variables, like

v['X']:=@x;
v['Y']:=@y;
v['Z']:=@z;

and the call the routine

res:=value('2*x+(5*y)/z')

Now one can change values of x,y and z and then evaluate again with the
new values. Use Errorposition>0 (or errocode>0) to detect errors.
(Errorcode=1 in case of syntax errors, in case of floating point and
stack errors it is as specified in TP manual)

The routine does not support raising to power or functions. If you want
to add them, first change the syntax in comments and then the code

Unit Eval;

Interface


{$IFOPT N+}
Type Real=Extended;
{$ENDIF}

Function Value(const str:string):real;

var v:array['A'..'Z'] of ^real; { Variables used in evaluation }

var errorcode:byte;
errorposition:integer;

Implementation

{ Set jump and longjump routines for error handling. Setjump returns
always value TRUE. When Longjump is called, the program returns from the
previous setjump call, but so that the value returned is FALSE. (Note
the numeric equivalents of those are just the opposite of those used
in C)

for Turbo pascals before 6.0 use external assembler routines

}


Var JRec:record
sp_:word;
bp_:word;
case Boolean of
false: (ip_,cs_:word);
true: (RetAddr:Pointer);
End;

Function SetJump:Boolean; far; Assembler;
Asm
Pop JRec.ip_
Pop JRec.cs_
Mov JRec.Bp_,bp
Mov JRec.Sp_,sp
Mov al,1
Jmp JRec.RetAddr
End;

Procedure LongJump; far; Assembler;
Asm
Mov bp,Jrec.bp_
Mov sp,Jrec.sp_
xor ax,ax
Jmp Jrec.RetAddr
end;


{
Error handling routines to get back from runtime error, in this
case only division by zero, but in floating point implemenation there
would be overflows as well. Jumping out from Exitprocedure is not
something from Borland manual, but it seems to work

(note this is a floating point implementation )

}


var ExitSave:pointer;

Procedure ExitP; Far;
Begin
ExitProc:=ExitSave;
If (ErrorAddr<>Nil) then begin
errorcode:=Exitcode;
LongJump;
End;
End;

Procedure SetErrorRoutine;
Begin
If ExitProc<>@ExitP Then Begin
ExitSave:=ExitProc;
ExitProc:=@ExitP;
End;
End;

Procedure RemoveErrorRoutine;
Begin
ExitProc:=ExitSave;
End;

{ Function to convert a sting to upper case. Used in MOD. }

function UpcaseStr(st:string): string;
var i:integer;
begin
for i:=1 to length(st) do st[i]:=upcase(st[i]);
UpcaseStr:=st;
End;

var st:string;
index:integer;

Procedure SkipBlank;
begin
while st[index]=' ' do inc(index);
End;

(* Syntax:

expression = term {'+'|'-' term}
term = factor {'*'|'/' factor }
factor = {'+'| '-'} ( number | '(' expression ')' | variable )

number = real value
variable = the specific letter passed as parameter


*)


Function term:real; forward;
Function factor:real; forward;

Function Expression:real;
var x:real;
begin
x:=term;
repeat
SkipBlank;
case st[index] of
'+': begin inc(index); x:=x+term; End;
'-': begin inc(index); x:=x-term; End;
else begin expression:=x; exit; end;
End;
until false;
End;


Function term:real;
var x:real;
begin
x:=factor;
repeat
SkipBlank;
case upcase(st[index]) of
'*': begin inc(index); x:=x*factor; end;
'/': begin inc(index); x:=x/factor; end;
else begin term:=x; exit; end;
End;
until false;
End;


Procedure ValCopy(const st:string; first, count:integer; var x:real;
var error:integer);
begin
val(copy(st,first,count),x,error);
End;


Function factor:real;
var x:real;
err,err2:integer;
s:-1..1;
begin
if sptr<700 then begin
errorcode:=202;
longjump;
End;
{ writeln(sptr);}
SkipBlank;
s:=1;
while (st[index]='-') or (st[index]='+') do begin
if st[index]='-' then s:=-s;
inc(index);
skipblank;
End;
case st[index] of
'0'..'9': begin
valcopy(st,index,255,x,err);
if err=0 then longjump; { Just in case }
valcopy(st,index,err-1,x,err2);
inc(index,err-1);
if err2>0 then longjump;
End;
'(': begin
inc(index);
x:=expression;
SkipBlank;
if st[index]<>')' then longjump;
inc(index);
End;
else if upcase(st[index]) in ['A'..'Z'] then begin
x:=v[upcase(st[index])]^;
inc(index);
end else longjump;
End;
factor:=x*s;
End;


Function Value(const str:string):real;
Begin
st:=str+#0;
errorcode:=0;
errorposition:=0;
if SetJump then begin
SetErrorRoutine;
index:=1;
value:=expression;
if index<=length(str) then longjump;
End
else begin
value:=0;
errorposition:=index;
if errocode=0 then errocode:=1;
End;
RemoveErrorRoutine;
End;


end.


Osmo Ronkanen

unread,
Jun 1, 1997, 3:00:00 AM6/1/97
to

In article <5mf0sh$7...@newsserv.zdv.uni-tuebingen.de>,

? <hannes...@student.uni-tuebingen.de> wrote:
>In article <01bc69a5$ce1c1b00$589b...@www.icon.co.za>, "schroder" <schr...@icon.co.za> says:
>>
>>HELP!!!! I'm trying to write a graphing program, using BP7.0 however, I've
>>hit one major stumbling block: how do you evaluate a string? I know that
>>with BBC Basic there is a command called EVAL, but is there any way of
>>doing a similar thing using pascal? To illustrate what I mean:
>>x is a integer, with a value of 5 graph is a string, with a value of "5*x +
>>3" now, EVAL(graph) gives the result of 28.
>>how can i do this in pascal???? i've tried writing my own procedure, but
>>the how do i work out the order of braces?
>>any help would be much appreciated!! please either reply to this thread, or
>>mail me at Ric...@mhs.kzn.school.za <=== preferred! :)
>>
>
>The procedure I would write would work like this (at the moment I don't
>have the time to write pascal code - perhaps someone wants to code and
>publish it):
>
>Example: eval('((1-2)*3+4)+5*6-7')
>
>1. Search the string for expressions in brackets, cut them out and
> recurse:
> '((1-2)*3+4)+5*6-7' -> eval('(1-2)*3+4') -> result: 1
> Convert the result of the recursion into a string and replace the
> expression in brackets with it:
> '((1-2)*3+4)+5*6-7' -> '1+5*6-7'

That works nice in your example. But what if the result is not so nice
and the expression is already almost 255 bytes. Also have you considered
time and accuracy (in case of FP) that is lost in those various number to
string conversions?

>
>If you have found out a better way to evaluate strings, you're free to
>correct me.

I say a recursive parser is easier to write and more effective.

That's simply write the syntax:

Expression = term {'+'|'-' term}


term = factor {'*'|'/' factor}

factor = number | '(' expression ')'

Then one just needs functions to return the current character from the
string and to advance the pointer. If the pointer ad advanced past the
end of the string (by one character) then curchar should return some
specific end-character, like nul. It is also nice to have a
setjump/longjump system, for error handling. (for those who do not know
setjump always returns a specific value. When one later calls longjump
the execution returns from the previously called setjump but it just
returns a different value). Alternatively one could for example set a
global error flag and after each call check the flag and return
immediately if it is set. Here I signal errors just with "error". See a
practical implementation from my previous post. This post is to explain
the actual parser and how it so clearly relates to the syntax above:


Function expression:real;


var x:real;
begin
x:= term;

while curchar in ['+','-'] do begin
case curchar of
'+': begin nextchar; x:=x+term; End;
'-': begin nextchar; x:=x-term; End;
End;
End;
expression:=x;


End;

Function term:real;
var x:real;
begin
x:= factor;

while curchar in ['*','/'] do begin
case curchar of
'*': begin nextchar; x:=x*factor; End;
'/': begin nextchar; x:=x/factor; End;
End;
End;
term:=x;
End;

function factor:real;
begin
case curchar of
'-','0'..'9'; factor:=getnumber { not implemented here }
'(': begin
nextchar;
factor:=expression;
if curchar=')' then nextchar else error;
End;
else error;
End;
End;

After that one should check if curchar is the end char and that no error
has occurred. (Note above does not handle FP errors. If one uses
setjump/longjump one can simply set the error procedure and jump out of
it with longjump. Otherwise one should check each calculation with
opposite one (especially one should check division by zero).

Osmo


nether

unread,
Jun 1, 1997, 3:00:00 AM6/1/97
to

> > HELP!!!! I'm trying to write a graphing program, using BP7.0 however,
I've
> > hit one major stumbling block: how do you evaluate a string? I know
that
> > with BBC Basic there is a command called EVAL, but is there any way of
> > doing a similar thing using pascal? To illustrate what I mean:
> > x is a integer, with a value of 5 graph is a string, with a value of
"5*x +
> > 3" now, EVAL(graph) gives the result of 28.
> > how can i do this in pascal???? i've tried writing my own procedure,
but
> > the how do i work out the order of braces?
> > any help would be much appreciated!! please either reply to this
thread, or
> > mail me at Ric...@mhs.kzn.school.za <=== preferred! :)

There is a nice source for this on Turbo Pascal Programmers page.


-------------==== Posted via Sexzilla News ====------------------
http://www.sexzilla.com Search, Read, Post to Usenet
-------------==== With A Whole Lot More ====------------------


Hannes Röhm

unread,
Jun 2, 1997, 3:00:00 AM6/2/97
to

In article <5mre45$m...@kruuna.Helsinki.FI>, ronk...@cc.helsinki.fi (Osmo Ronkanen) says:
[...]

>
>That works nice in your example. But what if the result is not so nice
>and the expression is already almost 255 bytes. Also have you considered
>time and accuracy (in case of FP) that is lost in those various number to
>string conversions?
>
[...]

>>
>>If you have found out a better way to evaluate strings, you're free to
>>correct me.
>
>I say a recursive parser is easier to write and more effective.
>
[...]
>Osmo
>

You're right, converting a number back into a string isn't the best way
to evaluate strings. I decided to write the evaluation procedure and I
found out that recursion is the best way. My implementation is different
than yours.

I wrote a procedure that can be used similar to the procedure "val". The
differences are, that it only "returns" real values and that the error is
set to -1 if there are to many open brackets.

Here's the code:


unit evalstr;

interface

procedure eval (src : string; var res : real; var err : integer);

implementation

procedure eval;

procedure triml(var str : string; var count : byte);

var i : byte;

begin
i := 0;
repeat
inc(i);
until ord(str[i]) > 32;
str := copy(str, i, length(str)-i+1);
count := i-1;
end;

procedure trimr(var str : string);

var i : byte;

begin
i := length(str) + 1;
repeat
dec(i);
until ord(str[i]) > 32;
str := copy(str, 1, i);
end;


function cutl(str : string; pos : byte) : string;

begin
if pos > 0 then
cutl := copy(str, pos, length(str)-pos+1)
else cutl := '';
end;

function nextnum(str : string; var nextpos : byte; var err : integer) : real;

var i, brcount : byte;
res : real;
spccount : byte;
xerr : integer;

begin
nextpos := 0;
res := 0;
triml(str, spccount);
i := 1;
brcount := 1;
if (str[1] = '(') and (length(str) > 1) then begin
repeat
inc(i);
if str[i] = '(' then
inc(brcount)
else if str[i] = ')' then
dec(brcount);
until (brcount = 0) or (i = length(str));
if brcount = 0 then begin
eval(copy(str, 2, i-2), res, err);
if err > 0 then
inc(err);
end
else
err := -1;
inc(i);
if (i <= length(str)) and (err = 0) then
nextpos := i + spccount;
end
else
begin
val(str, res, xerr);
if xerr = 0 then
err := 0
else if xerr > 1 then begin
val(copy(str, 1, xerr-1), res, err);
nextpos := xerr + spccount;
end
else
err := xerr;
end;
if err > 0 then
inc(err, spccount);
nextnum := res;
end;

function nextop(str : string; var nextpos : byte; var err : integer) : char;

const allowedchars = ['*', '/', '+', '-'];

var spccount : byte;

begin
err := 0;
nextpos := 0;
triml(str, spccount);
if length(str) > 0 then begin
if str[1] in allowedchars then begin
nextop := str[1];
if length(str) > 1 then
nextpos := spccount + 2
else
err := spccount + 1;
end
else begin
err := spccount + 1;
nextop := ' ';
end;
end
else
nextop := ' ';
end;

var nextpos, xnextpos, charcount : byte;
operator, xoperator : char;
operand : real;
xerr : integer;

begin
trimr(src);
charcount := 0;
res := nextnum(src, nextpos, err);
if nextpos > 0 then
while (err = 0) and (nextpos > 0) do begin
src := cutl(src, nextpos);
inc(charcount, nextpos - 1);
operator := nextop(src, nextpos, err);
if err = 0 then begin
src := cutl(src, nextpos);
inc(charcount, nextpos - 1);
operand := nextnum(src, nextpos, err);
if err = 0 then
if (operator = '+') or (operator = '-') then begin
xoperator := nextop(cutl(src, nextpos), xnextpos, xerr);
if (xoperator = '*') or (xoperator = '/') then begin
eval(src, operand, err);
nextpos := 0;
end;
if err = 0 then
if operator = '+' then
res := res + operand
else
res := res - operand
else
if err > 0 then
inc(err, charcount);
end
else
if operator = '*' then
res := res * operand
else if operator = '/' then
res := res / operand
else
if err > 0 then
inc(err, charcount);
end
else
if err > 0 then
inc(err, charcount);
end;
if err <> 0 then
res := 0;
end;

end.


It may not be the fastest or most effective way, but it works ;-)

Hannes.

Sacha Chua

unread,
Jun 3, 1997, 3:00:00 AM6/3/97
to

? wrote:

Hello!

> >hit one major stumbling block: how do you evaluate a string? I know > >the how do i work out the order of braces?> Example: eval('((1-2)*3+4)+5*6-7')


> 1. Search the string for expressions in brackets, cut them out and
> recurse:

<snip snip snip snip>


> If you have found out a better way to evaluate strings, you're free to
> correct me.

Here's what we do for that. We convert it into postfix form (like 2+3*2
becomes 232*+, I can post the algorithm for that once I've rewritten it!
:) ), and then from there the evaluation is easy, using a stack and
popping the operands off as necessary.

--
+--- - Sacha Chua -------------- Sygma Creations ---+
\ http://www.geocities.com/SouthBeach/6562/ /
/ sa...@i-manila.com.ph \
+--- ----------------- <grin> ------------------ ---+

Osmo Ronkanen

unread,
Jun 4, 1997, 3:00:00 AM6/4/97
to

In article <339402...@i-manila.com.ph>,

Sacha Chua <sac...@geocities.com> wrote:
>? wrote:
>
>Hello!
>
>> >hit one major stumbling block: how do you evaluate a string? I know > >the how do i work out the order of braces?> Example: eval('((1-2)*3+4)+5*6-7')
>> 1. Search the string for expressions in brackets, cut them out and
>> recurse:
><snip snip snip snip>
>> If you have found out a better way to evaluate strings, you're free to
>> correct me.
>
>Here's what we do for that. We convert it into postfix form (like 2+3*2
>becomes 232*+, I can post the algorithm for that once I've rewritten it!
>:) ), and then from there the evaluation is easy, using a stack and
>popping the operands off as necessary.

But the algorithm that does the conversion can just as easily evaluate
the expression. There is no need for the intermediate format.

Osmo


0 new messages