1 /*****************************************************************************
2 
3 	PushEx ()
4 	Reduce ()
5 	Push an item on the stack and try to reduce it.
6 
7 *****************************************************************************/
8 
9 #include "zport.h"		/* define portability identifiers */
10 #include "tecoc.h"		/* define general identifiers */
11 #include "defext.h"		/* define external global variables */
12 #include "dchars.h"		/* define identifiers for characters */
13 #include "deferr.h"		/* define identifiers for error messages */
14 
15 /*****************************************************************************
16 
17 	Reduce()
18 
19 	This function attempts to reduce the expression stack.  It is called
20 by PushEx when the stack has two or more values on it and therefore might be
21 reduceable.
22 
23 *****************************************************************************/
24 
25 #if USE_PROTOTYPES
26 static DEFAULT Reduce(void);
27 #endif
28 
Reduce()29 static DEFAULT Reduce()		/* reduce the expression stack */
30 {
31 	ESptr	ESp1;		/* 1st thing on stack (top) */
32 	ESptr	ESp2;		/* 2nd thing on stack (top-1) */
33 	ESptr	ESp3;		/* 3rd thing on stack (top-2) */
34 	WORD	OnStack;	/* number of items on stack */
35 	LONG	x;		/* temporary operand */
36 	LONG	y;		/* temporary operand */
37 
38 	FOREVER {		/* reduce until you can't reduce anymore */
39 		OnStack = EStTop - EStBot;
40 		if (OnStack < 0) {	/* nothing on stack */
41 			break;
42 		}
43 		ESp1 = &(EStack[EStTop]);
44 		ESp2 = ESp1 - 1;
45 		ESp3 = ESp2 - 1;
46 		if (OnStack >= 3) {
47 /*
48  * if it's x+y, x-y, x*y, x/y, x&y or x#y, reduce it
49  */
50 			if (ESp1->ElType == OPERAND  &&
51 			    ESp2->ElType == OPERATOR &&
52 			    ESp3->ElType == OPERAND  &&
53 			    ESp2->Elemnt != ')' &&
54 			    ESp2->Elemnt != '(') {
55 				x = ESp3->Elemnt;
56 				y = ESp1->Elemnt;
57 				switch ((char)ESp2->Elemnt) {
58 				case '+':	x += y;		break;
59 				case '-':	x -= y;		break;
60 				case '*':	x *= y;		break;
61 				case '/':	x /= y;		break;
62 				case '&':	x &= y;		break;
63 				case '#':	x |= y;		break;
64 				}
65 				ESp3->Elemnt = x;
66 /*
67  * ESp3->ElType is already OPERAND
68  */
69 				EStTop -= 2;
70 				continue;
71 			} else {
72 /*
73  * if it's (x),  reduce it to x
74  */
75 				if (ESp1->ElType == OPERATOR &&
76 				    ESp2->ElType == OPERAND  &&
77 				    ESp3->ElType == OPERATOR &&
78 				    ESp1->Elemnt == ')' &&
79 				    ESp3->Elemnt == '(') {
80 					ESp3->Elemnt = ESp2->Elemnt;
81 					ESp3->ElType = OPERAND;
82 					EStTop -= 2;
83 					continue;
84 				}
85 			}
86 		}
87 		if (OnStack >= 2) {
88 /*
89  * if it's +x or -x, reduce it to + or - x
90  */
91 			if (ESp1->ElType == OPERAND  &&
92 			    ESp2->ElType == OPERATOR &&
93 			    (ESp2->Elemnt == '+' || ESp2->Elemnt == '-')) {
94 				x = ESp1->Elemnt;
95 				if (ESp2->Elemnt == '-') {
96 					x = -x;
97 				}
98 				ESp2->Elemnt = x;
99 				ESp2->ElType = OPERAND;
100 				--EStTop;
101 				continue;
102 			}
103 		}
104 		if (OnStack >= 1) {
105 /*
106  * check for one's complement operator ^_.  This operator complements the
107  * PRECEDING argument.
108  */
109 			if (ESp1->ElType == OPERATOR &&
110 			    ESp1->Elemnt == USCHAR) {
111 				if (OnStack == 1 || ESp2->ElType != OPERAND) {
112 					ErrMsg(ERR_NAB); /* no arg before ^_ */
113 					return FAILURE;
114 				}
115 				ESp2->Elemnt = ~(ESp2->Elemnt);
116 /*
117  * ESp2->ElType is already OPERAND
118  */
119 				--EStTop;
120 				continue;
121 			}
122 		}
123 		break;		/* can't reduce anymore */
124 	}
125 	return (SUCCESS);
126 }
127 
128 /*****************************************************************************
129 
130 	PushEx()
131 
132 	This function pushes an item onto the expression stack.  The
133 expression stack implement's TECO's expression handling capability.  For
134 instance,  if a command like 10+qa=$ is executed,  then three values are
135 pushed onto the expression stack: 10, plus sign and the value of qa.  Each
136 time a value is pushed onto the expression stack,  the Reduce function is
137 called to see if the stack can be reduced.  In the above example,  Reduce
138 would cause the stack to be reduced when the value of qa is pushed,  because
139 the expression can be evaluated at that time.
140 
141 *****************************************************************************/
142 
PushEx(Item,EType)143 DEFAULT PushEx(Item, EType)	/* push onto expression stack */
144 LONG Item;
145 DEFAULT EType;
146 {
147 #if DEBUGGING
148 	static char *DbgFNm = "PushEx";
149 	if (EType == OPERAND) {
150 		sprintf(DbgSBf,"Item = %ld, EType = OPERAND", (LONG)Item);
151 	} else if (EType == OPERATOR) {
152 		sprintf(DbgSBf,"Item = '%c', EType = OPERATOR", (char)Item);
153 	} else {
154 		DbgFEn(3,DbgFNm,"FAILURE, illegal item type");
155 		TAbort(EXIT_FAILURE);
156 	}
157 	DbgFEn(3,DbgFNm,DbgSBf);
158 #endif
159 
160 	if (++EStTop >= EXS_SIZE) {		/* if expression stack full */
161 		ErrMsg(ERR_PDO);		/* push-down list overflow */
162 		DBGFEX(3,DbgFNm,"FAILURE, expression stack full");
163 		return FAILURE;
164 	}
165 
166 	EStack[EStTop].Elemnt = Item;		/* put item on stack */
167 	EStack[EStTop].ElType = EType;		/* put item type on stack */
168 	if (EStTop > (EStBot + 1)) {		/* if stack might reduce */
169 		if (Reduce() == FAILURE) {	/* reduce expression stack */
170 			DBGFEX(3,DbgFNm,"FAILURE, Reduce() failed");
171 			return FAILURE;
172 		}
173 	}
174 #if DEBUGGING
175 	sprintf(DbgSBf,"EStTop = %ld, EStBot = %ld", (LONG)EStTop, (LONG)EStBot);
176 	DbgFEx(3,DbgFNm,DbgSBf);
177 #endif
178 	return SUCCESS;
179 }
180