Article View: bln.sci.informatik
Article #115Re: a+(b*c) in Baum darstellen (Algorithmus)
From: Hermann Kremer
Date: Tue, 15 Oct 2002 23:21
Date: Tue, 15 Oct 2002 23:21
532 lines
16966 bytes
16966 bytes
Alex Scherbel schrieb in Nachricht <3dac82a2$0$171$9b622d9e@news.freenet.de>...
>Hallo!
>
>Kennt jemand einen Algorithmus, der einen Infix-Ausdruck in einem Baum
>darstellen kann?
>Also zum Beispiel:
>
> a+(b*c) => +
> / \
> a *
> / \
> b c
>Gru� Andy
Der folgende macht noch viel mehr:
/*************************************************************************/
/* */
/* EVALUATE.C - A simple mathematical expression evaluator in C */
/* */
/* operators supported: Operator Precedence */
/* */
/* ( Lowest */
/* ) Highest */
/* + (addition) Low */
/* - (subtraction) Low */
/* * (multiplication) Medium */
/* / (division) Medium */
/* % \ (modulus) High */
/* ^ (exponentiation) High */
/* sin( Lowest */
/* cos( Lowest */
/* atan( Lowest */
/* abs( Lowest */
/* sqrt( Lowest */
/* ln( Lowest */
/* exp( Lowest */
/* ceil( Lowest */
/* floor( Lowest */
/* round( Lowest */
/* */
/* */
/* constants supported: pi */
/* */
/* */
/* SYNOPSIS: eval "expression" */
/* */
/* */
/* Original Copyright 1991-93 by Robert B. Stout as part of */
/* the MicroFirm Function Library (MFL) */
/* */
/* This subset version is hereby donated to the public domain. */
/* */
/*************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <string.h>
#include <math.h>
typedef enum {Error_ = -1, Success_, False_ = 0, True_} Boolean_T;
typedef unsigned char BYTE;
typedef unsigned long DWORD;
typedef unsigned short WORD;
struct operator {
char token;
char *tag;
size_t taglen;
int precedence;
};
static struct operator verbs[] = {
{'+' , "+", 1, 2 },
{'-' , "-", 1, 3 },
{'*' , "*", 1, 4 },
{'/' , "/", 1, 5 },
{'%' , "%" , 1, 5 },
{'\\', "\\", 1, 5 },
{'^' , "^", 1, 6 },
{'(' , "(", 1, 0 },
{')' , ")", 1, 99},
{'S' , "SIN(", 4, 0 },
{'C' , "COS(", 4, 0 },
{'A' , "ABS(", 4, 0 },
{'L' , "LN(", 3, 0 },
{'E' , "EXP(", 4, 0 },
{'t' , "ATAN(", 5, 0 },
{'s' , "SQRT(", 5, 0 },
{'c' , "CEIL(", 5, 0 },
{'f' , "FLOOR(", 6, 0 },
{'r' , "ROUND(", 6, 0 },
{'\0', NULL, 0, 0 }
};
static char op_stack [256]; /* Operator stack */
static double arg_stack[256]; /* Argument stack */
static char token [256]; /* Token buffer */
static int op_sptr; /* op_stack pointer */
static int arg_sptr; /* arg_stack pointer */
static int parens; /* Nesting level */
static int state; /* 0 = Awaiting expression
1 = Awaiting operator
*/
const double Pi = 3.14159265358979323846;
static int do_op(void);
static int do_paren(void);
static void push_op(char);
static void push_arg(double);
static int pop_arg(double *);
static int pop_op(int *);
static char *get_exp(char *);
static struct operator *get_op(char *);
static int getprec(char);
static int getTOSprec(void);
static char *rmallws(char *);
static double round(double x)
{
return(x > 0.0 ? floor(x+0.5) : ceil(x-0.5));
}
/************************************************************************/
/* */
/* evaluate() */
/* */
/* Evaluates an ASCII mathematical expression. */
/* */
/* Arguments: 1 - String to evaluate */
/* 2 - Storage to receive double result */
/* */
/* Returns: Success_ if successful */
/* Error_ if syntax error */
/* R_ERROR if runtime error */
/* */
/* Side effects: Removes all whitespace from the string and converts */
/* it to U.C. */
/* */
/************************************************************************/
int evaluate(char *line, double *val)
{
double arg;
char *ptr = line, *str, *endptr;
int ercode;
struct operator *op;
strupr(line);
rmallws(line);
state = op_sptr = arg_sptr = parens = 0;
while (*ptr)
{
switch (state)
{
case 0:
if (((void *)0) != (str = get_exp(ptr)))
{
if (((void *)0) != (op = get_op(str)) &&
strlen(str) == op->taglen)
{
push_op(op->token);
ptr += op->taglen;
break;
}
if (Success_ == strcmp(str, "-"))
{
push_op(*str);
++ptr;
break;
}
if (Success_ == strcmp(str, "PI"))
push_arg(Pi);
else
{
if (0.0 == (arg = strtod(str, &endptr)) &&
((void *)0) == strchr(str, '0'))
{
return Error_;
}
push_arg(arg);
}
ptr += strlen(str);
}
else return Error_;
state = 1;
break;
case 1:
if (((void *)0) != (op = get_op(ptr)))
{
if (')' == *ptr)
{
if (Success_ > (ercode = do_paren()))
return ercode;
}
else
{
while (op_sptr &&
op->precedence <= getTOSprec())
{
do_op();
}
push_op(op->token);
state = 0;
}
ptr += op->taglen;
}
else return Error_;
break;
}
}
while (1 < arg_sptr)
{
if (Success_ > (ercode = do_op()))
return ercode;
}
if (!op_sptr)
return pop_arg(val);
else return Error_;
}
/*
** Evaluate stacked arguments and operands
*/
static int do_op(void)
{
double arg1, arg2;
int op;
if (Error_ == pop_op(&op))
return Error_;
pop_arg(&arg1);
pop_arg(&arg2);
switch (op)
{
case '+':
push_arg(arg2 + arg1);
break;
case '-':
push_arg(arg2 - arg1);
break;
case '*':
push_arg(arg2 * arg1);
break;
case '/':
if (0.0 == arg1)
return -2;
push_arg(arg2 / arg1);
break;
case '\\':
case '%' :
if (0.0 == arg1)
return -2;
push_arg(fmod(arg2, arg1));
break;
case '^':
push_arg(pow(arg2, arg1));
break;
case 't':
++arg_sptr;
push_arg(atan(arg1));
break;
case 'S':
++arg_sptr;
push_arg(sin(arg1));
break;
case 's':
if (0.0 > arg2)
return -2;
++arg_sptr;
push_arg(sqrt(arg1));
break;
case 'C':
++arg_sptr;
push_arg(cos(arg1));
break;
case 'A':
++arg_sptr;
push_arg(fabs(arg1));
break;
case 'L':
if (0.0 < arg1)
{
++arg_sptr;
push_arg(log(arg1));
break;
}
else return -2;
case 'E':
++arg_sptr;
push_arg(exp(arg1));
break;
case 'c':
++arg_sptr;
push_arg(ceil(arg1));
break;
case 'f':
++arg_sptr;
push_arg(floor(arg1));
break;
case 'r':
++arg_sptr;
push_arg(round(arg1));
break;
case '(':
arg_sptr += 2;
break;
default:
return Error_;
}
if (1 > arg_sptr)
return Error_;
else return op;
}
/*
** Evaluate one level
*/
static int do_paren(void)
{
int op;
if (1 > parens--)
return Error_;
do
{
if (Success_ > (op = do_op()))
break;
} while (getprec((char)op));
return op;
}
/*
** Stack operations
*/
static void push_op(char op)
{
if (!getprec(op))
++parens;
op_stack[op_sptr++] = op;
}
static void push_arg(double arg)
{
arg_stack[arg_sptr++] = arg;
}
static int pop_arg(double *arg)
{
*arg = arg_stack[--arg_sptr];
if (0 > arg_sptr)
return Error_;
else return Success_;
}
static int pop_op(int *op)
{
if (!op_sptr)
return Error_;
*op = op_stack[--op_sptr];
return Success_;
}
/*
** Get an expression
*/
static char * get_exp(char *str)
{
char *ptr = str, *tptr = token;
struct operator *op;
if (Success_ == strncmp(str, "PI", 2))
return strcpy(token, "PI");
while (*ptr)
{
if (((void *)0) != (op = get_op(ptr)))
{
if ('-' == *ptr)
{
if (str != ptr && 'E' != ptr[-1])
break;
if (str == ptr && !isdigit(ptr[1]) && '.' != ptr[1])
{
push_arg(0.0);
strcpy(token, op->tag);
return token;
}
}
else if (str == ptr)
{
strcpy(token, op->tag);
return token;
}
else break;
}
*tptr++ = *ptr++;
}
*tptr = '\0';
return token;
}
/*
** Get an operator
*/
static struct operator * get_op(char *str)
{
struct operator *op;
for (op = verbs; op->token; ++op)
{
if (Success_ == strncmp(str, op->tag, op->taglen))
return op;
}
return ((void *)0);
}
/*
** Get precedence of a token
*/
static int getprec(char token)
{
struct operator *op;
for (op = verbs; op->token; ++op)
{
if (token == op->token)
break;
}
if (op->token)
return op->precedence;
else return 0;
}
/*
** Get precedence of TOS token
*/
static int getTOSprec(void)
{
if (!op_sptr)
return 0;
return getprec(op_stack[op_sptr - 1]);
}
/*
** remove all whitespace from a string
*/
static char *rmallws(char *str)
{
char *obuf, *nbuf;
if (str)
{
for (obuf = str, nbuf = str; *obuf; ++obuf)
{
if (!isspace(*obuf))
*nbuf++ = *obuf;
}
*nbuf = '\0';
}
return str;
}
int main(int argc, char *argv[])
{
int retval;
double val;
printf("evaluate(%s) ", argv[1]);
printf("returned %d\n", retval = evaluate(argv[1], &val));
if (0 == retval)
printf("val = %f\n", val);
return 0;
}
/*************************************************************************/
Gru�
Hermann
--
>
Technical Details
Message-ID:
<aoi7r3$a9n$1@news.online.de>Path:
arc1-ca.pugleaf.net!archiver1.google.com!news1.google.com!sn-xit-03!sn-xit-05!sn-xit-01!sn-xit-04!supernews.com!newsfeed.gamma.ru!Gamma.RU!feed.news.nacamar.de!newsfeed01.sul.t-online.de!t-online.de!schlund.de!news.online.de!not-for-mailReferences:
<3dac82a2$0$171$9b622d9e@news.freenet.de>Show Full Headers
Complete Article Headers
X-Google-Language: ENGLISH,ASCII X-Google-Thread: 113080,d50faad52a419c16 X-Google-Attributes: gid113080,public X-Google-Thread: 10d38e,d50faad52a419c16 X-Google-Attributes: gid10d38e,public X-Google-Thread: 106601,d50faad52a419c16 X-Google-Attributes: gid106601,public X-Google-Thread: 102c5b,d50faad52a419c16 X-Google-Attributes: gid102c5b,public X-Google-Thread: fd78a,d50faad52a419c16 X-Google-Attributes: gidfd78a,public X-Google-Thread: 113dff,d50faad52a419c16 X-Google-Attributes: gid113dff,public X-Google-ArrivalTime: 2002-10-15 16:24:04 PST Path: arc1-ca.pugleaf.net!archiver1.google.com!news1.google.com!sn-xit-03!sn-xit-05!sn-xit-01!sn-xit-04!supernews.com!newsfeed.gamma.ru!Gamma.RU!feed.news.nacamar.de!newsfeed01.sul.t-online.de!t-online.de!schlund.de!news.online.de!not-for-mail From: "Hermann Kremer" <hermann.kremer@online.de> Newsgroups: bln.sci.informatik,de.sci.informatik.misc,maus.sci.informatik,schule.informatik,z-netz.sprachen.algorithmen,z-netz.wissenschaft.informatik Subject: Re: a+(b*c) in Baum darstellen (Algorithmus) Date: Wed, 16 Oct 2002 01:21:17 +0200 Organization: 1&1 Internet AG Lines: 534 Message-ID: <aoi7r3$a9n$1@news.online.de> References: <3dac82a2$0$171$9b622d9e@news.freenet.de> NNTP-Posting-Host: p5081679d.dip0.t-ipconnect.de X-Trace: news.online.de 1034724003 10551 80.129.103.157 (15 Oct 2002 23:20:03 GMT) X-Complaints-To: abuse@online.de NNTP-Posting-Date: 15 Oct 2002 23:20:03 GMT X-Newsreader: Microsoft Outlook Express 4.72.3110.5 X-MimeOLE: Produced By Microsoft MimeOLE V4.72.3110.3