1 /* $EPIC: expr2.c,v 1.19 2004/11/10 03:20:35 jnelson Exp $ */
2 /*
3  * Zsh: math.c,v 3.1.2.1 1997/06/01 06:13:15 hzoli Exp
4  * math.c - mathematical expression evaluation
5  * This file is based on 'math.c', which is part of zsh, the Z shell.
6  *
7  * Copyright (c) 1992-1997 Paul Falstad, All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  * 1. Redistributions of source code must retain the copyright notice,
13  *    this list of conditions and the two following paragraphs.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimers in the
16  *    documentation and/or other materials provided with the distribution
17  * 3. The names of the author(s) may not be used to endorse or promote
18  *    products derived from this software without specific prior written
19  *    permission.
20  *
21  * In no event shall Paul Falstad or the Zsh Development Group be liable
22  * to any party for direct, indirect, special, incidental, or consequential
23  * damages arising out of the use of this software and its documentation,
24  * even if Paul Falstad and the Zsh Development Group have been advised of
25  * the possibility of such damage.
26  *
27  * Paul Falstad and the Zsh Development Group specifically disclaim any
28  * warranties, including, but not limited to, the implied warranties of
29  * merchantability and fitness for a particular purpose.  The software
30  * provided hereunder is on an "as is" basis, and Paul Falstad and the
31  * Zsh Development Group have no obligation to provide maintenance,
32  * support, updates, enhancements, or modifications.
33  *
34  */
35 /*
36  * Substantial modifications by Jeremy Nelson which are
37  * Coypright 1998, 2003 EPIC Software Labs, All rights reserved.
38  *
39  * You may distribute this file under the same terms as the above, by
40  * including the parties "Jeremy Nelson" and "EPIC Software Labs" to the
41  * limitations of liability and the express disclaimer of all warranties.
42  * This software is provided "AS IS".
43  */
44 #include <math.h>
45 
46 #define STACKSZ 	80
47 #define TOKENCOUNT	80
48 #define MAGIC_TOKEN	-14
49 
50 /*
51  * THIS IS THE "NEW NEW" MATH PARSER -- or shall I say, this is the
52  * new math parser, second edition.
53  */
54 /*
55  * Question: Why is this math parser so much more hideous than the old one?
56  *
57  * Answer: The implementation looks very very complex, and to a certain
58  * extent it is.  However, do not be frightened by the malicious abuse of
59  * macros and the over-use of inline functions.  The design of this math
60  * parser is not nearly as complex as its implementation.  Maybe that is
61  * due to my not being the world's best C programmer, and I probably wrote
62  * this code too quickly.  One of the most important design considerations
63  * was that it should be possible to prove correctness, while maintaining
64  * the possibility for general optimization.  Those are conflicting goals
65  * and this implementation tries to balance the two.
66  */
67 /*
68  * Question: Why should I use this math parser instead of the old one?
69  *
70  * Answer: Like the old math parser, this new math parser evaluates infix
71  * notation expressions and returns the resulting value of the entire
72  * expression.  Unlike the old math parser, this new math parser correctly
73  * obeys both operator precedence as well as associativity.  It still can
74  * do short-circuiting of &&, ||, and ?: operators.  All operands start
75  * off their life as text strings, but can be converted to and from other
76  * data types (such as floating point, integer, and boolean).  Type conversion
77  * is automatic and efficient, and the results of every conversion is cached,
78  * so the conversion is only done once, and only when it is actually needed.
79  * This new math parser has a slew of new operators, as well as correct
80  * implementations of some of the old operators.  This new math parser also
81  * handles both integer and floating point operations gracefully.
82  */
83 /*
84  * Question:  Why is everything stored in a struct?
85  *
86  * Answer: All the information for each expression is stored in a struct.
87  * This is done so that there are no global variables in use (they're all
88  * collected making them easier to handle), and makes re-entrancy possible
89  * since you don't have to worry about whether or not all of the state
90  * information is accounted for (it's all on the stack).
91  */
92 /*
93  * Question: Why do you keep a 'symbol table' for each expression?
94  *
95  * By keeping a record of every direct symbol or derived symbol during
96  * the entire lifetime of the expression, we can be assured that we have
97  * a clean way to clean up after an expression (no memory leaks), and
98  * permit a reference to any operator to persist for the entire lifetime
99  * of the expression, without having to worry about who might be holding
100  * a reference to an operand (tokens never change over their lifetime).
101  * By refering to each token through an integer, rather than a pointer,
102  * we can also prevent stale pointers, which can cause crashes.
103  *
104  * This also solves several more problems.  There is never any concern over
105  * whether or not a certain string is malloced(), or just who is responsible
106  * for free()ing it.  If you need a value to stay around as a temporary value
107  * you can always tokenize() it and get a handle which you then use further.
108  * The value will not go away until the entire expression has been parsed.
109  */
110 /*
111  * Question:  Why don't you support pre-compiled expressions?
112  *
113  * Because this implementation does not create a compiled spanning tree
114  * out of the expression before executing it, but rather tokenizes the
115  * operands and reduces the operations based on prior operations.  Perhaps
116  * this might change in the future, but don't count on it.  The lexer uses
117  * the results of prior operations to support such things as short circuits
118  * and changing that would be a big pain.
119  */
120 
121 typedef 	int		TOKEN;
122 typedef 	int		BooL;
123 
124 /*
125  * These flags tell us whether or not a given token has a useful value
126  * of the given type.  This is used to tell us when we need to do automatic
127  * conversion, or whether the conversion was done before and we can just
128  * grab the cached value.  These flags are used by the "used" field, and
129  * are cumulative.
130  */
131 #define USED_NONE		0
132 #define USED_LVAL		1 << 0
133 #define	USED_RAW		1 << 1
134 #define	USED_EXPANDED		1 << 2
135 #define USED_INTEGER		1 << 3
136 #define USED_FLOAT		1 << 4
137 #define USED_BOOLEAN		1 << 5
138 
139 /*
140  * Theoretically, all these macros are independant because the return value of
141  * INT*FUNC is typecasted back to INTTYPE.  One caveat is that INT2STR
142  * must return a malloc'd string.
143  */
144 #ifdef HAVE_LONG_LONG
145 typedef long long INTTYPE;
146 #define FORMAT "%lld"
147 #define STR2INT(x) ((INTTYPE)atoll(x))
148 #define INT2STR(x) (malloc_sprintf(NULL, FORMAT , (INTTYPE)(x)))
149 #else
150 typedef long INTTYPE;
151 #define FORMAT "%ld"
152 #define STR2INT(x) ((INTTYPE)atol(x))
153 #define INT2STR(x) (malloc_sprintf(NULL, FORMAT , (INTTYPE)(x)))
154 #endif
155 
156 /*
157  * This is a symbol table entry.
158  */
159 typedef struct TOKEN_type
160 {
161 	int	used;			/* Which fields contain useful info? */
162 	char *	lval;			/* Cached unexpanded variable name */
163 	char *	raw_value;		/* Cached unexpected string */
164 	char *	expanded_value;		/* Cached full expanded string */
165 	INTTYPE	integer_value;		/* Cached integer value */
166 	double	float_value;		/* Cached floating point value */
167 	short	boolean_value;		/* Cached boolean value */
168 } SYMBOL;
169 
170 #define __inline
171 
172 /*
173  * This is an expression context
174  */
175 typedef struct
176 {
177 	/* POSITION AND STATE INFORMATION */
178 	/*
179 	 * This is the current position in the lexing.
180 	 */
181 	char	*ptr;
182 
183 	/*
184 	 * When set, the expression is lexed, but nothing that may have a side
185 	 * effect (function calls, assignments, etc) are actually performed.
186 	 * Dummy values are instead substituted.
187 	 */
188 	int	noeval;
189 
190 	/*
191 	 * When set, this means the next token may either be a prefix operator
192 	 * or an operand.  When clear, it means the next operator must be a
193 	 * non-prefix operator.
194 	 */
195 	int	operand;
196 
197 
198 	/* TOKEN TABLE */
199 	/*
200 	 * Each registered 'token' is given a TOKEN id.  The idea is
201 	 * that we want TOKEN to be an opaque type to be used to refer
202 	 * to a token in a generic way, but in practice its just an integer
203 	 * offset into a char ** table.  We register all tokens sequentially,
204 	 * so this just gets incremented when we want to register a new token.
205 	 */
206 	TOKEN	token;
207 
208 	/*
209 	 * This is the list of operand (string) tokens we have extracted
210 	 * so far from the expression.  Offsets into this array are stored
211 	 * into the parsing stack.
212 	 */
213 	SYMBOL	tokens[TOKENCOUNT + 1];
214 
215 
216 	/* OPERAND STACK */
217 	/*
218 	 * This is the operand shift stack.  These are the operands that
219 	 * are currently awaiting reduction.  Note that rather than keeping
220 	 * track of the lvals and rvals here, we simply keep track of offsets
221 	 * to the 'tokens' table that actually stores all the relevant data.
222 	 * Then we can just call the token-class functions to get that data.
223 	 * This is more efficient because it allows us to recycle tokens
224 	 * more reasonably without wasteful malloc-copies.
225 	 */
226 	TOKEN 	stack[STACKSZ + 1];
227 
228 	/* Current index to the operand stack */
229 	int	sp;
230 
231 	/* This is the last token that was lexed. */
232 	TOKEN	mtok;
233 
234 	/* This is set when an error happens */
235 	int	errflag;
236 
237 	TOKEN	last_token;
238 
239 	const char	*args;
240 	int	*args_flag;
241 } expr_info;
242 
243 /*
244  * Useful macro to get at a specific token.
245  * 'c' is the expression context, 'v' is the token handle.
246  */
247 #define TOK(c, v) 	c->tokens[v]
248 
249 /* Forward function references */
250 __inline static	TOKEN	tokenize_raw (expr_info *c, char *t);
251 	static	char *	after_expando_special (expr_info *c);
252 	static	char *	alias_special_char (char **buffer, char *ptr,
253 					const char *args, char *quote_em,
254 					int *args_flag);
255 
256 
257 /******************** EXPRESSION CONSTRUCTOR AND DESTRUCTOR ****************/
258 /*
259  * Clean the expression context pointed to by 'c'.
260  * This function must be called before you call mathparse().
261  */
setup_expr_info(expr_info * c)262 static void	setup_expr_info (expr_info *c)
263 {
264 	int	i;
265 
266 	c->ptr = NULL;
267 	c->noeval = 0;
268 	c->operand = 1;
269 	c->token = 0;
270 	for (i = 0; i <= TOKENCOUNT; i++)
271 	{
272 		TOK(c, i).used = USED_NONE;
273 		TOK(c, i).lval = NULL;
274 		TOK(c, i).raw_value = NULL;
275 		TOK(c, i).expanded_value = NULL;
276 		TOK(c, i).integer_value = 0;
277 		TOK(c, i).float_value = 0;
278 		TOK(c, i).boolean_value = 0;
279 	}
280 	for (i = 0; i <= STACKSZ; i++)
281 		c->stack[i] = 0;
282 	c->sp = -1;
283 	c->mtok = 0;
284 	c->errflag = 0;
285 	c->last_token = 0;
286 	tokenize_raw(c, empty_string);	/* Always token 0 */
287 }
288 
289 /*
290  * Clean up the expression context pointed to by 'c'.
291  * This function must be called after you call mathparse().
292  */
destroy_expr_info(expr_info * c)293 static void 	destroy_expr_info (expr_info *c)
294 {
295 	int	i;
296 
297 	c->ptr = NULL;
298 	c->noeval = -1;
299 	c->operand = -1;
300 	for (i = 0; i < c->token; i++)
301 	{
302 		TOK(c, i).used = USED_NONE;
303 		new_free(&TOK(c, i).lval);
304 		new_free(&TOK(c, i).raw_value);
305 		new_free(&TOK(c, i).expanded_value);
306 	}
307 	c->token = -1;
308 	for (i = 0; i <= STACKSZ; i++)
309 		c->stack[i] = -1;
310 	c->sp = -1;
311 	c->mtok = -1;
312 	c->errflag = -1;
313 	c->last_token = -1;
314 }
315 
316 
317 /**************** TOKEN, PRECEDENCE, and ASSOCITIVITY TABLES ****************/
318 /*
319  * LR = left-to-right associativity
320  * RL = right-to-left associativity
321  * BOOL = short-circuiting boolean
322  */
323 #define LR 		0
324 #define RL 		1
325 #define BOOL 		2
326 
327 /*
328  * These are all the token-types.  Each of the operators is represented,
329  * as is the generic operand type
330  */
331 
332 enum LEX {
333 	M_INPAR,
334 	NOT, 		COMP, 		PREMINUS,	PREPLUS,
335 			UPLUS,		UMINUS,		STRLEN,
336 			WORDC,		DEREF,
337 	POWER,
338 	MUL,		DIV,		MOD,
339 	PLUS,		MINUS,		STRCAT,
340 	SHLEFT,		SHRIGHT,
341 	LES,		LEQ,		GRE,		GEQ,
342 	MATCH,		NOMATCH,
343 	DEQ,		NEQ,
344 	AND,
345 	XOR,
346 	OR,
347 	DAND,
348 	DXOR,
349 	DOR,
350 	QUEST,		COLON,
351 	EQ,		PLUSEQ,		MINUSEQ,	MULEQ,		DIVEQ,
352 			MODEQ,		ANDEQ,		XOREQ,		OREQ,
353 			SHLEFTEQ,	SHRIGHTEQ,	DANDEQ,		DOREQ,
354 			DXOREQ,		POWEREQ,	STRCATEQ,    STRPREEQ,
355 			SWAP,
356 	COMMA,
357 	POSTMINUS,	POSTPLUS,
358 	ID,
359 	M_OUTPAR,
360 	ERROR,
361 	EOI,
362 	TOKCOUNT
363 };
364 
365 
366 /*
367  * Precedence table:  Operators with a lower precedence VALUE have a higher
368  * precedence.  The theory behind infix notation (algebraic notation) is that
369  * you have a sequence of operands seperated by (typically binary) operators.
370  * The problem of precedence is that each operand is surrounded by two
371  * operators, so it is ambiguous which operator the operand "binds" to.  This
372  * is resolved by "precedence rules" which state that given two operators,
373  * which one is allowed to "reduce" (operate on) the operand.  For a simple
374  * explanation, take the expression  (3+4*5).  Now the middle operand is a
375  * '4', but we dont know if it should be reduced via the plus, or via the
376  * multiply.  If we look up both operators in the prec table, we see that
377  * multiply has the lower value -- therefore the 4 is reduced via the multiply
378  * and then the result of the multiply is reduced by the addition.
379  */
380 static	int	prec[TOKCOUNT] =
381 {
382 	1,
383 	2,		2,		2,		2,
384 			2,		2,		2,
385 			2,		2,
386 	3,
387 	4,		4,		4,
388 	5,		5,		5,
389 	6,		6,
390 	7,		7,		7,		7,
391 	8,		8,
392 	9,		9,
393 	10,
394 	11,
395 	12,
396 	13,
397 	14,
398 	15,
399 	16,		16,
400 	17,		17,		17,		17,		17,
401 			17,		17,		17,		17,
402 			17,		17,		17,		17,
403 			17,		17,		17,		17,
404 			17,
405 	18,
406 	2,		2,
407 	0,
408 	137,
409 	156,
410 	200
411 };
412 #define TOPPREC 21
413 
414 
415 /*
416  * Associativity table: But precedence isnt enough.  What happens when you
417  * have two identical operations to determine between?  Well, the easy way
418  * is to say that the first operation is always done first.  But some
419  * operators dont work that way (like the assignment operator) and always
420  * reduce the LAST (or rightmost) operation first.  For example:
421  *	(3+4+5)	    ((4+3)+5)    (7+5)    (12)
422  *      (v1=v2=3)   (v1=(v2=3))  (v1=3)   (3)
423  * So for each operator we need to specify how to determine the precedence
424  * of the same operator against itself.  This is called "associativity".
425  * Left-to-right associativity means that the operations occur left-to-right,
426  * or first-operator, first-reduced.  Right-to-left associativity means
427  * that the operations occur right-to-left, or last-operator, first-reduced.
428  *
429  * We have a special case of associativity called BOOL, which is just a
430  * special type of left-to-right associtivity whereby the right hand side
431  * of the operand is not automatically parsed. (not really, but its the
432  * theory that counts.)
433  */
434 static 	int 	assoc[TOKCOUNT] =
435 {
436 	LR,
437 	RL,		RL,		RL,		RL,
438 			RL,		RL,		RL,
439 			RL,		RL,
440 	RL,
441 	LR,		LR,		LR,
442 	LR,		LR,		LR,
443 	LR,		LR,
444 	LR,		LR,		LR,		LR,
445 	LR,		LR,
446 	LR,		LR,
447 	LR,
448 	LR,
449 	LR,
450 	BOOL,
451 	BOOL,
452 	BOOL,
453 	RL,		RL,
454 	RL,		RL,		RL,		RL,		RL,
455 			RL,		RL,		RL,		RL,
456 			RL,		RL,		RL,		RL,
457 			RL,		RL,		RL,		RL,
458 			RL,
459 	LR,
460 	RL,		RL,
461 	LR,
462 	LR,
463 	LR,
464 	LR
465 };
466 
467 
468 /* ********************* CREATE NEW SYMBOLS AND TOKENS ********************/
469 /* Lvalues are stored via this routine */
tokenize_lval(expr_info * c,const char * t)470 __inline static	TOKEN		tokenize_lval (expr_info *c, const char *t)
471 {
472 	if (c->token >= TOKENCOUNT)
473 	{
474 		error("Too many tokens for this expression");
475 		return -1;
476 	}
477 	TOK(c, c->token).used = USED_LVAL;
478 	malloc_strcpy(&TOK(c, c->token).lval, t);
479 	return c->token++;
480 }
481 
482 /*
483  * This is where we store our rvalues, kind of.  What we really store here
484  * are all of the string operands from the original expression.  Whenever
485  * one of the original operands is parsed, it is converted to a string and
486  * put in here and the index into the 'token' table is returned.  Only the
487  * operands of the original expression go here.  All derived operands (the
488  * result of operators) directly create "expanded" tokens.
489  */
490 /* THIS FUNCTION MAKES A NEW COPY OF 'T'.  YOU MUST DISPOSE OF 'T' YOURSELF */
tokenize_raw(expr_info * c,char * t)491 __inline static	TOKEN		tokenize_raw (expr_info *c, char *t)
492 {
493 	if (c->token >= TOKENCOUNT)
494 	{
495 		error("Too many tokens for this expression");
496 		return -1;
497 	}
498 	TOK(c, c->token).used = USED_RAW;
499 	malloc_strcpy(&TOK(c, c->token).raw_value, t);
500 	return c->token++;
501 }
502 
503 /*
504  * This is where any rvalues are stored.  The result of any operation that
505  * yeilds a string creates an 'expanded' token.  Tokens that begin life as
506  * 'expanded' tokens never can be passed through expand_alias() again.  This
507  * protects against possible security holes in the client.
508  */
tokenize_expanded(expr_info * c,char * t)509 __inline static	TOKEN		tokenize_expanded (expr_info *c, char *t)
510 {
511 	if (c->token >= TOKENCOUNT)
512 	{
513 		error("Too many tokens for this expression");
514 		return -1;
515 	}
516 	TOK(c, c->token).used = USED_EXPANDED;
517 	malloc_strcpy(&TOK(c, c->token).expanded_value, t);
518 	return c->token++;
519 }
520 
521 /*
522  * This creates an integer token.  This is useful for quick operation on
523  * complex mathematical expressions, where conversions to and from strings
524  * is both expensive, and unnecesary.  This type of token is created by
525  * integer-only operations like &, |, ^, <<, >>.
526  */
tokenize_integer(expr_info * c,INTTYPE t)527 __inline static	TOKEN		tokenize_integer (expr_info *c, INTTYPE t)
528 {
529 	if (c->token >= TOKENCOUNT)
530 	{
531 		error("Too many tokens for this expression");
532 		return -1;
533 	}
534 	TOK(c, c->token).used = USED_INTEGER;
535 	TOK(c, c->token).integer_value = t;
536 	return c->token++;
537 }
538 
539 /*
540  * This creates a floating point token.  This is useful for the same things
541  * that integer tokens are, and this is the token generated by floating
542  * point operations, such as +, -, *, /, %, **.
543  */
tokenize_float(expr_info * c,double t)544 __inline static	TOKEN		tokenize_float (expr_info *c, double t)
545 {
546 	if (c->token >= TOKENCOUNT)
547 	{
548 		error("Too many tokens for this expression");
549 		return -1;
550 	}
551 	TOK(c, c->token).used = USED_FLOAT;
552 	TOK(c, c->token).float_value = t;
553 	return c->token++;
554 }
555 
556 /*
557  * This creates a boolean token.  This is useful for the same things as
558  * integer tokens are.  This token is generated by any sort of logic
559  * operation, such as ==, !=, >, <, &&, ||.
560  */
tokenize_bool(expr_info * c,BooL t)561 __inline static	TOKEN		tokenize_bool (expr_info *c, BooL t)
562 {
563 	if (c->token >= TOKENCOUNT)
564 	{
565 		error("Too many tokens for this expression");
566 		return -1;
567 	}
568 	TOK(c, c->token).used = USED_BOOLEAN;
569 	TOK(c, c->token).boolean_value = t;
570 	return c->token++;
571 }
572 
573 /******************** RETRIEVE SYMBOLS FROM TOKEN HANDLES *******************/
574 /*
575  * These functions permit you to get at the tokens in various ways.
576  * There is a definite concept of each token being stored in several
577  * different representations: "raw" format (as the user specified it
578  * in the expression), "expanded" format (what the raw value looks like
579  * after it is passed through expand_alias), "integer" format (what the
580  * expanded value looks like after a call to atol()), "float" format,
581  * (what the expanded value looks like after a call to atof()), and
582  * "boolean" format (what the expanded value looks like after a call to
583  * check_val()).  Each of these types are created on demand; so that if
584  * a token is never referenced in an integer context, the expensive
585  * conversion to an integer is not performed.  This is inteded to keep
586  * the number of unnecesary conversions to an absolute minimum.
587  *
588  * YOU MUST NOT EVER -- EVER -- FREE THE RETURN VALUE FROM ANY OF THESE
589  * FUNCTIONS!  TO DO SO WILL CRASH THE CLIENT!  YOU HAVE BEEN WARNED!
590  */
591 
592 /*
593  * Get the "raw" value of the token.  For tokens that have been created
594  * via "tokenize", nothing has to be done since the raw value is already
595  * present.  However, for computed tokens (such as the result of a math
596  * operation), the raw token may not actually exist, and so it must be
597  * infered from whatever data is available.  We use the value that has
598  * the most information, starting with expanded string, to the boolean
599  * value.
600  */
get_token_raw(expr_info * c,TOKEN v)601 __inline static	const char *	get_token_raw (expr_info *c, TOKEN v)
602 {
603 	if (v == MAGIC_TOKEN)	/* Magic token */
604 		return c->args;			/* XXX Probably wrong */
605 
606 	if (v < 0 || v >= c->token)
607 	{
608 		error("Token index [%d] is out of range", v);
609 		return get_token_raw(c, 0);	/* The empty token */
610 	}
611 
612 	if (v == 0)
613 		return empty_string;
614 
615 	if (c->noeval)
616 		return get_token_raw(c, 0);
617 #if 0
618 		panic("c->noeval is not valid here. [1]");
619 #endif
620 
621 
622 	if ((TOK(c, v).used & USED_RAW) == 0)
623 	{
624 		TOK(c, v).used |= USED_RAW;
625 
626 		if (TOK(c, v).used & USED_EXPANDED)
627 			panic("Cannot convert EXPANDED token to RAW");
628 		else if (TOK(c, v).used & USED_FLOAT)
629 		{
630 			TOK(c, v).raw_value =
631 				malloc_sprintf(NULL, "%f", TOK(c, v).float_value);
632 			canon_number(TOK(c, v).raw_value);
633 		}
634 		else if (TOK(c, v).used & USED_INTEGER)
635 			TOK(c, v).raw_value =
636 				INT2STR(TOK(c, v).integer_value);
637 		else if (TOK(c, v).used & USED_BOOLEAN)
638 			TOK(c, v).raw_value =
639 				malloc_sprintf(NULL, "%d", TOK(c, v).boolean_value);
640 		else if (TOK(c, v).used & USED_LVAL)
641 		{
642 			if (x_debug & DEBUG_NEW_MATH_DEBUG)
643 				yell(">>> Expanding var name [%d]: [%s]",
644 					v, TOK(c, v).lval);
645 
646 			TOK(c, v).raw_value = expand_alias(TOK(c, v).lval,
647 					c->args, c->args_flag, NULL);
648 
649 			if (x_debug & DEBUG_NEW_MATH_DEBUG)
650 				yell(">>> Expanded var name [%d]: [%s] to [%s]",
651 					v, TOK(c, v).lval, TOK(c, v).raw_value);
652 		}
653 		else
654 			panic("Can't convert this token to raw format");
655 	}
656 
657 	return TOK(c, v).raw_value;
658 }
659 
660 /*
661  * This is kind of funky.  This is used to get the "fully qualified"
662  * lvalue for a given token.  What that means is that this is not the
663  * raw value of TOK(c, v).lval, but is rather TOK(c, v).raw, but if
664  * and only if (TOK(c, v).used & USED_LVAL)!  Otherwise, this returns
665  * NULL and emits an error.
666  */
get_token_lval(expr_info * c,TOKEN v)667 __inline static const char *	get_token_lval (expr_info *c, TOKEN v)
668 {
669 	if (v == MAGIC_TOKEN)	/* Magic token */
670 		return c->args;			/* XXX Probably wrong */
671 
672 	if (v < 0 || v >= c->token)
673 	{
674 		error("Token index [%d] is out of range", v);
675 		return NULL;			/* No lvalue here! */
676 	}
677 
678 	if (v == 0)
679 		return NULL;		/* Suppress the operation entirely */
680 	else if (c->noeval)
681 	{
682 		return NULL;		/* Suppress the operation entirely */
683 #if 0
684 		return get_token_raw(c, 0);
685 		panic("c->noeval is not valid here. [0]");
686 #endif
687 	}
688 	else if (((TOK(c, v).used & USED_LVAL) == 0))
689 	{
690 		error("Token [%d] is not an lvalue", v);
691 		return NULL;			/* No lvalue here! */
692 	}
693 	else
694 		return get_token_raw(c, v);
695 }
696 
697 
698 /*
699  * Get the "expanded" representation of the token.  The first time you
700  * call this function, it gets the "raw" value, if there is one, and then
701  * call expand_alias() to get the value.  Of course, there is always a
702  * "raw" value, as get_token_raw() can convert from anything.
703  */
get_token_expanded(expr_info * c,TOKEN v)704 __inline static	const char *	get_token_expanded (expr_info *c, TOKEN v)
705 {
706 	if (v == MAGIC_TOKEN)	/* Magic token */
707 		return c->args;
708 
709 	if (v < 0 || v >= c->token)
710 	{
711 		error("Token index [%d] is out of range", v);
712 		return get_token_expanded(c, 0);	/* The empty token */
713 	}
714 
715 	if (v == 0)
716 		return get_token_raw(c, 0);
717 
718 	if (c->noeval)
719 		return get_token_raw(c, 0);
720 #if 0
721 		panic("c->noeval is not valid here. [2]");
722 #endif
723 
724 	if (x_debug & DEBUG_NEW_MATH_DEBUG)
725 		yell(">>> Getting token [%d] now.", v);
726 
727 	if ((TOK(c, v).used & USED_EXPANDED) == 0)
728 	{
729 		char	*myval;
730 
731 		myval = LOCAL_COPY(get_token_raw(c, v));
732 		TOK(c, v).used |= USED_EXPANDED;
733 
734 		/*
735 		 * If this token started off life as an lval, then the
736 		 * "raw" value of this token will yeild the expanded form
737 		 * of the lvalue, suitable for passing to alias_special_char.
738 		 */
739 		if (TOK(c, v).used & USED_LVAL)
740 		{
741 			char *buffer = NULL;
742 
743 			if (x_debug & DEBUG_NEW_MATH_DEBUG)
744 				yell(">>> Looking up variable [%d]: [%s]",
745 					v, myval);
746 
747 			alias_special_char(&buffer, myval, c->args,
748 					NULL, c->args_flag);
749 			if (!buffer)
750 				buffer = malloc_strdup(empty_string);
751 			TOK(c, v).expanded_value = buffer;
752 
753 			if (x_debug & DEBUG_NEW_MATH_DEBUG)
754 				yell("<<< Expanded variable [%d] [%s] to: [%s]",
755 					v, myval, TOK(c, v).expanded_value);
756 		}
757 
758 		/*
759 		 * Otherwise, this token started off life as an rval
760 		 * (such as a [...] string), and only needs to be expanded
761 		 * with alias_special_char to yeild a useful value.
762 		 */
763 		else if (TOK(c, v).used & USED_RAW)
764 		{
765 			if (x_debug & DEBUG_NEW_MATH_DEBUG)
766 				yell(">>> Expanding token [%d]: [%s]",
767 					v, myval);
768 
769 			TOK(c, v).used |= USED_EXPANDED;
770 			TOK(c, v).expanded_value =
771 				expand_alias(myval, c->args,
772 						c->args_flag, NULL);
773 
774 			if (x_debug & DEBUG_NEW_MATH_DEBUG)
775 				yell("<<< Expanded token [%d]: [%s] to: [%s]",
776 					v, myval, TOK(c, v).expanded_value);
777 		}
778 		else
779 			panic("Cannot convert from this token to EXPANDED");
780 	}
781 
782 	if (x_debug & DEBUG_NEW_MATH_DEBUG)
783 		yell("<<< Token [%d] value is [%s].", v, TOK(c, v).expanded_value);
784 	return TOK(c, v).expanded_value;
785 }
786 
787 /*
788  * Get the integer representation of the token.  The first time you call
789  * this function, it calls atof() on the "raw" value, if there is one,
790  * to get the result.
791  */
get_token_integer(expr_info * c,TOKEN v)792 __inline static	INTTYPE	get_token_integer (expr_info *c, TOKEN v)
793 {
794 	if (v == MAGIC_TOKEN)	/* Magic token */
795 		return STR2INT(c->args);		/* XXX Probably wrong */
796 
797 	if (v < 0 || v >= c->token)
798 	{
799 		error("Token index [%d] is out of range", v);
800 		return 0;		/* The empty token */
801 	}
802 
803 	if ((TOK(c, v).used & USED_INTEGER) == 0)
804 	{
805 		const char *	myval = get_token_expanded(c, v);
806 
807 		TOK(c, v).used |= USED_INTEGER;
808 		TOK(c, v).integer_value = STR2INT(myval);
809 	}
810 	return TOK(c, v).integer_value;
811 }
812 
813 /*
814  * Get the floating point value representation of the token.
815  */
get_token_float(expr_info * c,TOKEN v)816 __inline static	double	get_token_float (expr_info *c, TOKEN v)
817 {
818 	if (v == MAGIC_TOKEN)	/* Magic token */
819 		return atof(c->args);		/* XXX Probably wrong */
820 
821 	if (v < 0 || v >= c->token)
822 	{
823 		error("Token index [%d] is out of range", v);
824 		return 0.0;		/* The empty token */
825 	}
826 
827 	if ((TOK(c, v).used & USED_FLOAT) == 0)
828 	{
829 		const char *	myval = get_token_expanded(c, v);
830 
831 		TOK(c, v).used |= USED_FLOAT;
832 		TOK(c, v).float_value = atof(myval);
833 	}
834 	return TOK(c, v).float_value;
835 }
836 
837 /*
838  * Get the boolean value of the token
839  */
get_token_boolean(expr_info * c,TOKEN v)840 __inline static	BooL	get_token_boolean (expr_info *c, TOKEN v)
841 {
842 	if (v == MAGIC_TOKEN)	/* Magic token */
843 		return check_val(c->args);	/* XXX Probably wrong */
844 
845 	if (v < 0 || v >= c->token)
846 	{
847 		error("Token index [%d] is out of range", v);
848 		return 0;		/* The empty token */
849 	}
850 
851 	if ((TOK(c, v).used & USED_BOOLEAN) == 0)
852 	{
853 		const char *	myval = get_token_expanded(c, v);
854 
855 		TOK(c, v).used |= USED_BOOLEAN;
856 		TOK(c, v).boolean_value = check_val(myval);
857 	}
858 	return TOK(c, v).boolean_value;
859 }
860 
861 /* *********************** ADD TO OPERAND STACK **************************** */
862 /*
863  * Adding (shifting) and Removing (reducing) operands from the stack is a
864  * fairly straightforward process.  The general way to add an token to
865  * the stack is to pass in its TOKEN index.  However, there are some times
866  * when you want to shift a value that has not been tokenized.  So you call
867  * one of the other functions that will do this for you.
868  */
push_token(expr_info * c,TOKEN t)869 __inline static	TOKEN	push_token (expr_info *c, TOKEN t)
870 {
871 	if (c->sp == STACKSZ - 1)
872 	{
873 		error("Expressions may not have more than %d operands",
874 			STACKSZ);
875 		return -1;
876 	}
877 	else
878 		c->sp++;
879 
880 	if (x_debug & DEBUG_NEW_MATH_DEBUG)
881 		yell("Pushing token [%d] [%s]", t, get_token_expanded(c, t));
882 
883 	return ((c->stack[c->sp] = t));
884 }
885 
push_string(expr_info * c,char * val)886 __inline static	TOKEN	push_string (expr_info *c, char *val)
887 {
888 	return push_token(c, tokenize_expanded(c, val));
889 }
890 
push_float(expr_info * c,double val)891 __inline static	TOKEN	push_float (expr_info *c, double val)
892 {
893 	return push_token(c, tokenize_float(c, val));
894 }
895 
push_integer(expr_info * c,INTTYPE val)896 __inline static	TOKEN	push_integer (expr_info *c, INTTYPE val)
897 {
898 	return push_token(c, tokenize_integer(c, val));
899 }
900 
push_boolean(expr_info * c,BooL val)901 __inline static TOKEN	push_boolean (expr_info *c, BooL val)
902 {
903 	return push_token(c, tokenize_bool(c, val));
904 }
905 
push_lval(expr_info * c,const char * val)906 __inline static TOKEN	push_lval (expr_info *c, const char *val)
907 {
908 	return push_token(c, tokenize_lval(c, val));
909 }
910 
911 
912 /*********************** REMOVE FROM OPERAND STACK **************************/
top(expr_info * c)913 __inline static TOKEN	top (expr_info *c)
914 {
915 	if (c->sp < 0)
916 	{
917 		error("No operands.");
918 		return -1;
919 	}
920 	else
921 		return c->stack[c->sp];
922 }
923 
pop_token(expr_info * c)924 __inline static	TOKEN	pop_token (expr_info *c)
925 {
926 	if (c->sp < 0)
927 	{
928 		/*
929 		 * Attempting to pop more operands than are available
930 		 * Yeilds empty values.  Thats probably the most reasonable
931 		 * course of action.
932 		 */
933 		error("Cannot pop operand: no more operands");
934 		return 0;
935 	}
936 	else
937 		return c->stack[c->sp--];
938 }
939 
pop_integer(expr_info * c)940 __inline static	double		pop_integer (expr_info *c)
941 {
942 	return get_token_integer(c, pop_token(c));
943 }
944 
pop_float(expr_info * c)945 __inline static	double		pop_float (expr_info *c)
946 {
947 	return get_token_float(c, pop_token(c));
948 }
949 
pop_expanded(expr_info * c)950 __inline static	const char *	pop_expanded (expr_info *c)
951 {
952 	return get_token_expanded(c, pop_token(c));
953 }
954 
pop_boolean(expr_info * c)955 __inline static	BooL		pop_boolean (expr_info *c)
956 {
957 	return get_token_boolean(c, pop_token(c));
958 }
959 
pop_2_tokens(expr_info * c,TOKEN * t1,TOKEN * t2)960 __inline static void	pop_2_tokens (expr_info *c, TOKEN *t1, TOKEN *t2)
961 {
962 	*t2 = pop_token(c);
963 	*t1 = pop_token(c);
964 }
965 
pop_2_floats(expr_info * c,double * a,double * b)966 __inline static	void	pop_2_floats (expr_info *c, double *a, double *b)
967 {
968 	*b = pop_float(c);
969 	*a = pop_float(c);
970 }
971 
pop_2_integers(expr_info * c,INTTYPE * a,INTTYPE * b)972 __inline static	void	pop_2_integers (expr_info *c, INTTYPE *a, INTTYPE *b)
973 {
974 	*b = pop_integer(c);
975 	*a = pop_integer(c);
976 }
977 
pop_2_strings(expr_info * c,const char ** s,const char ** t)978 __inline static void	pop_2_strings (expr_info *c, const char **s, const char **t)
979 {
980 	*t = pop_expanded(c);
981 	*s = pop_expanded(c);
982 }
983 
pop_2_booleans(expr_info * c,BooL * a,BooL * b)984 __inline static void	pop_2_booleans (expr_info *c, BooL *a, BooL *b)
985 {
986 	*b = pop_boolean(c);
987 	*a = pop_boolean(c);
988 }
989 
pop_3_tokens(expr_info * c,BooL * a,TOKEN * v,TOKEN * w)990 __inline static	void	pop_3_tokens (expr_info *c, BooL *a, TOKEN *v, TOKEN *w)
991 {
992 	TOKEN	t1, t2, t3;
993 
994 	t3 = pop_token(c);
995 	t2 = pop_token(c);
996 	t1 = pop_token(c);
997 	*a = get_token_boolean(c, t1);
998 	*v = t2;
999 	*w = t3;
1000 }
1001 
1002 
1003 /******************************* OPERATOR REDUCER **************************/
1004 /*
1005  * This is the reducer.  It takes the relevant arguments off the argument
1006  * stack and then performs the neccesary operation on them.
1007  */
reduce(expr_info * cx,int what)1008 static void	reduce (expr_info *cx, int what)
1009 {
1010 	double	a, b;
1011 	BooL	c, d;
1012 	INTTYPE	i, j;
1013 	const char *s, *t;
1014 	TOKEN	v, w;
1015 
1016 	if (x_debug & DEBUG_NEW_MATH_DEBUG)
1017 		yell("Reducing last operation...");
1018 
1019 	if (cx->sp < 0)
1020 	{
1021 		error("An operator is missing a required operand");
1022 		return;
1023 	}
1024 
1025 	if (cx->errflag)
1026 		return;		/* Dont parse on an error */
1027 
1028 /* Check to see if we are evaluating the expression at this point. */
1029 #define CHECK_NOEVAL							\
1030 	if (cx->noeval)							\
1031 	{								\
1032 		if (x_debug & DEBUG_NEW_MATH_DEBUG)			\
1033 			yell("O: Operation short-circuited");		\
1034 		push_token(cx, 0);					\
1035 		break;							\
1036 	}
1037 
1038 /* Perform an ordinary garden variety floating point binary operation. */
1039 #define BINARY_FLOAT(floatop)						\
1040 	{ 								\
1041 		pop_2_floats(cx, &a, &b); 				\
1042 		CHECK_NOEVAL						\
1043 		push_float(cx, (floatop));				\
1044 		if (x_debug & DEBUG_NEW_MATH_DEBUG) 			\
1045 			yell("O: %s (%f %f) -> %f", 			\
1046 				#floatop, a, b, floatop); 		\
1047 		break; 							\
1048 	}
1049 
1050 /* Perform an ordinary garden variety integer binary operation */
1051 #define BINARY_INTEGER(intop)						\
1052 	{ 								\
1053 		pop_2_integers(cx, &i, &j); 				\
1054 		CHECK_NOEVAL						\
1055 		push_integer(cx, (intop)); 				\
1056 		if (x_debug & DEBUG_NEW_MATH_DEBUG) 			\
1057 			yell("O: %s (" FORMAT " " FORMAT ") -> " FORMAT, \
1058 				#intop, i, j, intop); 			\
1059 		break; 							\
1060 	}
1061 
1062 /* Perform an ordinary garden variety boolean binary operation */
1063 #define BINARY_BOOLEAN(boolop) 						\
1064 	{ 								\
1065 		pop_2_booleans(cx, &c, &d); 				\
1066 		CHECK_NOEVAL						\
1067 		push_boolean(cx, (boolop)); 				\
1068 		if (x_debug & DEBUG_NEW_MATH_DEBUG) 			\
1069 			yell("O: %s (%d %d) -> %d", 			\
1070 				#boolop, c, d, boolop); 		\
1071 		break; 							\
1072 	}
1073 
1074 /* Perform a floating point binary operation where the rhs must not be 0. */
1075 #define BINARY_FLOAT_NOZERO(floatop)					\
1076 	{ 								\
1077 		pop_2_floats(cx, &a, &b); 				\
1078 		CHECK_NOEVAL						\
1079 		if (b == 0.0) 						\
1080 		{ 							\
1081 			if (x_debug & DEBUG_NEW_MATH_DEBUG) 		\
1082 				yell("O: %s (%f %f) -> []", 		\
1083 					#floatop, a, b); 		\
1084 			error("Division by zero"); 			\
1085 			push_token(cx, 0);				\
1086 		} 							\
1087 		else 							\
1088 		{ 							\
1089 			if (x_debug & DEBUG_NEW_MATH_DEBUG) 		\
1090 			    yell("O: %s (%f %f) -> %f", 		\
1091 					#floatop, a, b, floatop); 	\
1092 			push_float(cx, (floatop)); 			\
1093 		} 							\
1094 		break; 							\
1095 	}
1096 
1097 /* Perform a floating point binary operation where the rhs must not be 0. */
1098 #define BINARY_INTEGER_NOZERO(intop)					\
1099 	{ 								\
1100 		pop_2_integers(cx, &i, &j); 				\
1101 		CHECK_NOEVAL						\
1102 		if (j == 0) 						\
1103 		{ 							\
1104 			if (x_debug & DEBUG_NEW_MATH_DEBUG) 		\
1105 				yell("O: %s (" FORMAT " " FORMAT ") -> []", \
1106 					#intop, i, j); 			\
1107 			error("Division by zero"); 			\
1108 			push_token(cx, 0);				\
1109 		} 							\
1110 		else 							\
1111 		{ 							\
1112 			if (x_debug & DEBUG_NEW_MATH_DEBUG) 		\
1113 			    yell("O: %s (" FORMAT " " FORMAT ") -> " FORMAT, \
1114 					#intop, i, j, intop); 		\
1115 			push_integer(cx, (intop)); 			\
1116 		} 							\
1117 		break; 							\
1118 	}
1119 
1120 /***************** ASSIGNMENT MACROS *******************/
1121 /* Prep the lvalue and the rvalue for a future assignment. */
1122 #define	GET_LVAL_RVAL							\
1123 		pop_2_tokens(cx, &v, &w);				\
1124 		if (!(s = get_token_lval(cx, v)))			\
1125 		{							\
1126 			push_token(cx, 0);				\
1127 			break;						\
1128 		}
1129 
1130 /* Perform an ordinary integer operation, assigning the result to the lvalue */
1131 #define IMPLIED_INTEGER(intop) 						\
1132 	{ 								\
1133 		GET_LVAL_RVAL						\
1134 		CHECK_NOEVAL						\
1135 		i = get_token_integer(cx, v);				\
1136 		j = get_token_integer(cx, w);				\
1137 									\
1138 		if (x_debug & DEBUG_NEW_MATH_DEBUG) 			\
1139 			yell("O: %s = %s (" FORMAT " " FORMAT ") -> " FORMAT, \
1140 				s, #intop, i, j, intop); 		\
1141 									\
1142 		w = tokenize_integer(cx, (intop));			\
1143 		t = get_token_expanded(cx, w);				\
1144 		add_var_alias(s, t, 0);					\
1145 		push_token(cx, w);					\
1146 		break; 							\
1147 	}
1148 
1149 /* Perform an ordinary float operation, assigning the result to the lvalue */
1150 #define IMPLIED_FLOAT(floatop) 						\
1151 	{ 								\
1152 		GET_LVAL_RVAL						\
1153 		CHECK_NOEVAL						\
1154 		a = get_token_float(cx, v);				\
1155 		b = get_token_float(cx, w);				\
1156 									\
1157 		if (x_debug & DEBUG_NEW_MATH_DEBUG) 			\
1158 			yell("O: %s = %s (%f %f) -> %f",  		\
1159 				s, #floatop, a, b, floatop);		\
1160 									\
1161 		w = tokenize_float(cx, (floatop));			\
1162 		t = get_token_expanded(cx, w);				\
1163 		add_var_alias(s, t, 0);					\
1164 		push_token(cx, w);					\
1165 		break; 							\
1166 	}
1167 
1168 /* Perform an ordinary boolean operation, assigning the result to the lvalue */
1169 #define IMPLIED_BOOLEAN(boolop) 					\
1170 	{ 								\
1171 		GET_LVAL_RVAL						\
1172 		CHECK_NOEVAL						\
1173 		c = get_token_boolean(cx, v);				\
1174 		d = get_token_boolean(cx, w);				\
1175 									\
1176 		if (x_debug & DEBUG_NEW_MATH_DEBUG) 			\
1177 			yell("O: %s = %s (%d %d) -> %d",  		\
1178 				s, #boolop, c, d, boolop); 		\
1179 									\
1180 		w = tokenize_bool(cx, (boolop));			\
1181 		t = get_token_expanded(cx, w);				\
1182 		add_var_alias(s, t, 0);					\
1183 		push_token(cx, w);					\
1184 		break; 							\
1185 	}
1186 
1187 
1188 /*
1189  * Perform a float operation, rvalue must not be zero, assigning the result
1190  * to the lvalue.
1191  */
1192 #define IMPLIED_FLOAT_NOZERO(floatop) 					\
1193 	{ 								\
1194 		GET_LVAL_RVAL						\
1195 		CHECK_NOEVAL						\
1196 		a = get_token_float(cx, v);				\
1197 		b = get_token_float(cx, w);				\
1198 									\
1199 		if (b == 0.0) 						\
1200 		{ 							\
1201 			if (x_debug & DEBUG_NEW_MATH_DEBUG) 		\
1202 				yell("O: %s = %s (%f %f) -> 0",  	\
1203 					s, #floatop, a, b); 		\
1204 			error("Division by zero"); 			\
1205 			add_var_alias(s, empty_string, 0);		\
1206 			push_token(cx, 0);				\
1207 			break;						\
1208 		} 							\
1209 									\
1210 		if (x_debug & DEBUG_NEW_MATH_DEBUG) 			\
1211 			yell("O: %s =  %s (%f %f) -> %f",  		\
1212 				s, #floatop, a, b, floatop); 		\
1213 									\
1214 		w = tokenize_float(cx, (floatop));			\
1215 		t = get_token_expanded(cx, w);				\
1216 		add_var_alias(s, t, 0);					\
1217 		push_token(cx, w);					\
1218 		break; 							\
1219 	}
1220 
1221 /*
1222  * Perform a float operation, rvalue must not be zero, assigning the result
1223  * to the lvalue.
1224  */
1225 #define IMPLIED_INTEGER_NOZERO(intop) 					\
1226 	{ 								\
1227 		GET_LVAL_RVAL						\
1228 		CHECK_NOEVAL						\
1229 		i = get_token_float(cx, v);				\
1230 		j = get_token_float(cx, w);				\
1231 									\
1232 		if (j == 0) 						\
1233 		{ 							\
1234 			if (x_debug & DEBUG_NEW_MATH_DEBUG) 		\
1235 				yell("O: %s = %s (" FORMAT " " FORMAT ") -> 0",\
1236 					s, #intop, i, j); 		\
1237 			error("Division by zero"); 			\
1238 			add_var_alias(s, empty_string, 0);		\
1239 			push_token(cx, 0);				\
1240 			break;						\
1241 		} 							\
1242 									\
1243 		if (x_debug & DEBUG_NEW_MATH_DEBUG) 			\
1244 			yell("O: %s =  %s (" FORMAT " "  FORMAT ") -> " FORMAT,\
1245 				s, #intop, i, j, intop); 		\
1246 									\
1247 		w = tokenize_float(cx, (intop));			\
1248 		t = get_token_expanded(cx, w);				\
1249 		add_var_alias(s, t, 0);					\
1250 		push_token(cx, w);					\
1251 		break; 							\
1252 	}
1253 
1254 
1255 /*
1256  * Perform an auto(in|de)crement operation on the last operand, assigning
1257  * to it the value of 'x', but pushing the value of 'y' onto the stack.
1258  */
1259 #define AUTO_UNARY(intop_assign, intop_result) 				\
1260 	{ 								\
1261 		v = pop_token(cx); 					\
1262 		if (!(s = get_token_lval(cx, v)))			\
1263 		{							\
1264 			push_token(cx, 0);				\
1265 			break;						\
1266 		}							\
1267 		CHECK_NOEVAL						\
1268 									\
1269 		j = get_token_integer(cx, v);				\
1270 		if (x_debug & DEBUG_NEW_MATH_DEBUG) 			\
1271 			yell("O: %s (%s " FORMAT ") -> " FORMAT, 	\
1272 				#intop_result, s, j, (intop_result));	\
1273 									\
1274 		w = tokenize_integer(cx, (intop_assign));		\
1275 		t = get_token_expanded(cx, w);				\
1276 		add_var_alias(s, t, 0);					\
1277 									\
1278 		push_integer(cx, (intop_result));			\
1279 		break; 							\
1280 	}
1281 
1282 /* ****************** START HERE *********************/
1283 #define dpushn(x1,x2,y1) 						\
1284 	{ 								\
1285 		if (x_debug & DEBUG_NEW_MATH_DEBUG) 			\
1286 		{ 							\
1287 			yell("O: COMPARE"); 				\
1288 			yell("O: %s -> %d", #x2, (x2)); 		\
1289 		} 							\
1290 		push_boolean( x1 , y1 ); 				\
1291 	}
1292 
1293 #define COMPARE(x, y) 							\
1294 	{ 								\
1295 		pop_2_strings(cx, &s, &t);				\
1296 		CHECK_NOEVAL						\
1297 		if (is_real_number(s) && is_real_number(t))		\
1298 		{							\
1299 			a = atof(s), b = atof(t);			\
1300 			if (x_debug & DEBUG_NEW_MATH_DEBUG) 		\
1301 				yell("O: %s N(%f %f) -> %d", #x, a, b, (x)); \
1302 			if ((x))		dpushn(cx, x, 1) 	\
1303 			else			dpushn(cx, x, 0) 	\
1304 		} 							\
1305 		else 							\
1306 		{ 							\
1307 			if (x_debug & DEBUG_NEW_MATH_DEBUG) 		\
1308 				yell("O: %s S(%s %s) -> %d", #x, s, t, (y)); \
1309 			if ((y))		dpushn(cx, y, 1) 	\
1310 			else			dpushn(cx, y, 0) 	\
1311 		} 							\
1312 		break; 							\
1313 	}
1314 
1315 	/************** THE OPERATORS THEMSELVES ********************/
1316 	switch (what)
1317 	{
1318 		/* Simple unary prefix operators */
1319 		case NOT:
1320 			c = pop_boolean(cx);
1321 			CHECK_NOEVAL
1322 			if (x_debug & DEBUG_NEW_MATH_DEBUG)
1323 				yell("O: !%d -> %d", c, !c);
1324 			push_boolean(cx, !c);
1325 			break;
1326 		case COMP:
1327 			i = pop_integer(cx);
1328 			CHECK_NOEVAL
1329 			if (x_debug & DEBUG_NEW_MATH_DEBUG)
1330 				yell(": ~" FORMAT " -> " FORMAT, i, ~i);
1331 			push_integer(cx, ~i);
1332 			break;
1333 		case UPLUS:
1334 			a = pop_float(cx);
1335 			CHECK_NOEVAL
1336 			if (x_debug & DEBUG_NEW_MATH_DEBUG)
1337 				yell("O: +%f -> %f", a, a);
1338 			push_float(cx, a);
1339 			break;
1340 		case UMINUS:
1341 			a = pop_float(cx);
1342 			CHECK_NOEVAL
1343 			if (x_debug & DEBUG_NEW_MATH_DEBUG)
1344 				yell("O: -%f -> %f", a, -a);
1345 			push_float(cx, -a);
1346 			break;
1347 		case STRLEN:
1348 			s = pop_expanded(cx);
1349 			CHECK_NOEVAL
1350 			i = strlen(s);
1351 			if (x_debug & DEBUG_NEW_MATH_DEBUG)
1352 				yell("O: @(%s) -> " FORMAT, s, i);
1353 			push_integer(cx, i);
1354 			break;
1355 		case WORDC:
1356 			s = pop_expanded(cx);
1357 			CHECK_NOEVAL
1358 			i = count_words(s, DWORD_YES, "\"");
1359 			if (x_debug & DEBUG_NEW_MATH_DEBUG)
1360 				yell("O: #(%s) -> " FORMAT, s, i);
1361 			push_integer(cx, i);
1362 			break;
1363 		case DEREF:
1364 		{
1365 			if (top(cx) == MAGIC_TOKEN)
1366 				break;		/* Dont do anything */
1367 
1368 			/*
1369 			 * We need to consume the operand, even if
1370 			 * we don't intend to use it; plus we need
1371 			 * to ensure this defeats auto-append.  Ick.
1372 			 */
1373 			s = pop_expanded(cx);
1374 			*cx->args_flag = 1;
1375 
1376 			CHECK_NOEVAL
1377 			push_lval(cx, s);
1378 			break;
1379 		}
1380 
1381 		/* (pre|post)(in|de)crement operators. */
1382 		case PREPLUS:   AUTO_UNARY(j + 1, j + 1)
1383 		case PREMINUS:  AUTO_UNARY(j - 1, j - 1)
1384 		case POSTPLUS:	AUTO_UNARY(j + 1, j)
1385 		case POSTMINUS: AUTO_UNARY(j - 1, j)
1386 
1387 		/* Simple binary operators */
1388 		case AND:	BINARY_INTEGER(i & j)
1389 		case XOR:	BINARY_INTEGER(i ^ j)
1390 		case OR:	BINARY_INTEGER(i | j)
1391 		case PLUS:	BINARY_FLOAT(a + b)
1392 		case MINUS:	BINARY_FLOAT(a - b)
1393 		case MUL:	BINARY_FLOAT(a * b)
1394 		case POWER:	BINARY_FLOAT(pow(a, b))
1395 		case SHLEFT:	BINARY_INTEGER(i << j)
1396 		case SHRIGHT:	BINARY_INTEGER(i >> j)
1397 		case DIV:	BINARY_FLOAT_NOZERO(a / b)
1398 		case MOD:	BINARY_INTEGER_NOZERO(i % j)
1399 		case DAND:	BINARY_BOOLEAN(c && d)
1400 		case DOR:	BINARY_BOOLEAN(c || d)
1401 		case DXOR:	BINARY_BOOLEAN((c && !d) || (!c && d))
1402 		case STRCAT:
1403 		{
1404 			char *	myval;
1405 
1406 			pop_2_strings(cx, &s, &t);
1407 			CHECK_NOEVAL
1408 			if (x_debug & DEBUG_NEW_MATH_DEBUG)
1409 				yell("O: (%s) ## (%s) -> %s%s", s, t, s, t);
1410 
1411 			myval = malloc_strdup2(s, t);
1412 			push_string(cx, myval);
1413 			new_free(&myval);
1414 			break;
1415 		}
1416 		/* Assignment operators */
1417 		case PLUSEQ:	IMPLIED_FLOAT(a + b)
1418 		case MINUSEQ:	IMPLIED_FLOAT(a - b)
1419 		case MULEQ:	IMPLIED_FLOAT(a * b)
1420 		case POWEREQ:	IMPLIED_FLOAT(pow(a, b))
1421 		case DIVEQ:	IMPLIED_FLOAT_NOZERO(a / b)
1422 		case MODEQ:	IMPLIED_INTEGER_NOZERO(i % j)
1423 		case ANDEQ:	IMPLIED_INTEGER(i & j)
1424 		case XOREQ:	IMPLIED_INTEGER(i ^ j)
1425 		case OREQ:	IMPLIED_INTEGER(i | j)
1426 		case SHLEFTEQ:	IMPLIED_INTEGER(i << j)
1427 		case SHRIGHTEQ: IMPLIED_INTEGER(i >> j)
1428 		case DANDEQ:	IMPLIED_BOOLEAN(c && d)
1429 		case DOREQ:	IMPLIED_BOOLEAN(c || d)
1430 		case DXOREQ:	IMPLIED_BOOLEAN((c && !d) || (!c && d))
1431 		case STRCATEQ:
1432 		{
1433 			char *	myval;
1434 
1435 			GET_LVAL_RVAL
1436 			CHECK_NOEVAL
1437 			myval = malloc_strdup(get_token_expanded(cx, v));
1438 			t = get_token_expanded(cx, w);
1439 
1440 			if (x_debug & DEBUG_NEW_MATH_DEBUG)
1441 				yell("O: %s = (%s ## %s) -> %s%s",
1442 					s, myval, t, myval, t);
1443 
1444 			malloc_strcat(&myval, t);
1445 			push_string(cx, myval);
1446 			add_var_alias(s, myval, 0);
1447 			new_free(&myval);
1448 			break;
1449 		}
1450 		case STRPREEQ:
1451 		{
1452 			char *	myval;
1453 
1454 			GET_LVAL_RVAL
1455 			CHECK_NOEVAL
1456 			myval = malloc_strdup(get_token_expanded(cx, w));
1457 			t = get_token_expanded(cx, v);
1458 
1459 			if (x_debug & DEBUG_NEW_MATH_DEBUG)
1460 				yell("O: %s = (%s ## %s) -> %s%s",
1461 					s, t, myval, t, myval);
1462 
1463 			malloc_strcat(&myval, t);
1464 			push_string(cx, myval);
1465 			add_var_alias(s, myval, 0);
1466 			new_free(&myval);
1467 			break;
1468 		}
1469 		case EQ:
1470 		{
1471 			GET_LVAL_RVAL
1472 			CHECK_NOEVAL
1473 			t = get_token_expanded(cx, w);
1474 
1475 			if (x_debug & DEBUG_NEW_MATH_DEBUG)
1476 				yell("O: %s = (%s)", s, t);
1477 
1478 			push_token(cx, w);
1479 			add_var_alias(s, t, 0);
1480 			break;
1481 		}
1482 		case SWAP:
1483 		{
1484 			const char *sval, *tval;
1485 
1486 			pop_2_tokens(cx, &v, &w);
1487 			CHECK_NOEVAL
1488 			if (!(s = get_token_lval(cx, v)))
1489 			{
1490 				push_token(cx, 0);
1491 				break;
1492 			}
1493 			if (!(t = get_token_lval(cx, w)))
1494 			{
1495 				push_token(cx, 0);
1496 				break;
1497 			}
1498 			sval = get_token_expanded(cx, v);
1499 			tval = get_token_expanded(cx, w);
1500 
1501 			if (x_debug & DEBUG_NEW_MATH_DEBUG)
1502 				yell("O: %s <=> %s", s, t);
1503 
1504 			add_var_alias(s, tval, 0);
1505 			add_var_alias(t, sval, 0);
1506 			push_token(cx, w);
1507 			break;
1508 		}
1509 
1510 		/* Comparison operators */
1511 		case DEQ:
1512 		{
1513 			pop_2_strings(cx, &s, &t);
1514 			CHECK_NOEVAL
1515 			c = my_stricmp(s, t) ? 0 : 1;
1516 
1517 			if (x_debug & DEBUG_NEW_MATH_DEBUG)
1518 				yell("O: %s == %s -> %d", s, t, c);
1519 
1520 			push_boolean(cx, c);
1521 			break;
1522 		}
1523 		case NEQ:
1524 		{
1525 			pop_2_strings(cx, &s, &t);
1526 			CHECK_NOEVAL
1527 			c = my_stricmp(s, t) ? 1 : 0;
1528 
1529 			if (x_debug & DEBUG_NEW_MATH_DEBUG)
1530 				yell("O: %s != %s -> %d", s, t, c);
1531 
1532 			push_boolean(cx, c);
1533 			break;
1534 		}
1535 		case MATCH:
1536 		{
1537 			pop_2_strings(cx, &s, &t);
1538 			CHECK_NOEVAL
1539 			c = wild_match(t, s) ? 1 : 0;
1540 
1541 			if (x_debug & DEBUG_NEW_MATH_DEBUG)
1542 				yell("O: %s =~ %s -> %d", s, t, c);
1543 
1544 			push_boolean(cx, c);
1545 			break;
1546 		}
1547 		case NOMATCH:
1548 		{
1549 			pop_2_strings(cx, &s, &t);
1550 			CHECK_NOEVAL
1551 			c = wild_match(t, s) ? 0 : 1;
1552 
1553 			if (x_debug & DEBUG_NEW_MATH_DEBUG)
1554 				yell("O: %s !~ %s -> %d", s, t, c);
1555 
1556 			push_boolean(cx, c);
1557 			break;
1558 		}
1559 
1560 		case LES:	COMPARE(a < b,  my_stricmp(s, t) < 0)
1561 		case LEQ:	COMPARE(a <= b, my_stricmp(s, t) <= 0)
1562 		case GRE:	COMPARE(a > b,  my_stricmp(s, t) > 0)
1563 		case GEQ:	COMPARE(a >= b, my_stricmp(s, t) >= 0)
1564 
1565 		/* Miscelaneous operators */
1566 		case QUEST:
1567 		{
1568 			pop_3_tokens(cx, &c, &v, &w);
1569 			CHECK_NOEVAL
1570 			if (x_debug & DEBUG_NEW_MATH_DEBUG)
1571 			{
1572 				yell("O: %d ? %s : %s -> %s", c,
1573 					get_token_expanded(cx, v),
1574 					get_token_expanded(cx, w),
1575 					(c ? get_token_expanded(cx, v) :
1576 					     get_token_expanded(cx, w)));
1577 			}
1578 			push_token(cx, c ? v : w);
1579 			break;
1580 		}
1581 		case COLON:
1582 			break;
1583 
1584 		case COMMA:
1585 		{
1586 			pop_2_tokens(cx, &v, &w);
1587 			CHECK_NOEVAL
1588 
1589 			if (x_debug & DEBUG_NEW_MATH_DEBUG)
1590 				yell("O: %s , %s -> %s",
1591 					get_token_expanded(cx, v),
1592 					get_token_expanded(cx, w),
1593 					get_token_expanded(cx, w));
1594 			push_token(cx, w);
1595 			break;
1596 		}
1597 
1598 		default:
1599 			error("Unknown operator or out of operators");
1600 			return;
1601 	}
1602 }
1603 
1604 
1605 /**************************** EXPRESSION LEXER ******************************/
1606 static	int	dummy = 1;
1607 
lexerr(expr_info * c,const char * format,...)1608 static int	lexerr (expr_info *c, const char *format, ...)
1609 {
1610 	char 	buffer[BIG_BUFFER_SIZE + 1];
1611 	va_list	a;
1612 
1613 	va_start(a, format);
1614 	vsnprintf(buffer, BIG_BUFFER_SIZE, format, a);
1615 	va_end(a);
1616 
1617 	error("%s", buffer);
1618 	c->errflag = 1;
1619 	return EOI;
1620 }
1621 
1622 /*
1623  * 'operand' is state information that tells us about what the next token
1624  * is expected to be.  When a binary operator is lexed, then the next token
1625  * is expected to be either a unary operator or an operand.  So in this
1626  * case 'operand' is set to 1.  When an operand is lexed, then the next token
1627  * is expected to be a binary operator, so 'operand' is set to 0.
1628  */
check_implied_arg(expr_info * c)1629 static __inline int	check_implied_arg (expr_info *c)
1630 {
1631 	if (c->operand == 2)
1632 	{
1633 		push_token(c, MAGIC_TOKEN);	/* XXXX Bleh */
1634 		c->operand = 0;
1635 		*c->args_flag = 1;
1636 		return 0;
1637 	}
1638 
1639 	return c->operand;
1640 }
1641 
operator(expr_info * c,const char * x,int y,TOKEN z)1642 static __inline TOKEN 	operator (expr_info *c, const char *x, int y, TOKEN z)
1643 {
1644 	check_implied_arg(c);
1645 	if (c->operand)
1646 		return lexerr(c, "A binary operator (%s) was found "
1647 				 "where an operand was expected", x);
1648 	c->ptr += y;
1649 	c->operand = 1;
1650 	return z;
1651 }
1652 
unary(expr_info * c,const char * x,int y,TOKEN z)1653 static __inline TOKEN 	unary (expr_info *c, const char *x, int y, TOKEN z)
1654 {
1655 	if (!c->operand)
1656 		return lexerr(c, "A unary operator (%s) was found where "
1657 				 "a binary operator was expected", x);
1658 	c->ptr += y;
1659 	c->operand = dummy;
1660 	return z;
1661 }
1662 
1663 
1664 /*
1665  * This finds and extracts the next token in the expression
1666  */
zzlex(expr_info * c)1667 static int	zzlex (expr_info *c)
1668 {
1669 	char	*start = c->ptr;
1670 
1671 #define OPERATOR(x, y, z) return operator(c, x, y, z);
1672 #define UNARY(x, y, z) return unary(c, x, y, z);
1673 
1674 	dummy = 1;
1675 	if (x_debug & DEBUG_NEW_MATH_DEBUG)
1676 		yell("Parsing next token from: [%s]", c->ptr);
1677 
1678 	for (;;)
1679 	{
1680 	    switch (*(c->ptr++))
1681 	    {
1682 		case '(':
1683 			c->operand = 1;
1684 			return M_INPAR;
1685 		case ')':
1686 			/*
1687 			 * If we get a close paren and the lexer is expecting
1688 			 * an operand, then obviously thats a syntax error.
1689 			 * But we gently just insert the empty value as the
1690 			 * rhs for the last operand and hope it all works out.
1691 			 */
1692 			if (check_implied_arg(c))
1693 				push_token(c, 0);
1694 			c->operand = 0;
1695 			return M_OUTPAR;
1696 
1697 		case '+':
1698 		{
1699 			/*
1700 			 * Note:  In general, any operand that depends on
1701 			 * whether it is a unary or binary operator based
1702 			 * upon the context is required to call the func
1703 			 * 'check_implied_arg' to solidify the context.
1704 			 * That is because some operators are ambiguous,
1705 			 * And if you see   (# + 4), it can only be determined
1706 			 * on the fly how to lex that.
1707 			 */
1708 			check_implied_arg(c);
1709 			if (*c->ptr == '+' && (c->operand || !isalnum(*c->ptr)))
1710 			{
1711 				c->ptr++;
1712 				return c->operand ? PREPLUS : POSTPLUS;
1713 			}
1714 			else if (*c->ptr == '=')
1715 				OPERATOR("+=", 1, PLUSEQ)
1716 			else if (c->operand)
1717 				UNARY("+", 0, UPLUS)
1718 			else
1719 				OPERATOR("+", 0, PLUS)
1720 		}
1721 		case '-':
1722 		{
1723 			check_implied_arg(c);
1724 			if (*c->ptr == '-' && (c->operand || !isalnum(*c->ptr)))
1725 			{
1726 				c->ptr++;
1727 				return (c->operand) ? PREMINUS : POSTMINUS;
1728 			}
1729 			else if (*c->ptr == '=')
1730 				OPERATOR("-=", 1, MINUSEQ)
1731 			else if (c->operand)
1732 				UNARY("-", 0, UMINUS)
1733 			else
1734 				OPERATOR("-", 0, MINUS)
1735 		}
1736 		case '*':
1737 		{
1738 			if (*c->ptr == '*')
1739 			{
1740 				c->ptr++;
1741 				if (*c->ptr == '=')
1742 					OPERATOR("**=", 1, POWEREQ)
1743 				else
1744 					OPERATOR("**", 0, POWER)
1745 			}
1746 			else if (*c->ptr == '=')
1747 				OPERATOR("*=", 1, MULEQ)
1748 			else if (c->operand)
1749 			{
1750 				dummy = 2;
1751 				UNARY("*", 0, DEREF)
1752 			}
1753 			else
1754 				OPERATOR("*", 0, MUL)
1755 		}
1756 		case '/':
1757 		{
1758 			if (*c->ptr == '=')
1759 				OPERATOR("/=", 1, DIVEQ)
1760 			else
1761 				OPERATOR("/", 0, DIV)
1762 		}
1763 		case '%':
1764 		{
1765 			if (*c->ptr == '=')
1766 				OPERATOR("%=", 1, MODEQ)
1767 			else
1768 				OPERATOR("%", 0, MOD)
1769 		}
1770 
1771 		case '!':
1772 		{
1773 			if (*c->ptr == '=')
1774 				OPERATOR("!=", 1, NEQ)
1775 			else if (*c->ptr == '~')
1776 				OPERATOR("!~", 1, NOMATCH)
1777 			else
1778 				UNARY("!", 0, NOT)
1779 		}
1780 		case '~':
1781 			UNARY("~", 0, COMP)
1782 
1783 		case '&':
1784 		{
1785 			if (*c->ptr == '&')
1786 			{
1787 				c->ptr++;
1788 				if (*c->ptr == '=')
1789 					OPERATOR("&&=", 1, DANDEQ)
1790 				else
1791 					OPERATOR("&&", 0, DAND)
1792 			}
1793 			else if (*c->ptr == '=')
1794 				OPERATOR("&=", 1, ANDEQ)
1795 			else
1796 				OPERATOR("&", 0, AND)
1797 		}
1798 		case '|':
1799 		{
1800 			if (*c->ptr == '|')
1801 			{
1802 				c->ptr++;
1803 				if (*c->ptr == '=')
1804 					OPERATOR("||=", 1, DOREQ)
1805 				else
1806 					OPERATOR("||", 0, DOR)
1807 			}
1808 			else if (*c->ptr == '=')
1809 				OPERATOR("|=", 1, OREQ)
1810 			else
1811 				OPERATOR("|", 0, OR)
1812 		}
1813 		case '^':
1814 		{
1815 			if (*c->ptr == '^')
1816 			{
1817 				c->ptr++;
1818 				if (*c->ptr == '=')
1819 					OPERATOR("^^=", 1, DXOREQ)
1820 				else
1821 					OPERATOR("^^", 0, DXOR)
1822 			}
1823 			else if (*c->ptr == '=')
1824 				OPERATOR("^=", 1, XOREQ)
1825 			else
1826 				OPERATOR("^", 0, XOR)
1827 		}
1828 		case '#':
1829 		{
1830 			check_implied_arg(c);
1831 			if (*c->ptr == '#')
1832 			{
1833 				c->ptr++;
1834 				if (*c->ptr == '=')
1835 					OPERATOR("##=", 1, STRCATEQ)
1836 				else
1837 					OPERATOR("##", 0, STRCAT)
1838 			}
1839 			else if (*c->ptr == '=')
1840 				OPERATOR("#=", 1, STRCATEQ)
1841 			else if (*c->ptr == '~')
1842 				OPERATOR("#~", 1, STRPREEQ)
1843 			else if (c->operand)
1844 			{
1845 				dummy = 2;
1846 				UNARY("#", 0, WORDC)
1847 			}
1848 			else
1849 				OPERATOR("#", 0, STRCAT)
1850 		}
1851 
1852 		case '@':
1853 			dummy = 2;
1854 			UNARY("@", 0, STRLEN)
1855 
1856 		case '<':
1857 		{
1858 			if (*c->ptr == '<')
1859 			{
1860 				c->ptr++;
1861 				if (*c->ptr == '=')
1862 					OPERATOR("<<=", 1, SHLEFTEQ)
1863 				else
1864 					OPERATOR("<<", 0, SHLEFT)
1865 			}
1866 			else if (*c->ptr == '=')
1867 			{
1868 				c->ptr++;
1869 				if (*c->ptr == '>')
1870 					OPERATOR("<=>", 1, SWAP)
1871 				else
1872 					OPERATOR("<=", 0, LEQ)
1873 			}
1874 			else
1875 				OPERATOR("<", 0, LES)
1876 		}
1877 		case '>':
1878 		{
1879 			if (*c->ptr == '>')
1880 			{
1881 				c->ptr++;
1882 				if (*c->ptr == '=')
1883 					OPERATOR(">>=", 1, SHRIGHTEQ)
1884 				else
1885 					OPERATOR(">>", 0, SHRIGHT)
1886 			}
1887 			else if (*c->ptr == '=')
1888 				OPERATOR(">=", 1, GEQ)
1889 			else
1890 				OPERATOR(">", 0, GRE)
1891 		}
1892 
1893 		case '=':
1894 			if (*c->ptr == '=')
1895 				OPERATOR("==", 1, DEQ)
1896 			else if (*c->ptr == '~')
1897 				OPERATOR("=~", 1, MATCH)
1898 			else
1899 				OPERATOR("=", 0, EQ)
1900 
1901 		case '?':
1902 			check_implied_arg(c);
1903 			c->operand = 1;
1904 			return QUEST;
1905 
1906 		case ':':
1907 			/*
1908 			 * I dont want to hear anything from you anti-goto
1909 			 * bigots out there. ;-)  If you can't figure out
1910 			 * what this does, you ought to give up programming.
1911 			 * And a big old :p to everyone who insisted that
1912 			 * i support this horrid hack.
1913 			 */
1914 			if (c->operand)
1915 				goto handle_expando;
1916 
1917 			c->operand = 1;
1918 			return COLON;
1919 
1920 		case ',':
1921 			/* Same song, second verse. */
1922 			if (c->operand)
1923 				goto handle_expando;
1924 
1925 			c->operand = 1;
1926 			return COMMA;
1927 
1928 		case '\0':
1929 			check_implied_arg(c);
1930 			c->operand = 1;
1931 			c->ptr--;
1932 			return EOI;
1933 
1934 		/*
1935 		 * The {...} operator is really a hack that is left over
1936 		 * from the old math parser.  The support for it here is
1937 		 * a hack.  The entire thing is a hack.
1938 		 */
1939 		case '{':
1940 		{
1941 			char *p = c->ptr;
1942 			char oc = 0;
1943 			ssize_t	span;
1944 
1945 			if (!c->operand)
1946 				return lexerr(c, "Misplaced { token");
1947 
1948 			if ((span = MatchingBracket(p, '{', '}')) >= 0)
1949 			{
1950 				c->ptr = p + span;
1951 				oc = *c->ptr;
1952 				*c->ptr = 0;
1953 			}
1954 			else
1955 				c->ptr = empty_string;
1956 
1957 			c->last_token = 0;
1958 			if (!c->noeval)
1959 			{
1960 				char *	result;
1961 
1962 				result = call_lambda_function(NULL, p, c->args);
1963 				c->last_token = tokenize_expanded(c, result);
1964 				new_free(&result);
1965 			}
1966 
1967 			if (oc)
1968 				*c->ptr++ = oc;
1969 			c->operand = 0;
1970 			return ID;
1971 		}
1972 
1973 		/******************** OPERAND TYPES **********************/
1974 		/*
1975 		 * This is an UNEXPANDED-STRING operand type.
1976 		 * Extract everything inside the [...]'s, and then
1977 		 * tokenize that as a "raw" token.  It will be expanded
1978 		 * on an as-needed basis.
1979 		 *
1980 		 * If we are in the no-eval section of a short-circuit,
1981 		 * then we throw away this token entirely.
1982 		 */
1983 		case '[':
1984 		{
1985 			char *p = c->ptr;
1986 			char oc = 0;
1987 			ssize_t	span;
1988 
1989 			if (!c->operand)
1990 				return lexerr(c, "Misplaced [ token");
1991 
1992 			if ((span = MatchingBracket(p, '[', ']')) >= 0)
1993 			{
1994 				c->ptr = p + span;
1995 				oc = *c->ptr;
1996 				*c->ptr = 0;
1997 			}
1998 			else
1999 				c->ptr = empty_string;
2000 
2001 			if (c->noeval)
2002 				c->last_token = 0;
2003 			else
2004 				c->last_token = tokenize_raw(c, p);
2005 
2006 			if (oc)
2007 				*c->ptr++ = oc;
2008 			c->operand = 0;
2009 			return ID;
2010 		}
2011 
2012 		/* The "space" characters. */
2013 		case 9: case 10: case 11: case 12: case 13: case ' ':
2014 			start++;
2015 			break;
2016 
2017 		/*
2018 		 * This is a NUMBER operand type.  This may seem unusual,
2019 		 * but we actually tokenize the string representation of
2020 		 * the number as an "expanded" token type.  Why do we do
2021 		 * this?  Because in the most common case, the user is
2022 		 * doing something like:
2023 		 *
2024 		 *		@ var = 0
2025 		 *
2026 		 * Now we already have the "0" in string format (natch),
2027 		 * and we will never actually reference the 0 as a number
2028 		 * per se -- all assignments are done on strings, so we
2029 		 * need the string anyhow.  So when we lex a number in the
2030 		 * expression, we tokenize it as an 'expanded string' and
2031 		 * then if we ever have to actually use the number in any
2032 		 * particular context, it will be converted as-needed.
2033 		 */
2034 		case '0': case '1': case '2': case '3': case '4':
2035 		case '5': case '6': case '7': case '8': case '9':
2036 		{
2037 			char 	*end;
2038 			char 	endc;
2039 
2040 			c->operand = 0;
2041 			c->ptr--;
2042 			strtod(c->ptr, &end);
2043 			endc = *end;
2044 			*end = 0;
2045 
2046 			if (c->noeval)
2047 				c->last_token = 0;
2048 			else
2049 				c->last_token = tokenize_expanded(c, c->ptr);
2050 
2051 			*end = endc;
2052 			c->ptr = end;
2053 			return ID;
2054 		}
2055 
2056 		/*
2057 		 * Handle those weirdo $-values
2058 		 */
2059 		case '$':
2060 			continue;
2061 
2062 		/*
2063 		 * This is an LVAL operand type.  This also may seem
2064 		 * unusual, but lval's may contain $'s, which need to
2065 		 * be expanded.  They may contain function calls, which
2066 		 * must only be expanded *once*.  When we lex out an lval
2067 		 * (such as "var" in "@ var = 5"), we tokenize the lval
2068 		 * as an unexpanded lval.  Then, if we ever actually need
2069 		 * to reference the proper variable name, we will get the
2070 		 * "raw" value, which will be the lval after passed through
2071 		 * expand_alias().  If we want to get the *value of the
2072 		 * variable $lval), then we will get the "expanded" value,
2073 		 * which will use the "raw" value to do the variable name
2074 		 * lookup.  See?  It's really pretty straightforward.  The
2075 		 * reason we do all this is to make sure that the expansion
2076 		 * of the variable name happens *at most once*, and that if
2077 		 * the variable is not actually referenced, then the expansion
2078 		 * isn't done at all.
2079 		 */
2080 		default:
2081 handle_expando:
2082 		{
2083 			char 	*end;
2084 			char	endc;
2085 
2086 			c->operand = 0;
2087 			c->ptr--;
2088 			if ((end = after_expando_special(c)))
2089 			{
2090 				endc = *end;
2091 				*end = 0;
2092 
2093 				/*
2094 				 * If we are in the short-circuit of a noeval,
2095 				 * then we throw the token away.
2096 				 */
2097 				if (c->noeval)
2098 					c->last_token = 0;
2099 				else
2100 					c->last_token = tokenize_lval(c, start);
2101 
2102 				*end = endc;
2103 				c->ptr = end;
2104 			}
2105 			else
2106 			{
2107 				c->last_token = 0; /* Empty token */
2108 				c->ptr = empty_string;
2109 			}
2110 
2111 			if (x_debug & DEBUG_NEW_MATH_DEBUG)
2112 				yell("After token: [%s]", c->ptr);
2113 			return ID;
2114 		}
2115 	    }
2116 	}
2117 }
2118 
2119 /******************************* STATE MACHINE *****************************/
2120 /*
2121  * mathparse -- this is the state machine that actually parses the
2122  * expression.   The parsing is done through a shift-reduce mechanism,
2123  * and all the precedence levels lower than 'pc' are evaluated.
2124  */
mathparse(expr_info * c,int pc)2125 static void	mathparse (expr_info *c, int pc)
2126 {
2127 	int	otok,
2128 		onoeval;
2129 
2130 	/*
2131 	 * Drop out of parsing if an error has occured
2132 	 */
2133 	if (c->errflag)
2134 		return;
2135 
2136 	/*
2137 	 * Get the next token in the expression
2138 	 */
2139 	c->mtok = zzlex(c);
2140 
2141 	/*
2142 	 * For as long as the next operator indicates a shift operation...
2143 	 */
2144 	while (prec[c->mtok] <= pc)
2145 	{
2146 	    /* Drop out if an error has occured */
2147 	    if (c->errflag)
2148 		return;
2149 
2150 	    /*
2151 	     * Figure out what to do with this token that needs
2152 	     * to be shifted.
2153 	     */
2154 	    switch (c->mtok)
2155 	    {
2156 		/*
2157 		 * This is any kind of an indentifier.  There are several
2158 		 * that we handle:
2159 		 *
2160 		 *	VARIABLE REFERENCE	ie, "foo"   in "@ foo = 2"
2161 		 *	NUMBER			ie, "2"     in "@ foo = 2"
2162 		 *	UNEXPANDED STRING	ie, "[boo]" in "@ foo = [boo]"
2163 		 *
2164 		 * The actual determination of which type is done in the lexer.
2165 		 * We just get a token id for the resulting identifier.
2166 		 * Getting the value is done on an as-needed basis.
2167 		 */
2168 		case ID:
2169 			if (x_debug & DEBUG_NEW_MATH_DEBUG)
2170 				yell("Parsed identifier token [%s]",
2171 					get_token_expanded(c, c->last_token));
2172 
2173 			/*
2174 			 * The lexer sets the last token to
2175 			 * 0 if noeval is set.  This saves us
2176 			 * from having to tokenize a string
2177 			 * that we expressly will not use.
2178 			 */
2179 			push_token(c, c->last_token);
2180 			break;
2181 
2182 		/*
2183 		 * An open-parenthesis indicates that we should
2184 		 * recursively evaluate the inside of the paren-set.
2185 		 */
2186 		case M_INPAR:
2187 		{
2188 			if (x_debug & DEBUG_NEW_MATH_DEBUG)
2189 				yell("Parsed open paren");
2190 			mathparse(c, TOPPREC);
2191 
2192 			/*
2193 			 * Of course if the expression ends without
2194 			 * a matching rparen, then we whine about it.
2195 			 */
2196 			if (c->mtok != M_OUTPAR)
2197 			{
2198 				if (!c->errflag)
2199 				    error("')' expected");
2200 				return;
2201 			}
2202 			break;
2203 		}
2204 
2205 		/*
2206 		 * A question mark requires that we check for short
2207 		 * circuiting.  We check the lhs, and if it is true,
2208 		 * then we evaluate the lhs of the colon.  If it is
2209 		 * false then we just parse the lhs of the colon and
2210 		 * evaluate the rhs of the colon.
2211 		 */
2212 		case QUEST:
2213 		{
2214 			BooL u = pop_boolean(c);
2215 
2216 			push_boolean(c, u);
2217 			if (!u)
2218 				c->noeval++;
2219 			mathparse(c, prec[QUEST] - 1);
2220 			if (!u)
2221 				c->noeval--;
2222 			else
2223 				c->noeval++;
2224 			mathparse(c, prec[QUEST]);
2225 			if (u)
2226 				c->noeval--;
2227 			reduce(c, QUEST);
2228 
2229 			continue;
2230 		}
2231 
2232 		/*
2233 		 * All other operators handle normally
2234 		 */
2235 		default:
2236 		{
2237 			/* Save state */
2238 			otok = c->mtok;
2239 			onoeval = c->noeval;
2240 
2241 			/*
2242 			 * Check for short circuiting.
2243 			 */
2244 			if (assoc[otok] == BOOL)
2245 			{
2246 			    if (x_debug & DEBUG_NEW_MATH_DEBUG)
2247 				yell("Parsed short circuit operator");
2248 
2249 			    switch (otok)
2250 			    {
2251 				case DAND:
2252 				case DANDEQ:
2253 				{
2254 					BooL u = pop_boolean(c);
2255 					push_boolean(c, u);
2256 					if (!u)
2257 						c->noeval++;
2258 					break;
2259 				}
2260 				case DOR:
2261 				case DOREQ:
2262 				{
2263 					BooL u = pop_boolean(c);
2264 					push_boolean(c, u);
2265 					if (u)
2266 						c->noeval++;
2267 					break;
2268 				}
2269 			    }
2270 			}
2271 
2272 		 	if (x_debug & DEBUG_NEW_MATH_DEBUG)
2273 			    yell("Parsed operator of type [%d]", otok);
2274 
2275 			/*
2276 			 * Parse the right hand side through
2277 			 * recursion if we're doing things R->L.
2278 			 */
2279 			mathparse(c, prec[otok] - (assoc[otok] != RL));
2280 
2281 			/*
2282 			 * Then reduce this operation.
2283 			 */
2284 			c->noeval = onoeval;
2285 			reduce(c, otok);
2286 			continue;
2287 		}
2288 	    }
2289 
2290 	    /*
2291 	     * Grab the next token
2292 	     */
2293 	    c->mtok = zzlex(c);
2294 	}
2295 }
2296 
2297 /******************************** HARNASS **********************************/
2298 /*
2299  * This is the new math parser.  It sets up an execution context, which
2300  * contains sundry information like all the extracted tokens, intermediate
2301  * tokens, shifted tokens, and the like.  The expression context is passed
2302  * around from function to function, each function is totaly independant
2303  * of state information stored in global variables.  Therefore, this math
2304  * parser is re-entrant safe.
2305  */
matheval(char * s,const char * args,int * args_flag)2306 static char *	matheval (char *s, const char *args, int *args_flag)
2307 {
2308 	expr_info	context;
2309 	char *		ret = NULL;
2310 
2311 	/* Sanity check */
2312 	if (!s || !*s)
2313 		return malloc_strdup(empty_string);
2314 
2315 	/* Create new state */
2316 	setup_expr_info(&context);
2317 	context.ptr = s;
2318 	context.args = args;
2319 	context.args_flag = args_flag;
2320 
2321 	/* Actually do the parsing */
2322 	mathparse(&context, TOPPREC);
2323 
2324 	/* Check for error */
2325 	if (context.errflag)
2326 	{
2327 		ret = malloc_strdup(empty_string);
2328 		goto cleanup;
2329 	}
2330 
2331 	/* Check for leftover operands */
2332 	if (context.sp)
2333 		error("The expression has too many operands");
2334 
2335 	if (x_debug & DEBUG_NEW_MATH_DEBUG)
2336 	{
2337 		int i;
2338 		yell("Terms left: %d", context.sp);
2339 		for (i = 0; i <= context.sp; i++)
2340 			yell("Term [%d]: [%s]", i,
2341 				get_token_expanded(&context, context.stack[i]));
2342 	}
2343 
2344 	/* Get the return value, if requested */
2345 	ret = malloc_strdup(get_token_expanded(&context, pop_token(&context)));
2346 
2347 cleanup:
2348 	/* Clean up and restore order */
2349 	destroy_expr_info(&context);
2350 
2351 	if (x_debug & DEBUG_NEW_MATH_DEBUG)
2352 		yell("Returning [%s]", ret);
2353 
2354 	/* Return the result */
2355 	return ret;
2356 }
2357 
2358 
2359 /******************************* SUPPORT *************************************/
2360 /*
2361  * after_expando_special: This is a special version of after_expando that
2362  * can handle parsing out lvalues in expressions.  Due to the eclectic nature
2363  * of lvalues in expressions, this is quite a bit different than the normal
2364  * after_expando, requiring a different function. Ugh.
2365  *
2366  * This replaces some much more complicated logic strewn
2367  * here and there that attempted to figure out just how long an expando
2368  * name was supposed to be.  Well, now this changes that.  This will slurp
2369  * up everything in 'start' that could possibly be put after a $ that could
2370  * result in a syntactically valid expando.  All you need to do is tell it
2371  * if the expando is an rvalue or an lvalue (it *does* make a difference)
2372  */
after_expando_special(expr_info * c)2373 static  char *	after_expando_special (expr_info *c)
2374 {
2375 	char	*start;
2376 	char	*rest;
2377 	int	call;
2378 
2379 	if (!(start = c->ptr))
2380 		return c->ptr;
2381 
2382 	for (;;)
2383 	{
2384 		rest = after_expando(start, 0, &call);
2385 		if (*rest != '$')
2386 			break;
2387 		start = rest + 1;
2388 	}
2389 
2390 	if (c->ptr == rest)
2391 	{
2392 		yell("Erf.  I'm trying to find an lval at [%s] and I'm not "
2393 			"having much luck finding one.  Punting the rest of "
2394 			"this expression", c->ptr);
2395 		return NULL;
2396 	}
2397 
2398 	/*
2399 	 * All done!
2400 	 */
2401 	return rest;
2402 }
2403 
2404