Okay, so I found this very basic regular math expression parser, and it works great!... except that if you enter an expression long enough (about 25 characters in length) it dies. The code isn't that complicated, but I can't see where the crash is happening.
Anyone see what's wrong?
</font><blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">code:</font><hr /><pre style="font-size:x-small; font-family: monospace;">
/* file calcu.c */
/* (c) Donald Axel GPL - license */
/* ANSI - C program demonstration, command line calculator */
/* Recursive descent parser */
/* Improve: Make a HELP command. Add more variables. */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <math.h>
#include "calcu.h"
#define stricmp strcasecmp
#define strnicmp strncasecmp
#define MAXL 8196
char gs[MAXL];
char *cp;
char *errorp;
double oldval;
int nextchar()
{
++cp;
while (*cp == ' ')
++cp;
return *cp;
}
int eatspace()
{
while (*cp == ' ')
++cp;
return *cp;
}
/* More local prototypes. This could, of course, be a separate file. */
double expression();
double product();
double potens();
double signedfactor();
double factor();
double stdfunc();
int evaluate(char *s, double *r)
{
cp = s;
eatspace();
*r = expression();
eatspace();
if (*cp == '\n' && !errorp)
return (0);
else
return (cp - s) + 11;
}
double expression()
{
double e;
int opera2;
e = product();
while ((opera2 = *cp) == '+' || opera2 == '-') {
nextchar();
if (opera2 == '+')
e += product();
else
e -= product();
}
eatspace();
return e;
}
double product()
{
double dp;
int ope;
dp = potens();
while ((ope = *cp) == '*' || ope == '/') {
nextchar();
if (ope == '*')
dp *= potens();
else
dp /= potens();
}
eatspace();
return dp;
}
double potens()
{
double dpo;
dpo = signedfactor();
while (*cp == '^') {
nextchar();
dpo = exp(log(dpo) * signedfactor());
}
eatspace();
return dpo;
}
double signedfactor()
{
double ds;
if (*cp == '-') {
nextchar();
ds = -factor();
} else
ds = factor();
eatspace();
return ds;
}
double factor()
{
double df;
switch (*cp) {
case '0':
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
df = strtod(cp, &cp);
break;
case '(':
nextchar();
df = expression();
if (*cp == ')')
nextchar();
else
errorp = cp;
break;
case 'X':
nextchar();
df = oldval;
break;
default:
df = stdfunc();
}
eatspace();
return df;
}
char *functionname[] =
{
"abs", "sqrt", "sin", "cos", "tan", "asin", "acos" "atan", "log", "exp", "sinh", "cosh",
"tanh", "\0"
};
double stdfunc()
{
double dsf;
char **fnptr;
int jj;
eatspace();
jj = 0;
fnptr = functionname;
while (**fnptr) {
if (strncmp(*fnptr, cp, strlen(*fnptr)) == 0)
break;
++fnptr;
++jj;
}
if (!**fnptr) {
errorp = cp;
return 1;
}
cp += (strlen(*fnptr) - 1);
nextchar();
dsf = factor();
switch (jj) {
case 0: dsf = abs(dsf); break;
case 1: dsf = sqrt(dsf); break;
case 2: dsf = sin(dsf); break;
case 3: dsf = cos(dsf); break;
case 4: dsf = tan(dsf); break;
case 5: dsf = asin(dsf); break;
case 6: dsf = acos(dsf); break;
case 7: dsf = atan(dsf); break;
case 8: dsf = log(dsf); break;
case 9: dsf = exp(dsf); break;
case 10: dsf = sinh(dsf); break;
case 11: dsf = cosh(dsf); break;
case 12: dsf = tanh(dsf); break;
default:{
errorp = cp;
return 4;
}
}
eatspace();
return dsf;
}
/* end calcu.c */</pre><hr /></blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">This is how I was using it:
</font><blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">code:</font><hr /><pre style="font-size:x-small; font-family: monospace;">+(NSString *)evaluateExpression
NSString *)string
{
char gs;
int rv;
double oldval;
[string getCString:&gs];
rv = evaluate(&gs, &oldval);
return [NSString stringWithFormat:@"%g", oldval];
}</pre><hr /></blockquote><font size="1" face="Geneva, Verdana, Arial, sans-serif">Thanx in advance,
F-bacher