3 ** PARSE.C Divides an input string into tokens and evaluates an
6 ** Originally written 5/89 in ANSI C
8 ** Eval is a floating point expression evaluator.
9 ** This is version 1.12
10 ** Copyright (C) 1993 Will Menninger
12 ** This program is free software; you can redistribute it and/or modify it
13 ** under the terms of the GNU General Public License as published by the
14 ** Free Software Foundation; either version 2 of the License, or any
17 ** This program is distributed in the hope that it will be useful, but
18 ** WITHOUT ANY WARRANTY; without even the implied warranty of
19 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 ** General Public License for more details.
22 ** You should have received a copy of the GNU General Public License along
23 ** with this program; if not, write to the Free Software Foundation, Inc.,
24 ** 675 Mass Ave, Cambridge, MA 02139, USA.
26 ** The author until 9/93 can be contacted at:
27 ** e-mail: willus@ilm.pfc.mit.edu
28 ** U.S. mail: Will Menninger, 45 River St., #2, Boston, MA 02108-1124
41 static double last_value
=0.0;
44 static int is_binary (char *s
);
45 static int is_unary (char c
);
46 static int instr (char c
,char *s
);
47 static BOOLEAN
legal (char *s
);
48 static BOOLEAN
is_digit (char c
);
49 static BOOLEAN
is_exp (char c
);
50 static BOOLEAN
get_token (int mode
,char *s
,int *n
,TOKENPTR t
,VARPTR vlist
,
51 VARPTR clist
,char *newname
);
52 static BOOLEAN
assign_as_var (char *s
,int *n
,TOKENPTR t
,VARPTR vlist
,
53 VARPTR clist
,char *newname
);
54 static BOOLEAN
assign_as_num (char *s
,int *n
,TOKENPTR t
,int max
,int base
);
55 static BOOLEAN
get_value (char *s
,VARPTR vlist
,VARPTR clist
,
57 static int base_override (char *s
,int *n
);
58 static int rank (int operator);
61 static int is_binary(char *s
)
64 if (s
[0]=='<' && s
[1]=='<')
66 if (s
[0]=='>' && s
[1]=='>')
68 return(instr(s
[0],BSTRING
));
72 static int is_unary(char c
)
75 return(instr(c
,USTRING
));
79 static int instr(char c
,char *s
)
84 for (i
=0;s
[i
]!=EOS
&& s
[i
]!=c
;i
++);
85 return(s
[i
]==EOS
? 0 : i
+1);
89 static BOOLEAN
legal(char *s
)
95 return(c
!=EOS
&& c
!='(' && c
!=')' && c
!=','
96 && c
!='=' && !isspace(c
) && !is_binary(s
));
100 static BOOLEAN
is_digit(char c
)
105 return((c
>='0' && c
<='9') || (c
>='a' && c
<='a'+base
-11));
106 return(c
>='0' && c
<='0'+base
-1);
110 static BOOLEAN
is_exp(char c
)
113 return((base
> 14) ? (c
=='\\') : (c
=='\\' || c
=='e' || c
=='E'));
117 ** get_token(int mode,char *s,int *n,TOKENPTR t,VARPTR vlist,
118 ** VARPTR clist,char *newname)
120 ** Figures out what the next token in the string s is, starting at (*n).
121 ** (*n) is returned pointing to the part of the string just after the
122 ** evaluated token. vlist and clist are used to search through in case
123 ** the token is a variable or constant. newname is assigned if the token
124 ** is a variable name not found in any of the lists.
126 ** Returns 0 for end of string, 1 for valid token found
130 static BOOLEAN
get_token(int mode
,char *s
,int *n
,TOKENPTR t
,VARPTR vlist
,
131 VARPTR clist
,char *newname
)
139 for (i
=(*n
);isspace(s
[i
]);i
++);
147 if (mode
==M_UNARY
&& is_unary(s
[i
]))
150 t
->code
=is_unary(s
[i
]);
154 if (is_binary(&s
[i
]) && (mode
!=M_UNARY
|| s
[i
]!='&'))
157 t
->code
=is_binary(&s
[i
]);
158 if (t
->code
==SHLEFT
|| t
->code
==SHRIGHT
)
163 t
->type
=instr(s
[i
],"(),=");
165 t
->type
+=LEFT_PAREN
-1;
173 return(assign_as_var(s
,n
,t
,vlist
,clist
,newname
));
175 c
=base_override(&s
[i
],&h
);
181 if (!is_digit(s
[i
]) && s
[i
]!='.')
182 return(assign_as_var(s
,n
,t
,vlist
,clist
,newname
));
183 if (s
[i
]=='.' && !is_digit(s
[i
+1]))
184 return(assign_as_var(s
,n
,t
,vlist
,clist
,newname
));
185 for (;legal(&s
[i
]);i
++)
187 if (s
[i
]=='.' || is_exp(s
[i
]))
190 return(assign_as_var(s
,n
,t
,vlist
,clist
,newname
));
195 return(assign_as_num(s
,n
,t
,i
,base
));
198 for (i
++;legal(&s
[i
]);i
++)
203 return(assign_as_var(s
,n
,t
,vlist
,clist
,newname
));
208 return(assign_as_num(s
,n
,t
,i
,base
));
210 if (s
[i
+1]=='+' || s
[i
+1]=='-')
212 if (!is_digit(s
[i
+1]))
213 return(assign_as_var(s
,n
,t
,vlist
,clist
,newname
));
214 for (i
++;legal(&s
[i
]);i
++)
217 return(assign_as_var(s
,n
,t
,vlist
,clist
,newname
));
220 return(assign_as_num(s
,n
,t
,i
,base
));
224 static BOOLEAN
assign_as_var(char *s
,int *n
,TOKENPTR t
,VARPTR vlist
,
225 VARPTR clist
,char *newname
)
229 char vname
[MAXINPUT
+1];
236 for (j
=0;legal(&s
[i
]) || (!j
&& s
[i
]=='&');i
++,j
++)
242 if (strlen(vname
)>MAXNAMELEN
)
243 vname
[MAXNAMELEN
]=EOS
;
244 strcpy(newname
,vname
);
245 if (vname
[0]=='\"' && vname
[1]==EOS
)
251 if (strlen(vname
)<=MAXFLEN
&& (i
=func_code(vname
))!=0)
258 strcpy(v
.name
,vname
);
259 if (search_varlist(&v
,clist
,&i
,MAXC
))
263 t
->value
=clist
[i
].value
;
268 if (search_varlist(&v
,vlist
,&i
,MAXV
))
271 t
->value
=vlist
[i
].value
;
281 static BOOLEAN
assign_as_num(char *s
,int *n
,TOKENPTR t
,int max
,int base
)
284 char num
[MAXINPUT
+1];
287 for (i
=(*n
),j
=0;i
<max
;i
++,j
++)
292 t
->value
=asciiconv(base
,num
);
298 ** evaluate(char *s,int showout,VARPTR vlist,VARPTR clist)
300 ** Evaluate parses the input string looking for help queries or an "equals"
301 ** sign that divides the string into an assignment variable and its
302 ** assigned expression. To evaluate the actual expression, get_value is
309 void evaluate(char *s
,int showout
,VARPTR vlist
,VARPTR clist
)
312 char varname
[MAXINPUT
+1];
316 int checked
,outbase
,oldbase
;
317 char bigbuf
[MAXOUTLEN
];
321 outbase
=base_override(s
,&j
);
323 if (outbase
&& isspace(s
[j
]))
333 for (i
=j
;s
[i
]!=EOS
&& s
[i
]!='=';i
++);
336 strcpy(varname
,&s
[j
]);
340 j
=get_token(M_UNARY
,varname
,&n
,&t
,vlist
,clist
,x
.name
);
343 printf("There must be valid variable name on the left side of the '='.\n");
346 if (varname
[n
]!=EOS
|| (t
.type
!=VARIABLE
&& t
.type
!=CONSTANT
))
348 printf("\"%s\" is not a valid variable name.\n",varname
);
351 if (t
.type
==CONSTANT
)
353 printf("\"%s\" is a pre-assigned constant. It cannot be reassigned.\n",x
.name
);
356 vn
=(t
.type
==VARIABLE
);
365 outbase
=base_override(&s
[i
],&j
);
366 if (outbase
&& isspace(s
[i
+j
]))
375 if (!get_value(&s
[i
],vlist
,clist
,&x
.value
))
378 if (outbase
!=oldbase
)
380 baseconv(x
.value
,bigbuf
);
382 printf("%s\n",bigbuf
);
383 if (outbase
!=oldbase
)
387 if (!insert_var(&x
,vlist
))
388 printf("No more variables can be assigned! Limit = %d.\n",MAXV
);
394 ** get_value(char *s,VARPTR vlist,VARPTR clist)
396 ** get_value evaluates an expression string by parsing it into tokens
397 ** (using get_token) and converting the string of tokens to a table that
398 ** contains tokens in reverse polish order. table_value is then called
399 ** to evaluate the final value of the reverse polish table of tokens.
400 ** That value is returned by get_value.
404 static BOOLEAN
get_value(char *s
,VARPTR vlist
,VARPTR clist
,double *ret_val
)
407 char nn
[MAXNAMELEN
+1];
410 char argcount
[MAXINPUT
+1];
418 while (get_token(mode
,s
,&spos
,&t
,vlist
,clist
,nn
))
421 return(eerror("The '=' character is not allowed in expressions."));
422 if (mode
==M_UNARY
&& (t
.type
==BINARY
|| t
.type
==COMMA
||
423 t
.type
==RIGHT_PAREN
))
424 return(eerror("Operand expected in expression."));
425 if (mode
==M_BINARY
&& (t
.type
==UNARY
|| t
.type
==CONSTANT
||
426 t
.type
==VARIABLE
|| t
.type
==FUNCTION
||
427 t
.type
==NUMBER
|| t
.type
==LEFT_PAREN
||
429 return(eerror("Operator expected in expression."));
430 if (t
.type
==VARIABLE
&& t
.code
<0)
432 printf("\"%s\" is an unassigned variable.\n",nn
);
435 if (mode
==M_FUNCTION
&& t
.type
!=LEFT_PAREN
)
436 return(eerror("Function names must be immediately followed "
437 "by a left parenthesis."));
459 while (top_of_stack(&t2
))
461 if (t2
.type
==BINARY
&& rank(t
.code
) > rank(t2
.code
))
463 if (t2
.type
==LEFT_PAREN
)
481 while (pop_token(&t2
) && t2
.type
!=LEFT_PAREN
)
484 if (t2
.type
!=LEFT_PAREN
)
485 return(eerror("Unmatched parentheses in expression."));
486 if (top_of_stack(&t2
) && t2
.type
==FUNCTION
)
491 if (func_nargs(t2
.code
)!=argcount
[argptr
]+1)
493 printf("Incorrect number of arguments "
494 "specified for function %s.\n",
503 while (pop_token(&t2
) && t2
.type
!=LEFT_PAREN
)
506 if (t2
.type
!=LEFT_PAREN
|| !top_of_stack(&t3
) ||
508 return(eerror("Misplaced comma in expression."));
509 if (!push_token(&t2
))
517 return(eerror("Expression is improperly terminated."));
518 while (pop_token(&t2
))
520 if (t2
.type
==LEFT_PAREN
)
521 return(eerror("Unmatched parentheses in expression."));
525 return(table_value(ret_val
));
529 BOOLEAN
eerror(char *message
)
532 printf("%s\n",message
);
537 static int rank(int operator)
565 static int base_override(char *s
,int *n
)
577 c
=tolower((int)s
[1]);
578 if (c
=='h' || c
=='o' || c
=='b' || c
=='d')
580 base
= c
=='h' ? 16 : (c
=='o' ? 8 :(c
=='b' ? 2 : 10));
585 else if (s
[0]=='0' && (s
[1]=='x' || s
[1]=='X'))
590 /* Assuming base 8 for a leading zero removed because of
591 confusion with floating point numbers */
594 c
=tolower((int)s
[1]);
595 if (c
=='0' || (c
>='2' && c
<='9') || (c
>='a' && c
<='z'))
597 base
= c
=='0' ? 10:((c
>='2'&&c
<='9')?c
-'0':c
-'a'+11);
610 void tokcpy(TOKENPTR dest
,TOKENPTR source
)
613 dest
->type
=source
->type
;
614 dest
->code
=source
->code
;
615 dest
->value
=source
->value
;