1 /*
2
3 * Copyright (c) 1984, 1985, 1986 AT&T
4 * All Rights Reserved
5
6 * THIS IS UNPUBLISHED PROPRIETARY SOURCE
7 * CODE OF AT&T.
8 * The copyright notice above does not
9 * evidence any actual or intended
10 * publication of such source code.
11
12 */
13 /* @(#)arith.c 1.1 */
14
15 /*
16 * ARITH.C
17 *
18 * Programmer: D. G. Korn
19 *
20 * Owner: D. A. Lambeth
21 *
22 * Date: April 17, 1980
23 *
24 *
25 *
26 * AEVAL (STRING)
27 *
28 * Evaluate STRING as an arithmetic expression (possibly
29 * containing variables from trees in NAMEP) and return its value.
30 *
31 * LOOKUP (NAME)
32 *
33 * Return a pointer to the shell-owned Namnod in TREE
34 * whose namid is NAME. If TYPE is non-zero, a new Namnod
35 * with the given namid will be inserted, when none is found.
36 *
37 * These functions are indirectly mutually recursive.
38 *
39 *
40 *
41 * See Also: LET(I), findnod(III)
42 */
43
44 #ifdef KSHELL
45 #include "shtype.h"
46 #else
47 #include <ctype.h>
48 #endif /* KSHELL */
49 #include <stdio.h>
50 #include "name.h"
51 #include "flags.h"
52
53 #define getchr() (*(unsigned char*)strg++)
54 #define seekto(loc) (strg=(loc))
55 #define ungetc() (--strg)
56 #define peekc() (*strg)
57 #define MAXLOOP 10
58
59 extern union Namval *aget_up();
60 extern char *bracket_match();
61 extern char *valup();
62 extern void failed();
63 extern struct Namnod *findnod();
64 #ifdef NAME_SCOPE
65 extern struct Namnod *copy_nod();
66 #endif
67 struct Namnod *lookup();
68
69 static long arith();
70 static void aerror();
71
72 static char *strg = 0;
73 static int level = 0;
74
75 /*
76 * AEVAL (STRING)
77 *
78 * char *STRING;
79 *
80 *
81 * Evaluate string as an arithmetic expression (possibly
82 * containing variables from trees in NAMEP) and return its
83 * value as a long int. STRING can be anything acceptable to
84 * the LET(I) builtin of the shell.
85 *
86 */
87
aeval(string)88 long aeval(string)
89 char *string;
90 {
91 long r;
92 long arith();
93 char *ostr;
94 ostr = strg;
95 if(level++ > MAXLOOP)
96 aerror(string,badnum);
97 strg = string;
98 r = arith(0);
99 strg = ostr;
100 level--;
101 return(r);
102 }
103
104 /*
105 * ARITH (PREC)
106 *
107 * int PREC;
108 *
109 * Evaluate the expression given in the global pointer strg
110 * as an arithmetic expression, to PREC digits. The form
111 * of strg is as is given for the LET builtin.
112 */
113
arith(prec)114 static long int arith(prec)
115 {
116 register int c;
117 #ifdef pdp11
118 long r;
119 long rr;
120 #else
121 register long r;
122 register long rr;
123 #endif
124 int base;
125 char *ostr;
126 char dot = 0;
127
128 /* ignore whitespace */
129 while((c=getchr()),isspace(c));
130 if(c==0)
131 goto done;
132 ostr = (strg-1);
133 r = 0;
134 if(c == '-')
135 r = -arith(8);
136 else if(c == '!')
137 r = !arith(7);
138 else if(isalpha(c))
139 {
140 int oldc;
141 char *varname,*sp;
142 varname = ostr;
143 for(;isalnum(c);c=getchr());
144 if(c == '[')
145 {
146 seekto(bracket_match(ungetc()));
147 c = getchr();
148 if(c == 0)
149 aerror(varname,subscript);
150 c = getchr();
151 }
152 /* null terminate variable name */
153 sp = (strg-1);
154 *sp = 0;
155 /* skip over whitespace */
156 for(oldc = c;isspace(c);c = getchr());
157 if(c == '='&& peekc() != '=')
158 asslong(lookup(varname),r=arith(2));
159 else
160 {
161 char *str;
162 register struct Namnod *np = lookup(varname);
163 register union Namval *up;
164 ungetc();
165 if (attest (np, INT_GER))
166 {
167 #ifdef NAME_SCOPE
168 if (attest (np,C_WRITE))
169 np = copy_nod(np,1);
170 #endif
171 up= &np->value.namval;
172 if(attest(np,IN_DIR))
173 up = up->up;
174 if(attest (np, (BLT_NOD)))
175 r = (long)((*up->fp->f_vp)());
176 else if(up->lp==NULL)
177 r = 0;
178 else
179 r = *up->lp;
180 }
181 else
182 {
183 if((str=valup(np))==0 || *str==0)
184 aerror(varname,badnum);
185 r = aeval(str);
186 }
187 }
188 *sp = oldc;
189 }
190 else
191 {
192 base = 10;
193 ungetc();
194 lastbase = base;
195 }
196
197 while((c=getchr()) && c != ']')
198 {
199 switch(c)
200 {
201 case ')':
202 if(prec)
203 goto done;
204 else
205 aerror(ostr,synmsg);
206
207 case '(':
208 r = arith(1);
209 if((c=getchr()) != ')')
210 aerror(ostr,synmsg);
211 break;
212
213 case '=': case '!':
214 if(prec > 3)
215 goto done;
216 if(getchr() != '=')
217 aerror(ostr,synmsg);
218 rr = arith(4);
219 if(c == '=')
220 r = r == rr;
221 else
222 r = r != rr;
223 break;
224
225 case '<': case '>':
226 if(prec > 4)
227 goto done;
228 if(peekc() == '=')
229 {
230 getchr();
231 rr = arith(5);
232 if(c == '<')
233 r = r <= rr;
234 else
235 r = r >= rr;
236 break;
237 }
238 rr = arith(5);
239 if(c == '<')
240 r = r < rr;
241 else
242 r = r > rr;
243 break;
244
245 case '+': case '-':
246 if(prec > 5)
247 goto done;
248 rr = arith(6);
249 if(c == '+')
250 r += rr;
251 else
252 r -= rr;
253 break;
254
255 case '*': case '/': case '%':
256 if(prec > 6)
257 goto done;
258 rr = arith(7);
259 if (c == '*')
260 r *= rr;
261 else if(rr == 0)
262 aerror(ostr,divzero);
263 else if (c == '/')
264 r /= rr;
265 else
266 r %= rr;
267 break;
268
269 case ' ': case '\n': case '\t':
270 break;
271
272 case '#':
273 lastbase = base = r;
274 r = 0;
275 break;
276
277 case '.':
278 if(dot++==0)
279 continue;
280
281 default:
282 {
283 register int d;
284 for(d=0; hdigits[d] && c != hdigits[d];d++);
285 d >>= 1;
286 if( d < base )
287 {
288 if(dot==0)
289 r = base*r + d;
290 }
291 else
292 aerror(ostr,badnum);
293 }
294 }
295 }
296 done:
297 ungetc();
298 return(r);
299 }
300
aerror(name,msg)301 static void aerror(name,msg)
302 char *name,*msg;
303 {
304 level = 0;
305 failed(name,msg);
306 }
307
308 /*
309 * lookup name and return Namnod pointer with this name.
310 * If none exists, it will be created.
311 */
312
lookup(name)313 struct Namnod *lookup(name)
314 char *name;
315 {
316 register struct Namnod *np = NULL;
317 register struct Amemory *ap;
318 register struct Amemory *app = namep;
319 int type = 0;
320 while((ap=app) && np==NULL)
321 {
322 app = app->nexttree;
323 np =findnod(name,ap,type|(app==NULL));
324 type = RE_USE;
325 }
326 return(np);
327 }
328
329