1 /***********************************************************************
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
13 * Information and Software Systems Research *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Phong Vo <kpv@research.att.com> *
21 ***********************************************************************/
26 * AT&T Bell Laboratories
28 * long integer arithmetic expression evaluator
29 * long constants may be represented as:
32 * 0[xX]hhh hexadecimal
34 * n#ccc base n, 2 <= b <= 36
36 * NOTE: all operands are evaluated as both the parse
37 * and evaluation are done on the fly
43 #define getchr(ex) (*(ex)->nextchr++)
44 #define peekchr(ex) (*(ex)->nextchr)
45 #define ungetchr(ex) ((ex)->nextchr--)
47 #define error(ex,msg) return(seterror(ex,msg))
49 typedef struct /* expression handle */
51 char* nextchr
; /* next expression char */
52 char* errchr
; /* next char after error */
53 char* errmsg
; /* error message text */
54 long (*convert
)(const char*, char**, void*);
55 void* handle
; /* user convert handle */
59 * set error message string
63 seterror(register Expr_t
* ex
, char* msg
)
65 if (!ex
->errmsg
) ex
->errmsg
= msg
;
66 ex
->errchr
= ex
->nextchr
;
72 * evaluate a subexpression with precedence
76 expr(register Expr_t
* ex
, register int precedence
)
84 while (c
= getchr(ex
), isspace(c
));
89 if (!precedence
) return(0);
90 error(ex
, "more tokens expected");
111 switch (c
= getchr(ex
))
116 if (!precedence
) error(ex
, "too many )'s");
120 if (getchr(ex
) != ')')
123 error(ex
, "closing ) expected");
126 if (operand
) error(ex
, "operator expected");
130 if (precedence
> 1) goto done
;
131 if (peekchr(ex
) == ':')
140 if (getchr(ex
) != ':')
143 error(ex
, ": expected for ? operator");
150 else n
= expr(ex
, 2);
156 if (peekchr(ex
) == '|')
158 if (precedence
> 2) goto done
;
165 if (precedence
> 4) goto done
;
171 if (precedence
> 5) goto done
;
176 if (peekchr(ex
) == '&')
178 if (precedence
> 3) goto done
;
185 if (precedence
> 6) goto done
;
192 if (peekchr(ex
) != '=') error(ex
, "operator syntax error");
193 if (precedence
> 7) goto done
;
196 if (c
== '=') n
= n
== x
;
201 if (peekchr(ex
) == c
)
203 if (precedence
> 9) goto done
;
206 if (c
== '<') n
<<= x
;
211 if (precedence
> 8) goto done
;
212 if (peekchr(ex
) == '=')
216 if (c
== '<') n
= n
<= x
;
222 if (c
== '<') n
= n
< x
;
229 if (precedence
> 10) goto done
;
231 if (c
== '+') n
+= x
;
237 if (precedence
> 11) goto done
;
239 if (c
== '*') n
*= x
;
240 else if (x
== 0) error(ex
, "divide by zero");
241 else if (c
== '/') n
/= x
;
245 if (isspace(c
)) continue;
247 if (isdigit(c
)) n
= strton(ex
->nextchr
, &ex
->nextchr
, NiL
, 0);
248 else if (ex
->convert
) n
= (*ex
->convert
)(ex
->nextchr
, &ex
->nextchr
, ex
->handle
);
249 if (ex
->nextchr
== pos
) error(ex
, "syntax error");
252 if (ex
->errmsg
) return(0);
253 if (!operand
) error(ex
, "operand expected");
257 if (!operand
) error(ex
, "operand expected");
262 * evaluate an integer arithmetic expression in s
264 * (long)(*convert)(const char* string, char** end, void* handle)
265 * is a user supplied conversion routine that is called when unknown
266 * chars are encountered; string points to the part to be
267 * converted and end is adjusted to point to the next non-converted
268 * character; if string is 0 then end points to an error message string
270 * NOTE: (*convert)() may call strexpr(ex, )
274 strexpr(const char* s
, char** end
, long(*convert
)(const char*, char**, void*), void* handle
)
279 ex
.nextchr
= (char*)s
;
281 ex
.convert
= convert
;
284 if (peekchr(&ex
) == ':')
285 seterror(&ex
, "invalid use of :");
288 if (convert
) (*convert
)(NiL
, &ex
.errmsg
, handle
);
289 ex
.nextchr
= ex
.errchr
;
292 if (end
) *end
= ex
.nextchr
;