[BACK]Return to expr.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / m4

Diff for /src/usr.bin/m4/expr.c between version 1.15 and 1.16

version 1.15, 2003/06/03 02:56:10 version 1.16, 2004/05/12 21:17:03
Line 1 
Line 1 
 /*      $OpenBSD$       */  /* $OpenBSD$ */
 /*      $NetBSD: expr.c,v 1.7 1995/09/28 05:37:31 tls Exp $     */  
   
 /*  /*
  * Copyright (c) 1989, 1993   * Copyright (c) 2004 Marc Espie <espie@cvs.openbsd.org>
  *      The Regents of the University of California.  All rights reserved.  
  *   *
  * This code is derived from software contributed to Berkeley by   * Permission to use, copy, modify, and distribute this software for any
  * Ozan Yigit at York University.   * purpose with or without fee is hereby granted, provided that the above
    * copyright notice and this permission notice appear in all copies.
  *   *
  * Redistribution and use in source and binary forms, with or without   * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
  * modification, are permitted provided that the following conditions   * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
  * are met:   * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
  * 1. Redistributions of source code must retain the above copyright   * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
  *    notice, this list of conditions and the following disclaimer.   * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
  * 2. Redistributions in binary form must reproduce the above copyright   * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  *    notice, this list of conditions and the following disclaimer in the   * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  *    documentation and/or other materials provided with the distribution.  
  * 3. Neither the name of the University nor the names of its contributors  
  *    may be used to endorse or promote products derived from this software  
  *    without specific prior written permission.  
  *  
  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND  
  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE  
  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE  
  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE  
  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL  
  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS  
  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)  
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT  
  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY  
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF  
  * SUCH DAMAGE.  
  */   */
   #include <sys/types.h>
 #ifndef lint  
 #if 0  
 static char sccsid[] = "@(#)expr.c      8.2 (Berkeley) 4/29/95";  
 #else  
 static char rcsid[] = "$OpenBSD$";  
 #endif  
 #endif /* not lint */  
   
 #include <sys/cdefs.h>  
 #include <ctype.h>  
 #include <err.h>  
 #include <stddef.h>  
 #include <stdio.h>  #include <stdio.h>
   #include <stddef.h>
 #include "mdef.h"  #include "mdef.h"
 #include "extern.h"  #include "extern.h"
   
 /*  int32_t end_result;
  *      expression evaluator: performs a standard recursive  const char *copy_toeval;
  *      descent parse to evaluate any expression permissible  
  *      within the following grammar:  
  *  
  *      expr    :       query EOS  
  *      query   :       lor  
  *              |       lor "?" query ":" query  
  *      lor     :       land { "||" land }  
  *      land    :       not { "&&" not }  
  *      not     :       eqrel  
  *              |       '!' not  
  *      eqrel   :       shift { eqrelop shift }  
  *      shift   :       primary { shop primary }  
  *      primary :       term { addop term }  
  *      term    :       exp { mulop exp }  
  *      exp     :       unary { expop unary }  
  *      unary   :       factor  
  *              |       unop unary  
  *      factor  :       constant  
  *              |       "(" query ")"  
  *      constant:       num  
  *              |       "'" CHAR "'"  
  *      num     :       DIGIT  
  *              |       DIGIT num  
  *      shop    :       "<<"  
  *              |       ">>"  
  *      eqrel   :       "="  
  *              |       "=="  
  *              |       "!="  
  *              |       "<"  
  *              |       ">"  
  *              |       "<="  
  *              |       ">="  
  *  
  *  
  *      This expression evaluator is lifted from a public-domain  
  *      C Pre-Processor included with the DECUS C Compiler distribution.  
  *      It is hacked somewhat to be suitable for m4.  
  *  
  *      Originally by:  Mike Lutz  
  *                      Bob Harper  
  */  
   
 #define EQL     0  extern void yy_scan_string(const char *);
 #define NEQ     1  extern int yyparse(void);
 #define LSS     2  
 #define LEQ     3  
 #define GTR     4  
 #define GEQ     5  
 #define OCTAL   8  
 #define DECIMAL 10  
 #define HEX     16  
   
 static const char *nxtch;                      /* Parser scan pointer */  
 static const char *where;  
   
 static int query(void);  
 static int lor(void);  
 static int land(void);  
 static int not(void);  
 static int eqrel(void);  
 static int shift(void);  
 static int primary(void);  
 static int term(void);  
 static int exp(void);  
 static int unary(void);  
 static int factor(void);  
 static int constant(void);  
 static int num(void);  
 static int geteqrel(void);  
 static int skipws(void);  
 static void experr(const char *);  
   
 /*  
  * For longjmp  
  */  
 #include <setjmp.h>  
 static jmp_buf expjump;  
   
 /*  
  * macros:  
  *      ungetch - Put back the last character examined.  
  *      getch   - return the next character from expr string.  
  */  
 #define ungetch()       nxtch--  
 #define getch()         *nxtch++  
   
 int  int
 expr(const char *expbuf)  yyerror(const char *msg)
 {  {
         int rval;          fprintf(stderr, "m4: %s in expr %s\n", msg, copy_toeval);
           return(0);
         nxtch = expbuf;  
         where = expbuf;  
         if (setjmp(expjump) != 0)  
                 return FALSE;  
   
         rval = query();  
         if (skipws() == EOS)  
                 return rval;  
   
         printf("m4: ill-formed expression.\n");  
         return FALSE;  
 }  }
   
 /*  int
  * query : lor | lor '?' query ':' query  expr(const char *toeval)
  */  
 static int  
 query()  
 {  {
         int result, true_val, false_val;          copy_toeval = toeval;
           yy_scan_string(toeval);
         result = lor();          yyparse();
         if (skipws() != '?') {          return end_result;
                 ungetch();  
                 return result;  
         }  
   
         true_val = query();  
         if (skipws() != ':')  
                 experr("bad query");  
   
         false_val = query();  
         return result ? true_val : false_val;  
 }  
   
 /*  
  * lor : land { '||' land }  
  */  
 static int  
 lor()  
 {  
         int c, vl, vr;  
   
         vl = land();  
         while ((c = skipws()) == '|') {  
                 if (getch() != '|')  
                         ungetch();  
                 vr = land();  
                 vl = vl || vr;  
         }  
   
         ungetch();  
         return vl;  
 }  
   
 /*  
  * land : not { '&&' not }  
  */  
 static int  
 land()  
 {  
         int c, vl, vr;  
   
         vl = not();  
         while ((c = skipws()) == '&') {  
                 if (getch() != '&')  
                         ungetch();  
                 vr = not();  
                 vl = vl && vr;  
         }  
   
         ungetch();  
         return vl;  
 }  
   
 /*  
  * not : eqrel | '!' not  
  */  
 static int  
 not()  
 {  
         int val, c;  
   
         if ((c = skipws()) == '!' && getch() != '=') {  
                 ungetch();  
                 val = not();  
                 return !val;  
         }  
   
         if (c == '!')  
                 ungetch();  
         ungetch();  
         return eqrel();  
 }  
   
 /*  
  * eqrel : shift { eqrelop shift }  
  */  
 static int  
 eqrel()  
 {  
         int vl, vr, eqrel;  
   
         vl = shift();  
         while ((eqrel = geteqrel()) != -1) {  
                 vr = shift();  
   
                 switch (eqrel) {  
   
                 case EQL:  
                         vl = (vl == vr);  
                         break;  
                 case NEQ:  
                         vl = (vl != vr);  
                         break;  
   
                 case LEQ:  
                         vl = (vl <= vr);  
                         break;  
                 case LSS:  
                         vl = (vl < vr);  
                         break;  
                 case GTR:  
                         vl = (vl > vr);  
                         break;  
                 case GEQ:  
                         vl = (vl >= vr);  
                         break;  
                 }  
         }  
         return vl;  
 }  
   
 /*  
  * shift : primary { shop primary }  
  */  
 static int  
 shift()  
 {  
         int vl, vr, c;  
   
         vl = primary();  
         while (((c = skipws()) == '<' || c == '>') && getch() == c) {  
                 vr = primary();  
   
                 if (c == '<')  
                         vl <<= vr;  
                 else  
                         vl >>= vr;  
         }  
   
         if (c == '<' || c == '>')  
                 ungetch();  
         ungetch();  
         return vl;  
 }  
   
 /*  
  * primary : term { addop term }  
  */  
 static int  
 primary()  
 {  
         int c, vl, vr;  
   
         vl = term();  
         while ((c = skipws()) == '+' || c == '-') {  
                 vr = term();  
   
                 if (c == '+')  
                         vl += vr;  
                 else  
                         vl -= vr;  
         }  
   
         ungetch();  
         return vl;  
 }  
   
 /*  
  * <term> := <exp> { <mulop> <exp> }  
  */  
 static int  
 term()  
 {  
         int c, vl, vr;  
   
         vl = exp();  
         while ((c = skipws()) == '*' || c == '/' || c == '%') {  
                 vr = exp();  
   
                 switch (c) {  
                 case '*':  
                         vl *= vr;  
                         break;  
                 case '/':  
                         if (vr == 0)  
                                 errx(1, "division by zero in eval.");  
                         else  
                                 vl /= vr;  
                         break;  
                 case '%':  
                         if (vr == 0)  
                                 errx(1, "modulo zero in eval.");  
                         else  
                                 vl %= vr;  
                         break;  
                 }  
         }  
         ungetch();  
         return vl;  
 }  
   
 /*  
  * <term> := <unary> { <expop> <unary> }  
  */  
 static int  
 exp()  
 {  
         int c, vl, vr, n;  
   
         vl = unary();  
         switch (c = skipws()) {  
   
         case '*':  
                 if (getch() != '*') {  
                         ungetch();  
                         break;  
                 }  
   
         case '^':  
                 vr = exp();  
                 n = 1;  
                 while (vr-- > 0)  
                         n *= vl;  
                 return n;  
         }  
   
         ungetch();  
         return vl;  
 }  
   
 /*  
  * unary : factor | unop unary  
  */  
 static int  
 unary()  
 {  
         int val, c;  
   
         if ((c = skipws()) == '+' || c == '-' || c == '~') {  
                 val = unary();  
   
                 switch (c) {  
                 case '+':  
                         return val;  
                 case '-':  
                         return -val;  
                 case '~':  
                         return ~val;  
                 }  
         }  
   
         ungetch();  
         return factor();  
 }  
   
 /*  
  * factor : constant | '(' query ')'  
  */  
 static int  
 factor()  
 {  
         int val;  
   
         if (skipws() == '(') {  
                 val = query();  
                 if (skipws() != ')')  
                         experr("bad factor");  
                 return val;  
         }  
   
         ungetch();  
         return constant();  
 }  
   
 /*  
  * constant: num | 'char'  
  * Note: constant() handles multi-byte constants  
  */  
 static int  
 constant()  
 {  
         int i;  
         int value;  
         int c;  
         int v[sizeof(int)];  
   
         if (skipws() != '\'') {  
                 ungetch();  
                 return num();  
         }  
         for (i = 0; i < sizeof(int); i++) {  
                 if ((c = getch()) == '\'') {  
                         ungetch();  
                         break;  
                 }  
                 if (c == '\\') {  
                         switch (c = getch()) {  
                         case '0':  
                         case '1':  
                         case '2':  
                         case '3':  
                         case '4':  
                         case '5':  
                         case '6':  
                         case '7':  
                                 ungetch();  
                                 c = num();  
                                 break;  
                         case 'n':  
                                 c = 012;  
                                 break;  
                         case 'r':  
                                 c = 015;  
                                 break;  
                         case 't':  
                                 c = 011;  
                                 break;  
                         case 'b':  
                                 c = 010;  
                                 break;  
                         case 'f':  
                                 c = 014;  
                                 break;  
                         }  
                 }  
                 v[i] = c;  
         }  
         if (i == 0 || getch() != '\'')  
                 experr("illegal character constant");  
         for (value = 0; --i >= 0;) {  
                 value <<= 8;  
                 value += v[i];  
         }  
         return value;  
 }  
   
 /*  
  * num : digit | num digit  
  */  
 static int  
 num()  
 {  
         int rval, c, base;  
         int ndig;  
   
         rval = 0;  
         ndig = 0;  
         c = skipws();  
         if (c == '0') {  
                 c = skipws();  
                 if (c == 'x' || c == 'X') {  
                         base = HEX;  
                         c = skipws();  
                 } else {  
                         base = OCTAL;  
                         ndig++;  
                 }  
         } else  
                 base = DECIMAL;  
         for(;;) {  
                 switch(c) {  
                         case '8': case '9':  
                                 if (base == OCTAL)  
                                         goto bad_digit;  
                                 /*FALLTHRU*/  
                         case '0': case '1': case '2': case '3':  
                         case '4': case '5': case '6': case '7':  
                                 rval *= base;  
                                 rval += c - '0';  
                                 break;  
                         case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':  
                                 c = tolower(c);  
                         case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':  
                                 if (base == HEX) {  
                                         rval *= base;  
                                         rval += c - 'a' + 10;  
                                         break;  
                                 }  
                                 /*FALLTHRU*/  
                         default:  
                                 goto bad_digit;  
                 }  
                 c = getch();  
                 ndig++;  
         }  
 bad_digit:  
         ungetch();  
   
         if (ndig == 0)  
                 experr("bad constant");  
   
         return rval;  
 }  
   
 /*  
  * eqrel : '=' | '==' | '!=' | '<' | '>' | '<=' | '>='  
  */  
 static int  
 geteqrel()  
 {  
         int c1, c2;  
   
         c1 = skipws();  
         c2 = getch();  
   
         switch (c1) {  
   
         case '=':  
                 if (c2 != '=')  
                         ungetch();  
                 return EQL;  
   
         case '!':  
                 if (c2 == '=')  
                         return NEQ;  
                 ungetch();  
                 ungetch();  
                 return -1;  
   
         case '<':  
                 if (c2 == '=')  
                         return LEQ;  
                 ungetch();  
                 return LSS;  
   
         case '>':  
                 if (c2 == '=')  
                         return GEQ;  
                 ungetch();  
                 return GTR;  
   
         default:  
                 ungetch();  
                 ungetch();  
                 return -1;  
         }  
 }  
   
 /*  
  * Skip over any white space and return terminating char.  
  */  
 static int  
 skipws()  
 {  
         int c;  
   
         while ((c = getch()) <= ' ' && c > EOS)  
                 ;  
         return c;  
 }  
   
 /*  
  * resets environment to eval(), prints an error  
  * and forces eval to return FALSE.  
  */  
 static void  
 experr(const char *msg)  
 {  
         printf("m4: %s in expr %s.\n", msg, where);  
         longjmp(expjump, -1);  
 }  }

Legend:
Removed from v.1.15  
changed lines
  Added in v.1.16