Algorithm required.

S

Steve Lambert

Hi Guys,

I realise this might not be the correct group for this post so maybe you
could redirect me accordingly. I have a coding requirement for which I
suspect a standard algorithm exists. I need to be able to evaluate a
general, bracketed boolean expression eg ( (A and B) OR (C and D) and (E or
F or G)) etc. Any ideas where I might be able to find appropriate
information.

Cheers

Steve
 
A

Arthur J. O'Dwyer

I realise this might not be the correct group for this post so maybe you
could redirect me accordingly.

comp.programming is for algorithmic questions.
I have a coding requirement for which I
suspect a standard algorithm exists. I need to be able to evaluate a
general, bracketed boolean expression eg ( (A and B) OR (C and D) and (E or
F or G)) etc. Any ideas where I might be able to find appropriate
information.

The general problem is called "parsing," and you can do it using a stack
in one pass, or you can build an intermediate data structure to hold the
"essence" of the formula until you're ready to solve it (e.g., if you're
going to be solving a system of equations this way).
ObOnTopic:

struct expr {
enum {ANDexp, ORexp, ATOM} type;
/* If it is a secondary expression... */
struct expr *lhs, *rhs;
/* If it is an atom... */
char varname[10];
};

[...]

int eval(struct expr *f) {
/* Evaluate a formula. */
switch (f->type) {
case ANDexp: return eval(f->lhs) && eval(f->rhs);
case ORexp: return eval(f->lhs) || eval(f->rhs);
case ATOM: return lookup_value(f->varname);
default: do_error("Whoops! I have a bug!");
}
}

The code for actually reading the input and building the 'expr' data
structure is left as an exercise for the reader with more free time this
morning. ;)

-Arthur
 
C

Chris Torek

ObOnTopic:

struct expr {
enum {ANDexp, ORexp, ATOM} type;
/* If it is a secondary expression... */
struct expr *lhs, *rhs;
/* If it is an atom... */
char varname[10];
};

I think it is worth pointing out that this is one of those rare
places where a union makes sense even in strictly conforming C
code. :) An "and" or "or" expression needs *just* the lhs and
rhs, while an "atom" expression needs *just* the varname -- so
why store all three in every kind of "expr" node? This gives
something like:

struct expr {
enum expr_type e_type;
union {
struct {
struct expr *sub_lhs, *sub_rhs;
} un_subexprs;
char un_varname[10];
} e_un;
};

Note that, in this case, the union and sub-struct types have no
tags (because none is really needed). The sub-struct is required
so that the lhs and rhs are in fact separate variables -- but if
you wanted to get rid of it, you could use an array instead:

struct expr {
enum expr_type e_type;
union {
struct expr *un_subexprs[2];
char un_varname[10];
} e_un;
};

and use un_subexprs[0] as the LHS and un_subexprs[1] as the RHS.

Unfortunately, there is no way to get rid of the separate union
member. I sometimes wish that C99 had adopted "anonymous" sub-
struct/union from one of the many dialects that have them (such
as Plan 9 C). As it is, you might choose to write:

#define e_varname e_un.un_varname

and/or:

#define e_lhs e_un.un_subexprs[0] /* assuming array */
#define e_rhs e_un.un_subexprs.sub_rhs /* assuming struct */

so that you can pretend C has anonymous sub-elements, even though
it does not. Note that this #define trick works only if the
struct-member "pseudo-names" (here e_varname, e_lhs, and e_rhs)
are not used as ordinary variable names, and tend not to work in
(for instance) debuggers.
 
C

CBFalconer

Chris said:
Arthur J. O'Dwyer said:
ObOnTopic:

struct expr {
enum {ANDexp, ORexp, ATOM} type;
/* If it is a secondary expression... */
struct expr *lhs, *rhs;
/* If it is an atom... */
char varname[10];
};

I think it is worth pointing out that this is one of those rare
places where a union makes sense even in strictly conforming C
code. :) An "and" or "or" expression needs *just* the lhs and
rhs, while an "atom" expression needs *just* the varname -- so
why store all three in every kind of "expr" node? This gives
something like:

struct expr {
enum expr_type e_type;
union {
struct {
struct expr *sub_lhs, *sub_rhs;
} un_subexprs;
char un_varname[10];
} e_un;
};

Note that, in this case, the union and sub-struct types have no
tags (because none is really needed). The sub-struct is required
so that the lhs and rhs are in fact separate variables -- but if
you wanted to get rid of it, you could use an array instead:

struct expr {
enum expr_type e_type;
union {
struct expr *un_subexprs[2];
char un_varname[10];
} e_un;
};

and use un_subexprs[0] as the LHS and un_subexprs[1] as the RHS.

Unfortunately, there is no way to get rid of the separate union
member. I sometimes wish that C99 had adopted "anonymous" sub-
struct/union from one of the many dialects that have them (such
as Plan 9 C). As it is, you might choose to write:

#define e_varname e_un.un_varname

and/or:

#define e_lhs e_un.un_subexprs[0] /* assuming array */
#define e_rhs e_un.un_subexprs.sub_rhs /* assuming struct */

so that you can pretend C has anonymous sub-elements, even though
it does not. Note that this #define trick works only if the
struct-member "pseudo-names" (here e_varname, e_lhs, and e_rhs)
are not used as ordinary variable names, and tend not to work in
(for instance) debuggers.

This is precisely where the better syntax of Pascal records will
shine. I would code that as:

TYPE
exprtype = andexpr, orexpr, atom;
exprptr = ^anexpr;
anexpr = RECORD
CASE etype : exptrtype OF
atom: (atomname : ARRAY[10] OF char);
andexpr,
orexpr: (lhs, rhs : exprptr);
END; (* CASE etype *)
END; (* expr RECORD *)

and future reference is dead simple:

VAR
thisexpr : exprptr;
....
new(thisexpr);
thisexpr^.etype = atom;
thisexpr^.atom = 'whatever ';
....
new(thisexpr);
thisexpr^.etype = orexpr;
thisexpr^.lhs = thatexpr;
thisexpr^.rhs = otherexpr;

and this is also a place where the much maligned WITH statement can
come into play:

new(thisexpr);
WITH thisexptr^ DO BEGIN
etype = orexpr;
lhs = thatexpr;
rhs = otherexptr;
END;

all of which avoids the interminable need for additional field,
union, structure names of pure standard C.
 
D

dandelion

Steve Lambert said:
Hi Guys,

I realise this might not be the correct group for this post so maybe you
could redirect me accordingly. I have a coding requirement for which I
suspect a standard algorithm exists. I need to be able to evaluate a
general, bracketed boolean expression eg ( (A and B) OR (C and D) and (E or
F or G)) etc. Any ideas where I might be able to find appropriate
information.

Get a copy of "The Dragon Book".

Aho, Sethi, Ullmann : Compilers. Principles, Techniques, and Tools.
Addison-Wesley, 1997. (the Dragonbook).
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
474,156
Messages
2,570,878
Members
47,404
Latest member
PerryRutt

Latest Threads

Top