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