Subversion Repositories DevTools

Rev

Details | Last modification | View Log | RSS feed

Rev Author Line No. Line
227 dpurdie 1
/*
2
 * MS-DOS SHELL - Maths Evaluation Functions
3
 *
4
 * MS-DOS SHELL - Copyright (c) 1990,4 Data Logic Limited and Paul Falstad
5
 *
6
 * This code is based on (in part) the shell program written by Paul Falstad
7
 * and is subject to the following copyright restrictions:
8
 *
9
 * 1.  Redistribution and use in source and binary forms are permitted
10
 *     provided that the above copyright notice is duplicated in the
11
 *     source form and the copyright notice in file sh6.c is displayed
12
 *     on entry to the program.
13
 *
14
 * 2.  The sources (or parts thereof) or objects generated from the sources
15
 *     (or parts of sources) cannot be sold under any circumstances.
16
 *
17
 * This source is based on the math.c (mathematical expression evaluation) from
18
 * the Z shell.  Z Shell is free software, under the GNU license.  This
19
 * code is included in this program under the provisions of paragraph 8 of
20
 * GNU GENERAL PUBLIC LICENSE, Version 1, February 1989.  I contacted Paul
21
 * via E-Mail, and he is happy to allow the source to be included in this
22
 * program.
23
 *
24
 *    $Header: /cvsroot/device/DEVL/UTILS/SH/SH11.C,v 1.1 2002/08/02 06:49:32 adamy Exp $
25
 *
26
 *    $Log: SH11.C,v $
27
 *    Revision 1.1  2002/08/02 06:49:32  adamy
28
 *    imported (reference only)
29
 *
30
 *    Revision 1.1  2001/07/20 05:55:42  ayoung
31
 *    WIN32 support
32
 *
33
 *    Revision 1.1.1.1  1999/12/02 01:11:12  gordonh
34
 *    UTIL
35
 *
36
 *	Revision 2.10  1994/08/25  20:49:11  istewart
37
 *	MS Shell 2.3 Release
38
 *
39
 *	Revision 2.9  1994/02/01  10:25:20  istewart
40
 *	Release 2.3 Beta 2, including first NT port
41
 *
42
 *	Revision 2.8  1993/11/09  10:39:49  istewart
43
 *	Beta 226 checking
44
 *
45
 *	Revision 2.7  1993/07/02  10:21:35  istewart
46
 *	224 Beta fixes
47
 *
48
 *	Revision 2.7  1993/07/02  10:21:35  istewart
49
 *	224 Beta fixes
50
 *
51
 *	Revision 2.6  1993/06/14  11:01:44  istewart
52
 *	More changes for 223 beta
53
 *
54
 *	Revision 2.5  1993/06/02  09:52:35  istewart
55
 *	Beta 223 Updates - see Notes file
56
 *
57
 *	Revision 2.4  1993/02/16  16:03:15  istewart
58
 *	Beta 2.22 Release
59
 *
60
 *	Revision 2.3  1993/01/26  18:35:09  istewart
61
 *	Release 2.2 beta 0
62
 *
63
 *	Revision 2.2  1992/11/06  10:03:44  istewart
64
 *	214 Beta test updates
65
 *
66
 *	Revision 2.1  1992/07/10  10:52:48  istewart
67
 *	211 Beta updates
68
 *
69
 *	Revision 2.0  1992/04/13  17:39:09  Ian_Stewartson
70
 *	MS-Shell 2.0 Baseline release
71
 *
72
 */
73
 
74
#include <sys/types.h>
75
#include <sys/stat.h>
76
#include <stdio.h>
77
#include <signal.h>
78
#include <setjmp.h>
79
#include <ctype.h>
80
#include <string.h>
81
#include <unistd.h>
82
#include <stdlib.h>
83
#include <limits.h>
84
#include "sh.h"
85
 
86
#define STACK_SIZE	100		/* Stack size			*/
87
#define MAX_PRECEDENCE	15
88
#define MAX_VARIABLES	32		/* Number of user variables	*/
89
 
90
/*
91
 * Some macros
92
 */
93
 
94
#define POP_2_VALUES()		b = stack[StackPointer--].val;	\
95
			  	a = stack[StackPointer--].val;
96
 
97
#define PUSH_VALUE_ON_STACK(X)	PushOnToStack ((long)(X), -1);
98
#define SET_VALUE_ON_STACK(X)	PushOnToStack (SetVariableValue	\
99
						(lv, (long)(X)), lv);
100
 
101
/* the value stack */
102
 
103
static int	LastToken;		/* Last token			*/
104
static int	StackPointer = -1;	/* Stack pointer		*/
105
 
106
static struct MathsStack {
107
    int		lval;
108
    long	val;
109
} stack[STACK_SIZE];
110
 
111
static int	NumberOfVariables = 0;		/* Number of variables	*/
112
static char	*ListOfVariableNames[MAX_VARIABLES];
113
static char	*CStringp;			/* Current position	*/
114
static long	YYLongValue;
115
static int	YYIntValue;
116
static int	JustParsing = 0;		/* Nonzero means we are	*/
117
						/* not evaluating, just	*/
118
						/* parsing		*/
119
static bool	RecogniseUnaryOperator = TRUE;	/* TRUE means recognize	*/
120
						/* unary plus, minus,	*/
121
						/* etc.			*/
122
 
123
/*
124
 * LEFT_RIGHT_A = left-to-right associativity
125
 * RIGHT_LEFT_A = right-to-left associativity
126
 * BOOL_A = short-circuiting boolean
127
 */
128
 
129
#define LEFT_RIGHT_A			0
130
#define RIGHT_LEFT_A			1
131
#define BOOL_A				2
132
 
133
#define OP_OPEN_PAR			0
134
#define OP_CLOSE_PAR			1
135
#define OP_NOT				2
136
#define OP_COMPLEMENT			3
137
#define OP_POST_PLUS			4
138
#define OP_POST_MINUS			5
139
#define OP_UNARY_PLUS			6
140
#define OP_UNARY_MINUS			7
141
#define OP_BINARY_AND_EQUALS		8
142
#define OP_BINARY_XOR_EQUALS		9
143
#define OP_BINARY_OR_EQUALS		10
144
#define OP_MULTIPLY			11
145
#define OP_DIVIDE			12
146
#define OP_MODULUS			13
147
#define OP_PLUS				14
148
#define OP_MINUS			15
149
#define OP_SHIFT_LEFT			16
150
#define OP_SHIFT_RIGHT			17
151
#define OP_LESS				18
152
#define OP_LESS_EQUALS			19
153
#define OP_GREATER			20
154
#define OP_GREATER_EQUALS		21
155
#define OP_EQUALS			22
156
#define OP_NOT_EQUALS			23
157
#define OP_LOGICAL_AND_EQUALS		24
158
#define OP_LOGICAL_OR_EQUALS		25
159
#define OP_LOGICAL_XOR_EQUALS		26
160
#define OP_QUESTION_MARK		27
161
#define OP_COLON			28
162
#define OP_SET				29
163
#define OP_PLUS_EQUAL			30
164
#define OP_MINUS_EQUAL			31
165
#define OP_MULTIPLY_EQUAL		32
166
#define OP_DIVIDE_EQUAL			33
167
#define OP_MODULUS_EQUAL		34
168
#define OP_BINARY_AND_SET		35
169
#define OP_BINARY_XOR_SET		36
170
#define OP_BINARY_OR_SET		37
171
#define OP_SHIFT_LEFT_EQUAL		38
172
#define OP_SHIFT_RIGHT_EQUAL		39
173
#define OP_LOGICAL_AND_SET		40
174
#define OP_LOGICAL_OR_SET		41
175
#define OP_LOGICAL_XOR_SET		42
176
#define OP_COMMA			43
177
#define OP_END_OF_INPUT			44
178
#define OP_PRE_PLUS			45
179
#define OP_PRE_MINUS			46
180
#define OP_NUMERIC_VALUE		47
181
#define OP_VARIABLE			48
182
#define MAX_OPERATORS			49
183
 
184
/* precedences */
185
 
186
static struct Operators {
187
    int		Precedences;		/* Operator Precedences		*/
188
    int		Type;			/* Operator Association		*/
189
} Operators [MAX_OPERATORS] = {
190
    {   1,	LEFT_RIGHT_A },		/* 0 - (			*/
191
    { 137,	LEFT_RIGHT_A },		/* 1 - )			*/
192
    {   2,	RIGHT_LEFT_A },		/* 2 - !			*/
193
    {   2,	RIGHT_LEFT_A },		/* 3 - ~			*/
194
    {   2,	RIGHT_LEFT_A },		/* 4 - x++			*/
195
    {   2,	RIGHT_LEFT_A },		/* 5 - x--			*/
196
    {   2,	RIGHT_LEFT_A },		/* 6 - +			*/
197
    {   2,	RIGHT_LEFT_A },		/* 7 - -			*/
198
    {   4,	LEFT_RIGHT_A },		/* 8 - &			*/
199
    {   5,	LEFT_RIGHT_A },		/* 9 - ^			*/
200
    {   6,	LEFT_RIGHT_A },		/* 10 - |			*/
201
    {   7,	LEFT_RIGHT_A },		/* 11 - *			*/
202
    {   7,	LEFT_RIGHT_A },		/* 12 - /			*/
203
    {   7,	LEFT_RIGHT_A },		/* 13 - %			*/
204
    {   8,	LEFT_RIGHT_A },		/* 14 - +			*/
205
    {   8,	LEFT_RIGHT_A },		/* 15 - -			*/
206
    {   3,	LEFT_RIGHT_A },		/* 16 - <			*/
207
    {   3,	LEFT_RIGHT_A },		/* 17 - >			*/
208
    {   9,	LEFT_RIGHT_A },		/* 18 - < (less than)		*/
209
    {   9,	LEFT_RIGHT_A },		/* 19 - <= (less than equal)	*/
210
    {   9,	LEFT_RIGHT_A },		/* 20 - > (greater than)	*/
211
    {   9,	LEFT_RIGHT_A },		/* 21 - >= (greater than equal) */
212
    {  10,	LEFT_RIGHT_A },		/* 22 - ==			*/
213
    {  10,	LEFT_RIGHT_A },		/* 23 - !=			*/
214
    {  11,	BOOL_A },		/* 24 - &&			*/
215
    {  12,	BOOL_A },		/* 25 - ||			*/
216
    {  12,	LEFT_RIGHT_A },		/* 26 - ^^			*/
217
    {  13,	RIGHT_LEFT_A },		/* 27 - ?			*/
218
    {  13,	RIGHT_LEFT_A },		/* 28 - :			*/
219
    {  14,	RIGHT_LEFT_A },		/* 29 - = 			*/
220
    {  14,	RIGHT_LEFT_A },		/* 30 - +=			*/
221
    {  14,	RIGHT_LEFT_A },		/* 31 - -=			*/
222
    {  14,	RIGHT_LEFT_A },		/* 32 - *=			*/
223
    {  14,	RIGHT_LEFT_A },		/* 33 - /=			*/
224
    {  14,	RIGHT_LEFT_A },		/* 34 - %=			*/
225
    {  14,	RIGHT_LEFT_A },		/* 35 - &=			*/
226
    {  14,	RIGHT_LEFT_A },		/* 36 - ^=			*/
227
    {  14,	RIGHT_LEFT_A },		/* 37 - |=			*/
228
    {  14,	RIGHT_LEFT_A },		/* 38 - <=			*/
229
    {  14,	RIGHT_LEFT_A },		/* 39 - >=			*/
230
    {  14,	BOOL_A },		/* 40 - &&=			*/
231
    {  14,	BOOL_A },		/* 41 - ||=			*/
232
    {  14,	RIGHT_LEFT_A },		/* 42 - ^^=			*/
233
    {  15,	RIGHT_LEFT_A },		/* 43 - ,			*/
234
    { 200,	RIGHT_LEFT_A },		/* 44 - End of input		*/
235
    {   2,	RIGHT_LEFT_A },		/* 45 - ++x			*/
236
    {   2,	RIGHT_LEFT_A },		/* 46 - --x			*/
237
    {   0,	LEFT_RIGHT_A },		/* 47 - Numeric value		*/
238
    {   0,	LEFT_RIGHT_A }		/* 48 - Variable		*/
239
};
240
 
241
 
242
 
243
/*
244
 * Functions
245
 */
246
 
247
static void F_LOCAL	PushOnToStack (long, int);
248
static long F_LOCAL	SetVariableValue (int, long);
249
static bool F_LOCAL	CheckNotZero (long);
250
static void F_LOCAL	ProcessOperator (int);
251
static void F_LOCAL	ProcessBinaryOperator (int);
252
static void F_LOCAL	ParseMathsExpression (int);
253
static int F_LOCAL	MathsLexicalAnalyser (void);
254
static int F_LOCAL	DecideSingleOperator (int, int);
255
static int F_LOCAL	DecideDoubleOperator (char, int, int, int, int);
256
static int F_LOCAL	DecideSignOperator (char, int, int, int, int, int);
257
static char * F_LOCAL	ExtractNameAndIndex (int, int *);
258
 
259
/*
260
 * Analyse the string
261
 */
262
 
263
static int F_LOCAL MathsLexicalAnalyser (void)
264
{
265
    while (TRUE)
266
    {
267
	switch (*(CStringp++))
268
	{
269
	    case '+':
270
		return DecideSignOperator ('+', OP_PRE_PLUS,
271
						OP_POST_PLUS,
272
						OP_PLUS_EQUAL,
273
						OP_UNARY_PLUS,
274
						OP_PLUS);
275
 
276
	    case '-':
277
		return DecideSignOperator ('+', OP_PRE_MINUS,
278
						OP_POST_MINUS,
279
						OP_MINUS_EQUAL,
280
						OP_UNARY_MINUS,
281
						OP_MINUS);
282
 
283
	    case CHAR_OPEN_PARATHENSIS:
284
		RecogniseUnaryOperator = TRUE;
285
		return OP_OPEN_PAR;
286
 
287
	    case CHAR_CLOSE_PARATHENSIS:
288
		return OP_CLOSE_PAR;
289
 
290
	    case '!':
291
		if (*CStringp == '=')
292
		{
293
		    RecogniseUnaryOperator = TRUE;
294
		    CStringp++;
295
		    return OP_NOT_EQUALS;
296
		}
297
 
298
		return OP_NOT;
299
 
300
	    case CHAR_TILDE:
301
		return OP_COMPLEMENT;
302
 
303
	    case '&':
304
		return DecideDoubleOperator ('&', OP_LOGICAL_AND_SET,
305
						  OP_BINARY_AND_SET,
306
						  OP_LOGICAL_AND_EQUALS,
307
						  OP_BINARY_AND_EQUALS);
308
 
309
	    case '|':
310
		return DecideDoubleOperator ('|', OP_LOGICAL_OR_SET,
311
						  OP_BINARY_OR_SET,
312
						  OP_LOGICAL_OR_EQUALS,
313
						  OP_BINARY_OR_EQUALS);
314
 
315
	    case CHAR_XOR:
316
		return DecideDoubleOperator (CHAR_XOR, OP_LOGICAL_XOR_SET,
317
						  OP_BINARY_XOR_SET,
318
						  OP_LOGICAL_XOR_EQUALS,
319
						  OP_BINARY_XOR_EQUALS);
320
 
321
	    case '*':
322
		return DecideSingleOperator (OP_MULTIPLY_EQUAL, OP_MULTIPLY);
323
 
324
	    case '/':
325
		return DecideSingleOperator (OP_DIVIDE_EQUAL, OP_DIVIDE);
326
 
327
	    case '%':
328
		return DecideSingleOperator (OP_MODULUS_EQUAL, OP_MODULUS);
329
 
330
	    case '<':
331
		return DecideDoubleOperator ('<', OP_SHIFT_LEFT_EQUAL,
332
						  OP_LESS_EQUALS,
333
						  OP_SHIFT_LEFT,
334
						  OP_LESS);
335
 
336
	    case '>':
337
		return DecideDoubleOperator ('>', OP_SHIFT_RIGHT_EQUAL,
338
						  OP_GREATER_EQUALS,
339
						  OP_SHIFT_RIGHT,
340
						  OP_GREATER);
341
 
342
	    case CHAR_ASSIGN:
343
		return DecideSingleOperator (OP_EQUALS, OP_SET);
344
 
345
	    case '?':
346
		RecogniseUnaryOperator = TRUE;
347
		return OP_QUESTION_MARK;
348
 
349
	    case ':':
350
		RecogniseUnaryOperator = TRUE;
351
		return OP_COLON;
352
 
353
	    case ',':
354
		RecogniseUnaryOperator = TRUE;
355
		return OP_COMMA;
356
 
357
	    case 0:
358
		RecogniseUnaryOperator = TRUE;
359
		CStringp--;
360
		return OP_END_OF_INPUT;
361
 
362
	    default:
363
		if (isspace (*(CStringp - 1)))
364
		    break;
365
 
366
/* Check for a numeric value */
367
 
368
		if (isdigit (*--CStringp))
369
		{
370
		    char	*End;
371
		    int		base = 10;
372
 
373
		    RecogniseUnaryOperator = FALSE;
374
 
375
/* Which format are we in? base#number or number.  Base is a decimal number
376
 * so we can check for a decimal base and look at the end character to see
377
 * if it was a # sign.  If it was, this is a base#number.  Otherwise, its
378
 * just a number
379
 */
380
 
381
		    strtol (CStringp, &End, 10);
382
 
383
		    if (*End == '#')
384
		    {
385
			LastNumberBase = (int)strtol (CStringp, &CStringp, 10);
386
			base = LastNumberBase;
387
			CStringp++;
388
		    }
389
 
390
		    YYLongValue = strtol (CStringp, &CStringp, base);
391
		    return OP_NUMERIC_VALUE;
392
		}
393
 
394
/* Check for a variable */
395
 
396
		if (IS_VariableFC ((int)*CStringp))
397
		{
398
		    char	*p, q;
399
		    char	*eb;
400
 
401
		    p = CStringp;
402
 
403
		    if (NumberOfVariables == MAX_VARIABLES)
404
		    {
405
			ShellErrorMessage ("too many identifiers");
406
			ExpansionErrorDetected = TRUE;
407
			return OP_END_OF_INPUT;
408
		    }
409
 
410
		    RecogniseUnaryOperator = FALSE;
411
 
412
		    while (IS_VariableSC ((int)(*++CStringp)))
413
			continue;
414
 
415
/* Save the variable name.  Check for array index and skip over. */
416
 
417
		    if ((*CStringp == CHAR_OPEN_BRACKETS) &&
418
			((eb = strchr (CStringp,
419
				       CHAR_CLOSE_BRACKETS)) != (char *)NULL))
420
			CStringp = eb + 1;
421
 
422
/* Save the string */
423
 
424
		    q = *CStringp;
425
		    *CStringp = 0;
426
		    ListOfVariableNames[YYIntValue = NumberOfVariables++] =
427
					StringCopy (p);
428
		    *CStringp = q;
429
		    return OP_VARIABLE;
430
		}
431
 
432
		return OP_END_OF_INPUT;
433
	}
434
    }
435
}
436
 
437
/*
438
 * Stick variable on the stack
439
 */
440
 
441
static void F_LOCAL PushOnToStack (long val, int lval)
442
{
443
    if (StackPointer == STACK_SIZE - 1)
444
    {
445
	ShellErrorMessage ("stack overflow");
446
	ExpansionErrorDetected = TRUE;
447
    }
448
 
449
    else
450
	StackPointer++;
451
 
452
    stack[StackPointer].val = val;
453
    stack[StackPointer].lval = lval;
454
}
455
 
456
/*
457
 * Get a variable value
458
 */
459
 
460
static long F_LOCAL SetVariableValue (int s, long v)
461
{
462
    char	*vn;
463
    int		index;
464
 
465
    if (s == -1 || s >= NumberOfVariables)
466
    {
467
	ExpansionErrorDetected = TRUE;
468
	ShellErrorMessage ("lvalue required");
469
	return 0;
470
    }
471
 
472
    if (JustParsing)
473
	return v;
474
 
475
    vn = ExtractNameAndIndex (s, &index);
476
    SetVariableArrayFromNumeric (vn, index, v);
477
    return v;
478
}
479
 
480
/*
481
 * Check for Division by zero
482
 */
483
 
484
static bool F_LOCAL CheckNotZero (long a)
485
{
486
    if (a)
487
	return TRUE;
488
 
489
    ShellErrorMessage ("division by zero");
490
    ExpansionErrorDetected = TRUE;
491
    return FALSE;
492
}
493
 
494
/*
495
 * Process operator
496
 */
497
 
498
static void F_LOCAL ProcessOperator (int what)
499
{
500
    long	a, b, c;
501
    int		lv;
502
 
503
    if (StackPointer < 0)
504
    {
505
	ShellErrorMessage ("bad math expression - stack empty");
506
	ExpansionErrorDetected = TRUE;
507
	return;
508
    }
509
 
510
    switch (what)
511
    {
512
	case OP_NOT:
513
	    stack[StackPointer].val = !stack[StackPointer].val;
514
	    stack[StackPointer].lval= -1;
515
	    break;
516
 
517
	case OP_COMPLEMENT:
518
	    stack[StackPointer].val = ~stack[StackPointer].val;
519
	    stack[StackPointer].lval= -1;
520
	    break;
521
 
522
	case OP_POST_PLUS:
523
	    SetVariableValue (stack[StackPointer].lval,
524
			       stack[StackPointer].val + 1);
525
	    break;
526
 
527
	case OP_POST_MINUS:
528
	    SetVariableValue (stack[StackPointer].lval,
529
			       stack[StackPointer].val - 1);
530
	    break;
531
 
532
	case OP_UNARY_PLUS:
533
	    stack[StackPointer].lval= -1;
534
	    break;
535
 
536
	case OP_UNARY_MINUS:
537
	    stack[StackPointer].val = -stack[StackPointer].val;
538
	    stack[StackPointer].lval= -1;
539
	    break;
540
 
541
	case OP_BINARY_AND_EQUALS:
542
	    POP_2_VALUES ();
543
	    PUSH_VALUE_ON_STACK (a & b);
544
	    break;
545
 
546
	case OP_BINARY_XOR_EQUALS:
547
	    POP_2_VALUES ();
548
	    PUSH_VALUE_ON_STACK (a ^ b);
549
	    break;
550
 
551
	case OP_BINARY_OR_EQUALS:
552
	    POP_2_VALUES ();
553
	    PUSH_VALUE_ON_STACK (a | b);
554
	    break;
555
 
556
	case OP_MULTIPLY:
557
	    POP_2_VALUES ();
558
	    PUSH_VALUE_ON_STACK (a * b);
559
	    break;
560
 
561
	case OP_DIVIDE:
562
	    POP_2_VALUES ();
563
 
564
	    if (CheckNotZero (b))
565
		 PUSH_VALUE_ON_STACK (a / b);
566
 
567
	    break;
568
 
569
	case OP_MODULUS:
570
	    POP_2_VALUES ();
571
 
572
	    if (CheckNotZero (b))
573
		PUSH_VALUE_ON_STACK (a % b);
574
 
575
	    break;
576
 
577
	case OP_PLUS:
578
	    POP_2_VALUES ();
579
	    PUSH_VALUE_ON_STACK (a + b);
580
	    break;
581
 
582
	case OP_MINUS:
583
	    POP_2_VALUES ();
584
	    PUSH_VALUE_ON_STACK (a - b);
585
	    break;
586
 
587
	case OP_SHIFT_LEFT:
588
	    POP_2_VALUES ();
589
	    PUSH_VALUE_ON_STACK (a  <<  b);
590
	    break;
591
 
592
	case OP_SHIFT_RIGHT:
593
	    POP_2_VALUES ();
594
	    PUSH_VALUE_ON_STACK (a >> b);
595
	    break;
596
 
597
	case OP_LESS:
598
	    POP_2_VALUES ();
599
	    PUSH_VALUE_ON_STACK (a < b);
600
	    break;
601
 
602
	case OP_LESS_EQUALS:
603
	    POP_2_VALUES ();
604
	    PUSH_VALUE_ON_STACK (a <= b);
605
	    break;
606
 
607
	case OP_GREATER:
608
	    POP_2_VALUES ();
609
	    PUSH_VALUE_ON_STACK (a > b);
610
	    break;
611
 
612
	case OP_GREATER_EQUALS:
613
	    POP_2_VALUES ();
614
	    PUSH_VALUE_ON_STACK (a >= b);
615
	    break;
616
 
617
	case OP_EQUALS:
618
	    POP_2_VALUES ();
619
	    PUSH_VALUE_ON_STACK (a == b);
620
	    break;
621
 
622
	case OP_NOT_EQUALS:
623
	    POP_2_VALUES ();
624
	    PUSH_VALUE_ON_STACK (a != b);
625
	    break;
626
 
627
	case OP_LOGICAL_AND_EQUALS:
628
	    POP_2_VALUES ();
629
	    PUSH_VALUE_ON_STACK (a && b);
630
	    break;
631
 
632
	case OP_LOGICAL_OR_EQUALS:
633
	    POP_2_VALUES ();
634
	    PUSH_VALUE_ON_STACK (a || b);
635
	    break;
636
 
637
	case OP_LOGICAL_XOR_EQUALS:
638
	    POP_2_VALUES ();
639
	    PUSH_VALUE_ON_STACK ((a && !b) || (!a && b));
640
	    break;
641
 
642
	case OP_QUESTION_MARK:
643
	    c = stack[StackPointer--].val;
644
	    POP_2_VALUES ();
645
 
646
	    PUSH_VALUE_ON_STACK ((a) ? b : c);
647
	    break;
648
 
649
	case OP_COLON:
650
	    break;
651
 
652
	case OP_SET:
653
	    POP_2_VALUES ();
654
	    lv = stack[StackPointer + 1].lval;
655
	    SET_VALUE_ON_STACK (b);
656
	    break;
657
 
658
	case OP_PLUS_EQUAL:
659
	    POP_2_VALUES ();
660
	    lv = stack[StackPointer + 1].lval;
661
	    SET_VALUE_ON_STACK (a + b);
662
	    break;
663
 
664
	case OP_MINUS_EQUAL:
665
	    POP_2_VALUES ();
666
	    lv = stack[StackPointer + 1].lval;
667
	    SET_VALUE_ON_STACK (a - b);
668
	    break;
669
 
670
	case OP_MULTIPLY_EQUAL:
671
	    POP_2_VALUES ();
672
	    lv = stack[StackPointer + 1].lval;
673
	    SET_VALUE_ON_STACK (a * b);
674
	    break;
675
 
676
	case OP_DIVIDE_EQUAL:
677
	    POP_2_VALUES ();
678
	    lv = stack[StackPointer + 1].lval;
679
 
680
	    if (CheckNotZero (b))
681
		SET_VALUE_ON_STACK (a / b);
682
 
683
	    break;
684
 
685
	case OP_MODULUS_EQUAL:
686
	    POP_2_VALUES ();
687
	    lv = stack[StackPointer + 1].lval;
688
 
689
	    if (CheckNotZero (b))
690
		 SET_VALUE_ON_STACK (a % b);
691
 
692
	    break;
693
 
694
	case OP_BINARY_AND_SET:
695
	    POP_2_VALUES ();
696
	    lv = stack[StackPointer + 1].lval;
697
	    SET_VALUE_ON_STACK (a & b);
698
	    break;
699
 
700
	case OP_BINARY_XOR_SET:
701
	    POP_2_VALUES ();
702
	    lv = stack[StackPointer + 1].lval;
703
	    SET_VALUE_ON_STACK (a ^ b);
704
	    break;
705
 
706
	case OP_BINARY_OR_SET:
707
	    POP_2_VALUES ();
708
	    lv = stack[StackPointer + 1].lval;
709
	    SET_VALUE_ON_STACK (a | b);
710
	    break;
711
 
712
	case OP_SHIFT_LEFT_EQUAL:
713
	    POP_2_VALUES ();
714
	    lv = stack[StackPointer + 1].lval;
715
	    SET_VALUE_ON_STACK (a << b);
716
	    break;
717
 
718
	case OP_SHIFT_RIGHT_EQUAL:
719
	    POP_2_VALUES ();
720
	    lv = stack[StackPointer + 1].lval;
721
	    SET_VALUE_ON_STACK (a >> b);
722
	    break;
723
 
724
	case OP_LOGICAL_AND_SET:
725
	    POP_2_VALUES ();
726
	    lv = stack[StackPointer + 1].lval;
727
	    SET_VALUE_ON_STACK (a && b);
728
	    break;
729
 
730
	case OP_LOGICAL_OR_SET:
731
	    POP_2_VALUES ();
732
	    lv = stack[StackPointer + 1].lval;
733
	    SET_VALUE_ON_STACK (a || b);
734
	    break;
735
 
736
	case OP_LOGICAL_XOR_SET:
737
	    POP_2_VALUES ();
738
	    lv = stack[StackPointer + 1].lval;
739
	    SET_VALUE_ON_STACK ((a && !b) || (!a && b));
740
	    break;
741
 
742
	case OP_COMMA:
743
	    POP_2_VALUES ();
744
	    PUSH_VALUE_ON_STACK (b);
745
	    break;
746
 
747
	case OP_PRE_PLUS:
748
	    stack[StackPointer].val =
749
		SetVariableValue (stack[StackPointer].lval,
750
				  stack[StackPointer].val + 1);
751
	    break;
752
 
753
	case OP_PRE_MINUS:
754
	    stack[StackPointer].val =
755
		SetVariableValue (stack[StackPointer].lval,
756
				  stack[StackPointer].val - 1);
757
	    break;
758
 
759
	default:
760
	    ShellErrorMessage ("out of integers");
761
	    ExpansionErrorDetected = TRUE;
762
	    return;
763
    }
764
}
765
 
766
/*
767
 * Handle binary operators
768
 */
769
 
770
static void F_LOCAL ProcessBinaryOperator (int tk)
771
{
772
    switch (tk)
773
    {
774
	case OP_LOGICAL_AND_EQUALS:
775
	case OP_LOGICAL_AND_SET:
776
	    if (!stack[StackPointer].val)
777
		JustParsing++;
778
 
779
	    break;
780
 
781
	case OP_LOGICAL_OR_EQUALS:
782
	case OP_LOGICAL_OR_SET:
783
	    if (stack[StackPointer].val)
784
		JustParsing++;
785
 
786
	    break;
787
    }
788
}
789
 
790
/*
791
 * Common processing
792
 */
793
 
794
long EvaluateMathsExpression (char *s)
795
{
796
    int		i;
797
 
798
    for (i = 0; i != MAX_VARIABLES; i++)
799
	ListOfVariableNames[i] = (char *)NULL;
800
 
801
    LastNumberBase = -1;		/* Reset base			*/
802
    NumberOfVariables = 0;
803
    CStringp = s;
804
    StackPointer = -1;
805
    RecogniseUnaryOperator = TRUE;
806
    ParseMathsExpression (MAX_PRECEDENCE);
807
 
808
    if (StackPointer)
809
    {
810
	ShellErrorMessage ("bad math expression - unbalanced stack");
811
	ExpansionErrorDetected = TRUE;
812
    }
813
 
814
    if (*CStringp)
815
    {
816
	ShellErrorMessage ("bad math expression - illegal character: %c",
817
			   *CStringp);
818
	ExpansionErrorDetected = TRUE;
819
    }
820
 
821
    for (i = 0; i != NumberOfVariables; i++)
822
	ReleaseMemoryCell ((void *)ListOfVariableNames[i]);
823
 
824
    return stack[0].val;
825
}
826
 
827
/*
828
 * operator-precedence parse the string and execute
829
 */
830
 
831
static void F_LOCAL ParseMathsExpression (int pc)
832
{
833
    char	*vn;
834
    int		index;
835
 
836
    LastToken = MathsLexicalAnalyser ();
837
 
838
    while (Operators[LastToken].Precedences <= pc)
839
    {
840
	if (LastToken == OP_NUMERIC_VALUE)
841
	    PushOnToStack (YYLongValue, -1);
842
 
843
	else if (LastToken == OP_VARIABLE)
844
	{
845
	    vn = ExtractNameAndIndex (YYIntValue, &index);
846
	    PushOnToStack (GetVariableArrayAsNumeric (vn, index), YYIntValue);
847
	}
848
 
849
	else if (LastToken == OP_OPEN_PAR)
850
	{
851
	    ParseMathsExpression (MAX_PRECEDENCE);
852
 
853
	    if (LastToken != OP_CLOSE_PAR)
854
	    {
855
		ShellErrorMessage ("unmatched ()'s");
856
		return;
857
	    }
858
	}
859
 
860
	else if (LastToken == OP_QUESTION_MARK)
861
	{
862
	    long	q = stack[StackPointer].val;
863
 
864
	    if (!q)
865
		JustParsing++;
866
 
867
	    ParseMathsExpression (Operators[OP_QUESTION_MARK].Precedences - 1);
868
 
869
	    if (!q)
870
		JustParsing--;
871
 
872
	    else
873
		JustParsing++;
874
 
875
	    ParseMathsExpression (Operators[OP_QUESTION_MARK].Precedences);
876
 
877
	    if (q)
878
		JustParsing--;
879
 
880
	    ProcessOperator (OP_QUESTION_MARK);
881
	    continue;
882
	}
883
 
884
	else
885
	{
886
	    int		otok = LastToken;
887
	    int		onoeval = JustParsing;
888
 
889
	    if (Operators[otok].Type == BOOL_A)
890
		ProcessBinaryOperator (otok);
891
 
892
	    ParseMathsExpression (Operators[otok].Precedences -
893
				  (Operators[otok].Type != RIGHT_LEFT_A));
894
	    JustParsing = onoeval;
895
	    ProcessOperator (otok);
896
	    continue;
897
	}
898
 
899
	LastToken = MathsLexicalAnalyser ();
900
    }
901
}
902
 
903
/*
904
 * Decide on 'op=', 'opop' or 'op'
905
 */
906
 
907
static int F_LOCAL DecideDoubleOperator (char op,
908
					 int dequal,
909
					 int equal,
910
				         int twice,
911
					 int single)
912
{
913
    RecogniseUnaryOperator = TRUE;
914
 
915
    if (*CStringp == op)
916
    {
917
	if (*(++CStringp) == CHAR_ASSIGN)
918
	{
919
	    CStringp++;
920
	    return dequal;
921
	}
922
 
923
	return twice;
924
    }
925
 
926
    else if (*CStringp == CHAR_ASSIGN)
927
    {
928
	CStringp++;
929
	return equal;
930
    }
931
 
932
    return single;
933
}
934
 
935
/*
936
 * Decide on single operator 'op' or 'op='
937
 */
938
 
939
static int F_LOCAL DecideSingleOperator (int equal, int single)
940
{
941
    RecogniseUnaryOperator = TRUE;
942
 
943
    if (*CStringp != CHAR_ASSIGN)
944
	return single;
945
 
946
    CStringp++;
947
    return equal;
948
}
949
 
950
/*
951
 * Handle +=, ++, + or -=, --, -
952
 */
953
 
954
static int F_LOCAL DecideSignOperator (char sign, int pre_op, int post_op,
955
				    int equals, int unary_op, int op)
956
{
957
    if ((*CStringp == sign) && (RecogniseUnaryOperator || !isalnum (*CStringp)))
958
    {
959
	CStringp++;
960
	return RecogniseUnaryOperator ? pre_op : post_op;
961
    }
962
 
963
    if (*CStringp == CHAR_ASSIGN)
964
    {
965
	RecogniseUnaryOperator = TRUE;
966
	CStringp++;
967
	return equals;
968
    }
969
 
970
    return RecogniseUnaryOperator ? unary_op : op;
971
}
972
 
973
/*
974
 * Validate maths expression without the error message generated a
975
 * command.  This forces the processing to drop down the stack rather than
976
 * doing a deep-exit on error.
977
 */
978
 
979
bool ValidMathsExpression (char *string, long *value)
980
{
981
    ErrorPoint 	Save_ERP = e.ErrorReturnPoint;
982
    bool	Save_EED = ExpansionErrorDetected;
983
    bool	Result;
984
 
985
/* save the environment */
986
 
987
    e.ErrorReturnPoint = (ErrorPoint)NULL;
988
    ExpansionErrorDetected = FALSE;
989
 
990
/* Validate the number */
991
 
992
    *value = EvaluateMathsExpression (string);
993
    Result = ExpansionErrorDetected;
994
 
995
/* Restore environment */
996
 
997
    e.ErrorReturnPoint = Save_ERP;
998
    ExpansionErrorDetected = Save_EED;
999
    return Result;
1000
}
1001
 
1002
/*
1003
 * Extract a variable name and possible index
1004
 */
1005
 
1006
static char * F_LOCAL ExtractNameAndIndex (int s, int *index)
1007
{
1008
    long	IndValue;
1009
    char	*Vp;
1010
    char	*sp = StringCopy (ListOfVariableNames[s]);
1011
 
1012
    if (!GetVariableName (sp, &IndValue, &Vp, (bool *)NULL) || (*Vp))
1013
	PrintErrorMessage (BasicErrorMessage, ListOfVariableNames[s],
1014
			   LIT_BadID);
1015
 
1016
    if (IndValue == -1)
1017
	PrintErrorMessage (LIT_BadArray, ListOfVariableNames[s]);
1018
 
1019
    *index = (int)IndValue;
1020
    return sp;
1021
}