724bcb61fbe481a37f91174f7ce27ef0f65c39b4
[oweals/cde.git] / cde / programs / dtksh / ksh93 / src / cmd / ksh93 / sh / streval.c
1 /* $XConsortium: streval.c /main/3 1995/11/01 16:51:05 rswiston $ */
2 /***************************************************************
3 *                                                              *
4 *                      AT&T - PROPRIETARY                      *
5 *                                                              *
6 *        THIS IS UNPUBLISHED PROPRIETARY SOURCE CODE OF        *
7 *                    AT&T BELL LABORATORIES                    *
8 *         AND IS NOT TO BE DISCLOSED OR USED EXCEPT IN         *
9 *            ACCORDANCE WITH APPLICABLE AGREEMENTS             *
10 *                                                              *
11 *                Copyright (c) 1995 AT&T Corp.                 *
12 *              Unpublished & Not for Publication               *
13 *                     All Rights Reserved                      *
14 *                                                              *
15 *       The copyright notice above does not evidence any       *
16 *      actual or intended publication of such source code      *
17 *                                                              *
18 *               This software was created by the               *
19 *           Advanced Software Technology Department            *
20 *                    AT&T Bell Laboratories                    *
21 *                                                              *
22 *               For further information contact                *
23 *                    {research,attmail}!dgk                    *
24 *                                                              *
25 ***************************************************************/
26
27 /* : : generated by proto : : */
28
29 #if !defined(__PROTO__)
30 #if defined(__STDC__) || defined(__cplusplus) || defined(_proto) || defined(c_plusplus)
31 #if defined(__cplusplus)
32 #define __MANGLE__      "C"
33 #else
34 #define __MANGLE__
35 #endif
36 #define __STDARG__
37 #define __PROTO__(x)    x
38 #define __OTORP__(x)
39 #define __PARAM__(n,o)  n
40 #if !defined(__STDC__) && !defined(__cplusplus)
41 #if !defined(c_plusplus)
42 #define const
43 #endif
44 #define signed
45 #define void            int
46 #define volatile
47 #define __V_            char
48 #else
49 #define __V_            void
50 #endif
51 #else
52 #define __PROTO__(x)    ()
53 #define __OTORP__(x)    x
54 #define __PARAM__(n,o)  o
55 #define __MANGLE__
56 #define __V_            char
57 #define const
58 #define signed
59 #define void            int
60 #define volatile
61 #endif
62 #if defined(__cplusplus) || defined(c_plusplus)
63 #define __VARARG__      ...
64 #else
65 #define __VARARG__
66 #endif
67 #if defined(__STDARG__)
68 #define __VA_START__(p,a)       va_start(p,a)
69 #else
70 #define __VA_START__(p,a)       va_start(p)
71 #endif
72 #endif
73 #include        "streval.h"
74 #include        <ctype.h>
75 #include        <error.h>
76 #include        "FEATURE/externs"
77
78 #define MAXLEVEL        9
79
80 struct vars                      /* vars stacked per invocation         */
81 {
82         const char*     nextchr; /* next char in current expression     */
83         const char*     errchr;  /* next char after error               */
84         struct lval     errmsg;  /* error message text                  */
85         const char*     errstr;  /* error string                        */
86         unsigned char   paren;   /* parenthesis level                   */
87         char            isfloat; /* set when floating number            */
88 };
89
90
91 #define getchr()        (*cur.nextchr++)
92 #define peekchr()       (*cur.nextchr)
93 #define ungetchr()      (cur.nextchr--)
94
95 #define pushchr(s)      {struct vars old;old=cur;cur.nextchr=((char*)(s));cur.errmsg.value=0;cur.errstr=0;cur.paren=0;
96 #define popchr()        cur=old;}
97 #define ERROR(msg)      return(seterror(msg))
98
99 static struct vars      cur;
100 static char             noassign;       /* set to skip assignment       */
101 static int              level;
102 static double           (*convert) __PROTO__((const char**,struct lval*,int,double));
103                                 /* external conversion routine          */
104 static double           expr __PROTO__((int));  /* subexpression evaluator      */
105 static double           seterror __PROTO__((const char[]));     /* set error message string     */
106
107
108 /*
109  * evaluate an integer arithmetic expression in s
110  *
111  * (double)(*convert)(char** end, struct lval* string, int type, double value)
112  *     is a user supplied conversion routine that is called when unknown 
113  *     chars are encountered.
114  * *end points to the part to be converted and must be adjusted by convert to
115  * point to the next non-converted character; if typ is ERRMSG then string
116  * points to an error message string
117  *
118  * NOTE: (*convert)() may call strval()
119  */
120
121 double strval __PARAM__((const char *s, char** end, double(*conv)(const char**,struct lval*,int,double)), (s, end, conv)) __OTORP__(const char *s; char** end; double(*conv)();){
122         register double n;
123
124         pushchr(s);
125         cur.isfloat = 0;
126         convert = conv;
127         if(level++ >= MAXLEVEL)
128                 (void)seterror(e_recursive);
129         else
130                 n = expr(0);
131         if (cur.errmsg.value)
132         {
133                 if(cur.errstr) s = cur.errstr;
134                 (void)(*convert)( &s , &cur.errmsg, ERRMSG, n);
135                 cur.nextchr = cur.errchr;
136                 n = 0;
137         }
138         if (end) *end = (char*)cur.nextchr;
139         if(level>0) level--;
140         popchr();
141         return(n);
142 }
143
144 /*   
145  * evaluate a subexpression with precedence
146  */
147
148 static double expr __PARAM__((register int precedence), (precedence)) __OTORP__(register int precedence;){
149         register int    c, op;
150         register double n, x;
151         int             wasop, incr=0;
152         struct lval     lvalue, assignop;
153         const char      *pos;
154         char            invalid=0;
155
156         while ((c=getchr()) && isspace(c));
157         switch (c)
158         {
159         case 0:
160                 if(precedence>5)
161                         ERROR(e_moretokens);
162                 return(0);
163
164         case '-':
165                 incr = -2;
166                 /* FALL THRU */
167         case '+':
168                 incr++;
169                 if(c != peekchr())
170                 {
171                         /* unary plus or minus */
172                         n = incr*expr(2*MAXPREC-1);
173                         incr = 0;
174                 }
175                 else /* ++ or -- */
176                 {
177                         invalid = 1;
178                         getchr();
179                 }
180                 break;
181
182         case '!':
183                 n = !expr(2*MAXPREC-1);
184                 break;
185         case '~':
186         {
187                 long nl;
188                 n = expr(2*MAXPREC-1);
189                 nl = (long)n;
190                 if(nl != n)
191                         ERROR(e_incompatible);
192                 else
193                         n = ~nl;
194                 break;
195         }
196         default:
197                 ungetchr();
198                 invalid = 1;
199                 break;
200         }
201         wasop = invalid;
202         lvalue.value = 0;
203         lvalue.fun = 0;
204         while(1)
205         {
206                 cur.errchr = cur.nextchr;
207                 if((c=getchr()) >= sizeof(strval_states))
208                         op = (c=='|' ? A_OR: (c=='^'?A_XOR:A_REG));
209                 else if((op=strval_states[c])==0)
210                         continue;
211                 switch(op)
212                 {
213                         case A_EOF:
214                                 ungetchr();
215                                 break;
216                         case A_DIG:
217 #ifdef future
218                                 n = c - '0';
219                                 while((c=getchr()), isdigit(c))
220                                         n = (10*n) + (c-'0');
221                                 wasop = 0;
222                                 ungetchr();
223                                 continue;
224 #endif
225                         case A_REG:     case A_DOT:
226                                 op = 0;
227                                 break;
228                         case A_QUEST:
229                                 if(*cur.nextchr==':')
230                                 {
231                                         cur.nextchr++;
232                                         op = A_QCOLON;
233                                 }
234                                 break;
235                         case A_LT:      case A_GT: 
236                                 if(*cur.nextchr==c)
237                                 {
238                                         cur.nextchr++;
239                                         op -= 2;
240                                         break;
241                                 }
242                                 /* FALL THRU */
243                         case A_NOT:     case A_COLON:
244                                 c = '=';
245                                 /* FALL THRU */
246                         case A_ASSIGN:
247                         case A_PLUS:    case A_MINUS:
248                         case A_OR:      case A_AND:
249                                 if(*cur.nextchr==c)
250                                 {
251                                         cur.nextchr++;
252                                         op--;
253                                 }
254                 }
255                 assignop.value = 0;
256                 if(op && wasop++ && op!=A_LPAR)
257                         ERROR(e_synbad);
258                 /* check for assignment operation */
259                 if(peekchr()== '=' && !(strval_precedence[op]&NOASSIGN))
260                 {
261                         if(!noassign && (!lvalue.value || precedence > 2))
262                                 ERROR(e_notlvalue);
263                         assignop = lvalue;
264                         getchr();
265                         c = 3;
266                 }
267                 else
268                 {
269                         c = (strval_precedence[op]&PRECMASK);
270                         c *= 2;
271                 }
272                 /* from here on c is the new precedence level */
273                 if(lvalue.value && (op!=A_ASSIGN))
274                 {
275                         if(noassign)
276                                 n = 1;
277                         else
278                         {
279                                 pos = cur.nextchr;
280                                 n = (*convert)(&cur.nextchr, &lvalue, VALUE, n);
281                                 if (cur.nextchr!=pos)
282                                 {
283                                         if(cur.errmsg.value = lvalue.value)
284                                                 cur.errstr = cur.nextchr;
285                                         ERROR(e_synbad);
286                                 }
287                         }
288                         if(cur.nextchr==0)
289                                 ERROR(e_badnum);
290                         if(!(strval_precedence[op]&SEQPOINT))
291                                 lvalue.value = 0;
292                         invalid = 0;
293                 }
294                 if(invalid && op>A_ASSIGN)
295                         ERROR(e_synbad);
296                 if(precedence >= c)
297                         goto done;
298                 if(strval_precedence[op]&RASSOC)
299                         c--;
300                 if(c < 2*MAXPREC && !(strval_precedence[op]&SEQPOINT))
301                 {
302                         wasop = 0;
303                         x = expr(c);
304                 }
305                 if((strval_precedence[op]&NOFLOAT) && !noassign && cur.isfloat)
306                         ERROR(e_incompatible);
307                 switch(op)
308                 {
309                 case A_RPAR:
310                         if(!cur.paren)
311                                 ERROR(e_paren);
312                         if(invalid)
313                                 ERROR(e_synbad);
314                         goto done;
315
316                 case A_COMMA:
317                         wasop = 0;
318                         n = expr(c);
319                         lvalue.value = 0;
320                         break;
321
322                 case A_LPAR:
323                 {
324                         char    savefloat = cur.isfloat;
325                         double (*fun) __PROTO__((double));
326                         fun = lvalue.fun;
327                         lvalue.fun = 0;
328                         cur.isfloat = 0;
329                         if(!invalid)
330                                 ERROR(e_synbad);
331                         cur.paren++;
332                         n = expr(1);
333                         cur.paren--;
334                         if(fun)
335                         {
336                                 n = (*fun)(n);
337                                 cur.isfloat = (fun!=floor);
338                         }
339                         cur.isfloat |= savefloat;
340                         if (getchr() != ')')
341                                 ERROR(e_paren);
342                         wasop = 0;
343                         break;
344                 }
345
346                 case A_PLUSPLUS:
347                         incr = 1;
348                         goto common;
349                 case A_MINUSMINUS:
350                         incr = -1;
351                 common:
352                         x = n;
353                         wasop=0;
354                 case A_ASSIGN:
355                         if(!noassign && !lvalue.value)
356                                 ERROR(e_notlvalue);
357                         n = x;
358                         assignop = lvalue;
359                         lvalue.value = 0;
360                         break;
361
362                 case A_QUEST:
363                         if(!n)
364                                 noassign++;
365                         x = expr(1);
366                         if(!n)
367                                 noassign--;
368                         if(getchr()!=':')
369                                 ERROR(e_questcolon);
370                         if(n)
371                         {
372                                 n = x;
373                                 noassign++;
374                                 (void)expr(c);
375                                 noassign--;
376                         }
377                         else
378                                 n = expr(c);
379                         lvalue.value = 0;
380                         wasop = 0;
381                         break;
382
383                 case A_COLON:
384                         (void)seterror(e_badcolon);
385                         break;
386
387                 case A_OR:
388                         n = (long)n | (long)x;
389                         break;
390
391                 case A_QCOLON:
392                 case A_OROR:
393                         if(n)
394                         {
395                                 noassign++;
396                                 expr(c);
397                                 noassign--;
398                         }
399                         else
400                                 n = expr(c);
401                         if(op==A_OROR)
402                                 n = (n!=0);
403                         lvalue.value = 0;
404                         wasop=0;
405                         break;
406
407                 case A_XOR:
408                         n = (long)n ^ (long)x;
409                         break;
410
411                 case A_NOT:
412                         ERROR(e_synbad);
413
414                 case A_AND:
415                         n = (long)n & (long)x;
416                         break;
417
418                 case A_ANDAND:
419                         if(n==0)
420                         {
421                                 noassign++;
422                                 expr(c);
423                                 noassign--;
424                         }
425                         else
426                                 n = (expr(c)!=0);
427                         lvalue.value = 0;
428                         wasop=0;
429                         break;
430
431                 case A_EQ:
432                         n = n == x;
433                         break;
434
435                 case A_NEQ:
436                         n = n != x;
437                         break;
438
439                 case A_LT:
440                         n = n < x;
441                         break;
442
443                 case A_LSHIFT:
444                         n = (long)n << (long)x;
445                         break;
446
447                 case A_LE:
448                         n = n <= x;
449                         break;
450
451                 case A_GT:
452                         n = n > x;
453                         break;
454
455                 case A_RSHIFT:
456                         n = (long)n >> (long)x;
457                         break;
458
459                 case A_GE:
460                         n = n >= x;
461                         break;
462
463                 case A_PLUS:
464                         n +=  x;
465                         break;
466
467                 case A_MINUS:
468                         n -=  x;
469                         break;
470
471                 case A_TIMES:
472                         n *=  x;
473                         break;
474
475                 case A_DIV:
476                         if(x!=0)
477                         {
478                                 if(cur.isfloat)
479                                         n /=  x;
480                                 else
481                                         n =  (long)n / (long)x;
482                                 break;
483                         }
484
485                 case A_MOD:
486                         if(x!=0)
487                                 n = (long)n % (long)x;
488                         else if(!noassign)
489                                 ERROR(e_divzero);
490                         break;
491
492                 default:
493                         if(!wasop)
494                                 ERROR(e_synbad);
495                         wasop = 0;
496                         pos = --cur.nextchr;
497                         lvalue.isfloat = 0;
498                         n = (*convert)(&cur.nextchr, &lvalue, LOOKUP, n);
499                         if (cur.nextchr == pos)
500                         {
501                                 if(cur.errmsg.value = lvalue.value)
502                                         cur.errstr = pos;
503                                 ERROR(e_synbad);
504                         }
505                         cur.isfloat |= lvalue.isfloat;
506         
507                         /* check for function call */
508                         if(lvalue.fun)
509                                 continue;
510                         /* this handles ++x and --x */
511                         if(!noassign && incr)
512                         {
513                                 if(lvalue.value)
514                                 {
515                                         pos = cur.nextchr;
516                                         n = (*convert)(&cur.nextchr, &lvalue, VALUE, n);
517                                         if (cur.nextchr!=pos)
518                                         {
519                                                 if(cur.errmsg.value = lvalue.value)
520                                                         cur.errstr=cur.nextchr;
521                                                 ERROR(e_synbad);
522                                         }
523                                 }
524                                 n += incr;
525                                 incr = 0;
526                                 goto common;
527                         }
528                         break;
529                 }
530                 invalid = 0;
531                 if(!noassign && assignop.value)
532                         (void)(*convert)(&cur.nextchr,&assignop,ASSIGN,n+incr);
533                 incr = 0;
534         }
535  done:
536         cur.nextchr = cur.errchr;
537         return(n);
538 }
539
540 /*
541  * set error message string
542  */
543
544 static double seterror __PARAM__((const char *msg), (msg)) __OTORP__(const char *msg;){
545         if(!cur.errmsg.value)
546                 cur.errmsg.value = (char*)msg;
547         cur.errchr = cur.nextchr;
548         cur.nextchr = "";
549         level = 0;
550         return(0);
551 }
552
553 #ifdef _mem_name_exception
554 #undef error
555     int matherr __PARAM__((struct exception *ep), (ep)) __OTORP__(struct exception *ep;){
556         const char *message;
557         switch(ep->type)
558         {
559             case DOMAIN:
560                 message = e_domain;
561                 break;
562             case SING:
563                 message = e_singularity;
564                 break;
565             case OVERFLOW:
566                 message = e_overflow;
567                 break;
568             default:
569                 return(1);
570         }
571         level=0;
572         error(ERROR_exit(1),message,ep->name);
573         return(0);
574     }
575 #endif /* _mem_name_exception */