xref: /original-bsd/local/toolchest/ksh/shlib/arith.c (revision 28301386)
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 
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 
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 
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 
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