Home | History | Annotate | Line # | Download | only in m4
expr.c revision 1.1.1.1
      1 /*
      2  * Copyright (c) 1989 The Regents of the University of California.
      3  * All rights reserved.
      4  *
      5  * This code is derived from software contributed to Berkeley by
      6  * Ozan Yigit.
      7  *
      8  * Redistribution and use in source and binary forms, with or without
      9  * modification, are permitted provided that the following conditions
     10  * are met:
     11  * 1. Redistributions of source code must retain the above copyright
     12  *    notice, this list of conditions and the following disclaimer.
     13  * 2. Redistributions in binary form must reproduce the above copyright
     14  *    notice, this list of conditions and the following disclaimer in the
     15  *    documentation and/or other materials provided with the distribution.
     16  * 3. All advertising materials mentioning features or use of this software
     17  *    must display the following acknowledgement:
     18  *	This product includes software developed by the University of
     19  *	California, Berkeley and its contributors.
     20  * 4. Neither the name of the University nor the names of its contributors
     21  *    may be used to endorse or promote products derived from this software
     22  *    without specific prior written permission.
     23  *
     24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
     25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
     28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     34  * SUCH DAMAGE.
     35  */
     36 
     37 #ifndef lint
     38 static char sccsid[] = "@(#)expr.c	5.3 (Berkeley) 2/26/91";
     39 #endif /* not lint */
     40 
     41 #include <setjmp.h>
     42 #include <stdio.h>
     43 
     44 /*
     45  *      expression evaluator: performs a standard recursive
     46  *      descent parse to evaluate any expression permissible
     47  *      within the following grammar:
     48  *
     49  *      expr    :       query EOS
     50  *      query   :       lor
     51  *              |       lor "?" query ":" query
     52  *      lor     :       land { "||" land }
     53  *      land    :       bor { "&&" bor }
     54  *      bor     :       bxor { "|" bxor }
     55  *      bxor    :       band { "^" band }
     56  *      band    :       eql { "&" eql }
     57  *      eql     :       relat { eqrel relat }
     58  *      relat   :       shift { rel shift }
     59  *      shift   :       primary { shop primary }
     60  *      primary :       term { addop term }
     61  *      term    :       unary { mulop unary }
     62  *      unary   :       factor
     63  *              |       unop unary
     64  *      factor  :       constant
     65  *              |       "(" query ")"
     66  *      constant:       num
     67  *              |       "'" CHAR "'"
     68  *      num     :       DIGIT
     69  *              |       DIGIT num
     70  *      shop    :       "<<"
     71  *              |       ">>"
     72  *      eqlrel  :       "="
     73  *              |       "=="
     74  *              |       "!="
     75  *      rel     :       "<"
     76  *              |       ">"
     77  *              |       "<="
     78  *              |       ">="
     79  *
     80  *
     81  *      This expression evaluator is lifted from a public-domain
     82  *      C Pre-Processor included with the DECUS C Compiler distribution.
     83  *      It is hacked somewhat to be suitable for m4.
     84  *
     85  *      Originally by:  Mike Lutz
     86  *                      Bob Harper
     87  */
     88 
     89 #define TRUE    1
     90 #define FALSE   0
     91 #define EOS     (char) 0
     92 #define EQL     0
     93 #define NEQ     1
     94 #define LSS     2
     95 #define LEQ     3
     96 #define GTR     4
     97 #define GEQ     5
     98 #define OCTAL   8
     99 #define DECIMAL 10
    100 
    101 static char *nxtch;     /* Parser scan pointer */
    102 
    103 /*
    104  * For longjmp
    105  */
    106 static jmp_buf  expjump;
    107 
    108 /*
    109  * macros:
    110  *
    111  *      ungetch - Put back the last character examined.
    112  *      getch   - return the next character from expr string.
    113  */
    114 #define ungetch()       nxtch--
    115 #define getch()         *nxtch++
    116 
    117 expr(expbuf)
    118 char *expbuf;
    119 {
    120         register int rval;
    121 
    122         nxtch = expbuf;
    123         if (setjmp(expjump) != 0)
    124                 return (FALSE);
    125         rval = query();
    126         if (skipws() == EOS)
    127                 return(rval);
    128         experr("Ill-formed expression");
    129 }
    130 
    131 /*
    132  * query : lor | lor '?' query ':' query
    133  *
    134  */
    135 query()
    136 {
    137         register int bool, true_val, false_val;
    138 
    139         bool = lor();
    140         if (skipws() != '?') {
    141                 ungetch();
    142                 return(bool);
    143         }
    144 
    145         true_val = query();
    146         if (skipws() != ':')
    147                 experr("Bad query");
    148 
    149         false_val = query();
    150         return(bool ? true_val : false_val);
    151 }
    152 
    153 /*
    154  * lor : land { '||' land }
    155  *
    156  */
    157 lor()
    158 {
    159         register int c, vl, vr;
    160 
    161         vl = land();
    162         while ((c = skipws()) == '|' && getch() == '|') {
    163                 vr = land();
    164                 vl = vl || vr;
    165         }
    166 
    167         if (c == '|')
    168                 ungetch();
    169         ungetch();
    170         return(vl);
    171 }
    172 
    173 /*
    174  * land : bor { '&&' bor }
    175  *
    176  */
    177 land()
    178 {
    179         register int c, vl, vr;
    180 
    181         vl = bor();
    182         while ((c = skipws()) == '&' && getch() == '&') {
    183                 vr = bor();
    184                 vl = vl && vr;
    185         }
    186 
    187         if (c == '&')
    188                 ungetch();
    189         ungetch();
    190         return(vl);
    191 }
    192 
    193 /*
    194  * bor : bxor { '|' bxor }
    195  *
    196  */
    197 bor()
    198 {
    199         register int vl, vr, c;
    200 
    201         vl = bxor();
    202         while ((c = skipws()) == '|' && getch() != '|') {
    203                 ungetch();
    204                 vr = bxor();
    205                 vl |= vr;
    206         }
    207 
    208         if (c == '|')
    209                 ungetch();
    210         ungetch();
    211         return(vl);
    212 }
    213 
    214 /*
    215  * bxor : band { '^' band }
    216  *
    217  */
    218 bxor()
    219 {
    220         register int vl, vr;
    221 
    222         vl = band();
    223         while (skipws() == '^') {
    224                 vr = band();
    225                 vl ^= vr;
    226         }
    227 
    228         ungetch();
    229         return(vl);
    230 }
    231 
    232 /*
    233  * band : eql { '&' eql }
    234  *
    235  */
    236 band()
    237 {
    238         register int vl, vr, c;
    239 
    240         vl = eql();
    241         while ((c = skipws()) == '&' && getch() != '&') {
    242                 ungetch();
    243                 vr = eql();
    244                 vl &= vr;
    245         }
    246 
    247         if (c == '&')
    248                 ungetch();
    249         ungetch();
    250         return(vl);
    251 }
    252 
    253 /*
    254  * eql : relat { eqrel relat }
    255  *
    256  */
    257 eql()
    258 {
    259         register int vl, vr, rel;
    260 
    261         vl = relat();
    262         while ((rel = geteql()) != -1) {
    263                 vr = relat();
    264 
    265                 switch (rel) {
    266 
    267                 case EQL:
    268                         vl = (vl == vr);
    269                         break;
    270                 case NEQ:
    271                         vl = (vl != vr);
    272                         break;
    273                 }
    274         }
    275         return(vl);
    276 }
    277 
    278 /*
    279  * relat : shift { rel shift }
    280  *
    281  */
    282 relat()
    283 {
    284         register int vl, vr, rel;
    285 
    286         vl = shift();
    287         while ((rel = getrel()) != -1) {
    288 
    289                 vr = shift();
    290                 switch (rel) {
    291 
    292                 case LEQ:
    293                         vl = (vl <= vr);
    294                         break;
    295                 case LSS:
    296                         vl = (vl < vr);
    297                         break;
    298                 case GTR:
    299                         vl = (vl > vr);
    300                         break;
    301                 case GEQ:
    302                         vl = (vl >= vr);
    303                         break;
    304                 }
    305         }
    306         return(vl);
    307 }
    308 
    309 /*
    310  * shift : primary { shop primary }
    311  *
    312  */
    313 shift()
    314 {
    315         register int vl, vr, c;
    316 
    317         vl = primary();
    318         while (((c = skipws()) == '<' || c == '>') && c == getch()) {
    319                 vr = primary();
    320 
    321                 if (c == '<')
    322                         vl <<= vr;
    323                 else
    324                         vl >>= vr;
    325         }
    326 
    327         if (c == '<' || c == '>')
    328                 ungetch();
    329         ungetch();
    330         return(vl);
    331 }
    332 
    333 /*
    334  * primary : term { addop term }
    335  *
    336  */
    337 primary()
    338 {
    339         register int c, vl, vr;
    340 
    341         vl = term();
    342         while ((c = skipws()) == '+' || c == '-') {
    343                 vr = term();
    344                 if (c == '+')
    345                         vl += vr;
    346                 else
    347                         vl -= vr;
    348         }
    349 
    350         ungetch();
    351         return(vl);
    352 }
    353 
    354 /*
    355  * <term> := <unary> { <mulop> <unary> }
    356  *
    357  */
    358 term()
    359 {
    360         register int c, vl, vr;
    361 
    362         vl = unary();
    363         while ((c = skipws()) == '*' || c == '/' || c == '%') {
    364                 vr = unary();
    365 
    366                 switch (c) {
    367                 case '*':
    368                         vl *= vr;
    369                         break;
    370                 case '/':
    371                         vl /= vr;
    372                         break;
    373                 case '%':
    374                         vl %= vr;
    375                         break;
    376                 }
    377         }
    378         ungetch();
    379         return(vl);
    380 }
    381 
    382 /*
    383  * unary : factor | unop unary
    384  *
    385  */
    386 unary()
    387 {
    388         register int val, c;
    389 
    390         if ((c = skipws()) == '!' || c == '~' || c == '-') {
    391                 val = unary();
    392 
    393                 switch (c) {
    394                 case '!':
    395                         return(! val);
    396                 case '~':
    397                         return(~ val);
    398                 case '-':
    399                         return(- val);
    400                 }
    401         }
    402 
    403         ungetch();
    404         return(factor());
    405 }
    406 
    407 /*
    408  * factor : constant | '(' query ')'
    409  *
    410  */
    411 factor()
    412 {
    413         register int val;
    414 
    415         if (skipws() == '(') {
    416                 val = query();
    417                 if (skipws() != ')')
    418                         experr("Bad factor");
    419                 return(val);
    420         }
    421 
    422         ungetch();
    423         return(constant());
    424 }
    425 
    426 /*
    427  * constant: num | 'char'
    428  *
    429  */
    430 constant()
    431 {
    432         /*
    433          * Note: constant() handles multi-byte constants
    434          */
    435 
    436         register int    i;
    437         register int    value;
    438         register char   c;
    439         int             v[sizeof (int)];
    440 
    441         if (skipws() != '\'') {
    442                 ungetch();
    443                 return(num());
    444         }
    445         for (i = 0; i < sizeof(int); i++) {
    446                 if ((c = getch()) == '\'') {
    447                         ungetch();
    448                         break;
    449                 }
    450                 if (c == '\\') {
    451                         switch (c = getch()) {
    452                         case '0':
    453                         case '1':
    454                         case '2':
    455                         case '3':
    456                         case '4':
    457                         case '5':
    458                         case '6':
    459                         case '7':
    460                                 ungetch();
    461                                 c = num();
    462                                 break;
    463                         case 'n':
    464                                 c = 012;
    465                                 break;
    466                         case 'r':
    467                                 c = 015;
    468                                 break;
    469                         case 't':
    470                                 c = 011;
    471                                 break;
    472                         case 'b':
    473                                 c = 010;
    474                                 break;
    475                         case 'f':
    476                                 c = 014;
    477                                 break;
    478                         }
    479                 }
    480                 v[i] = c;
    481         }
    482         if (i == 0 || getch() != '\'')
    483                 experr("Illegal character constant");
    484         for (value = 0; --i >= 0;) {
    485                 value <<= 8;
    486                 value += v[i];
    487         }
    488         return(value);
    489 }
    490 
    491 /*
    492  * num : digit | num digit
    493  *
    494  */
    495 num()
    496 {
    497         register int rval, c, base;
    498         int ndig;
    499 
    500         base = ((c = skipws()) == '0') ? OCTAL : DECIMAL;
    501         rval = 0;
    502         ndig = 0;
    503         while (c >= '0' && c <= (base == OCTAL ? '7' : '9')) {
    504                 rval *= base;
    505                 rval += (c - '0');
    506                 c = getch();
    507                 ndig++;
    508         }
    509         ungetch();
    510         if (ndig)
    511                 return(rval);
    512         experr("Bad constant");
    513 }
    514 
    515 /*
    516  * eqlrel : '=' | '==' | '!='
    517  *
    518  */
    519 geteql()
    520 {
    521         register int c1, c2;
    522 
    523         c1 = skipws();
    524         c2 = getch();
    525 
    526         switch (c1) {
    527 
    528         case '=':
    529                 if (c2 != '=')
    530                         ungetch();
    531                 return(EQL);
    532 
    533         case '!':
    534                 if (c2 == '=')
    535                         return(NEQ);
    536                 ungetch();
    537                 ungetch();
    538                 return(-1);
    539 
    540         default:
    541                 ungetch();
    542                 ungetch();
    543                 return(-1);
    544         }
    545 }
    546 
    547 /*
    548  * rel : '<' | '>' | '<=' | '>='
    549  *
    550  */
    551 getrel()
    552 {
    553         register int c1, c2;
    554 
    555         c1 = skipws();
    556         c2 = getch();
    557 
    558         switch (c1) {
    559 
    560         case '<':
    561                 if (c2 == '=')
    562                         return(LEQ);
    563                 ungetch();
    564                 return(LSS);
    565 
    566         case '>':
    567                 if (c2 == '=')
    568                         return(GEQ);
    569                 ungetch();
    570                 return(GTR);
    571 
    572         default:
    573                 ungetch();
    574                 ungetch();
    575                 return(-1);
    576         }
    577 }
    578 
    579 /*
    580  * Skip over any white space and return terminating char.
    581  */
    582 skipws()
    583 {
    584         register char c;
    585 
    586         while ((c = getch()) <= ' ' && c > EOS)
    587                 ;
    588         return(c);
    589 }
    590 
    591 /*
    592  * Error handler - resets environment to eval(), prints an error,
    593  * and returns FALSE.
    594  */
    595 experr(msg)
    596 char *msg;
    597 {
    598         printf("mp: %s\n",msg);
    599         longjmp(expjump, -1);          /* Force eval() to return FALSE */
    600 }
    601