m4: Sync with FreeBSD.
[dragonfly.git] / usr.bin / m4 / expr.c
index 18129ba..1556277 100644 (file)
-/*     $OpenBSD: expr.c,v 1.14 2002/04/26 16:15:16 espie Exp $ */
-/*     $NetBSD: expr.c,v 1.7 1995/09/28 05:37:31 tls Exp $     */
-
+/* $OpenBSD: expr.c,v 1.18 2010/09/07 19:58:09 marco Exp $ */
 /*
- * Copyright (c) 1989, 1993
- *     The Regents of the University of California.  All rights reserved.
- *
- * This code is derived from software contributed to Berkeley by
- * Ozan Yigit at York University.
+ * Copyright (c) 2004 Marc Espie <espie@cvs.openbsd.org>
  *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *     This product includes software developed by the University of
- *     California, Berkeley and its contributors.
- * 4. 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.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
  *
- * 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.
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  *
- * @(#)expr.c  8.2 (Berkeley) 4/29/95
- * $OpenBSD: expr.c,v 1.14 2002/04/26 16:15:16 espie Exp $
- * $FreeBSD: src/usr.bin/m4/expr.c,v 1.14 2004/05/01 03:59:43 smkelly Exp $
- * $DragonFly: src/usr.bin/m4/expr.c,v 1.4 2006/12/27 21:29:02 pavalos Exp $
+ * $FreeBSD: src/usr.bin/m4/expr.c,v 1.19 2012/11/17 01:54:24 svnexp Exp $
  */
 
-#include <sys/types.h>
-#include <ctype.h>
-#include <err.h>
-#include <stddef.h>
+#include <stdint.h>
 #include <stdio.h>
+#include <stddef.h>
 #include "mdef.h"
 #include "extern.h"
 
-/*
- *      expression evaluator: performs a standard recursive
- *      descent parse to evaluate any expression permissible
- *      within the following grammar:
- *
- *      expr    :       query EOS
- *      query   :       lor
- *              |       lor "?" query ":" query
- *      lor     :       land { "||" land }
- *      land    :       bor { "&&" bor }
- *      bor     :       xor { "|" xor }
- *      xor     :       band { "^" eqrel }
- *      band    :       eqrel { "&" eqrel }
- *      eqrel   :       nerel { ("==" | "!=") nerel }
- *      nerel   :       shift { ("<" | ">" | "<=" | ">=") shift }
- *      shift   :       primary { ("<<" | ">>") primary }
- *      primary :       term { ("+" | "-") term }
- *      term    :       exp { ("*" | "/" | "%") exp }
- *      exp     :       unary { "**" unary }
- *      unary   :       factor
- *              |       ("+" | "-" | "~" | "!") unary
- *      factor  :       constant
- *              |       "(" query ")"
- *      constant:       num
- *              |       "'" CHAR "'"
- *      num     :       DIGIT
- *              |       DIGIT num
- *
- *
- *      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
-#define NEQ     1
-#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;
+int32_t end_result;
+static const char *copy_toeval;
+int yyerror(const char *msg);
 
-static int query(int mayeval);
-static int lor(int mayeval);
-static int land(int mayeval);
-static int bor(int mayeval);
-static int xor(int mayeval);
-static int band(int mayeval);
-static int eqrel(int mayeval);
-static int nerel(int mayeval);
-static int shift(int mayeval);
-static int primary(int mayeval);
-static int term(int mayeval);
-static int expx(int mayeval);
-static int unary(int mayeval);
-static int factor(int mayeval);
-static int constant(int mayeval);
-static int num(int mayeval);
-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++
+extern void yy_scan_string(const char *);
+extern int yyparse(void);
 
 int
-expr(const char *expbuf)
+yyerror(const char *msg)
 {
-       int rval;
-
-       nxtch = expbuf;
-       where = expbuf;
-       if (setjmp(expjump) != 0)
-               return FALSE;
-
-       rval = query(1);
-       if (skipws() == EOS)
-               return rval;
-
-       printf("m4: ill-formed expression.\n");
-       return FALSE;
-}
-
-/*
- * query : lor | lor '?' query ':' query
- */
-static int
-query(int mayeval)
-{
-       int result, true_val, false_val;
-
-       result = lor(mayeval);
-       if (skipws() != '?') {
-               ungetch();
-               return result;
-       }
-
-       true_val = query(result);
-       if (skipws() != ':')
-               experr("bad query: missing \":\"");
-
-       false_val = query(!result);
-       return result ? true_val : false_val;
-}
-
-/*
- * lor : land { '||' land }
- */
-static int
-lor(int mayeval)
-{
-       int c, vl, vr;
-
-       vl = land(mayeval);
-       while ((c = skipws()) == '|') {
-               if (getch() != '|') {
-                       ungetch();
-                       break;
-               }
-               if (vl != 0)
-                       mayeval = 0;
-               vr = land(mayeval);
-               vl = vl || vr;
-       }
-
-       ungetch();
-       return vl;
+       fprintf(stderr, "m4: %s in expr %s\n", msg, copy_toeval);
+       return(0);
 }
 
-/*
- * land : not { '&&' not }
- */
-static int
-land(int mayeval)
-{
-       int c, vl, vr;
-
-       vl = bor(mayeval);
-       while ((c = skipws()) == '&') {
-               if (getch() != '&') {
-                       ungetch();
-                       break;
-               }
-               if (vl == 0)
-                       mayeval = 0;
-               vr = bor(mayeval);
-               vl = vl && vr;
-       }
-
-       ungetch();
-       return vl;
-}
-
-/*
- * bor : xor { "|" xor }
- */
-static int
-bor(int mayeval)
-{
-       int vl, vr, c, cr;
-
-       vl = xor(mayeval);
-       while ((c = skipws()) == '|') {
-               cr = getch();
-               ungetch();
-               if (cr == '|')
-                       break;
-               vr = xor(mayeval);
-               vl |= vr;
-       }
-       ungetch();
-       return (vl);
-}
-
-/*
- * xor : band { "^" band }
- */
-static int
-xor(int mayeval)
-{
-       int vl, vr, c;
-
-       vl = band(mayeval);
-       while ((c = skipws()) == '^') {
-               vr = band(mayeval);
-               vl ^= vr;
-       }
-       ungetch();
-       return (vl);
-}
-
-/*
- * band : eqrel { "&" eqrel }
- */
-static int
-band(int mayeval)
-{
-       int c, cr, vl, vr;
-
-       vl = eqrel(mayeval);
-       while ((c = skipws()) == '&') {
-               cr = getch();
-               ungetch();
-               if (cr == '&')
-                       break;
-               vr = eqrel(mayeval);
-               vl &= vr;
-       }
-       ungetch();
-       return vl;
-}
-
-/*
- * eqrel : nerel { ("==" | "!=" ) nerel }
- */
-static int
-eqrel(int mayeval)
-{
-       int vl, vr, c, cr;
-
-       vl = nerel(mayeval);
-       while ((c = skipws()) == '!' || c == '=') {
-               if ((cr = getch()) != '=') {
-                       ungetch();
-                       break;
-               }
-               vr = nerel(mayeval);
-               switch (c) {
-               case '=':
-                       vl = (vl == vr);
-                       break;
-               case '!':
-                       vl = (vl != vr);
-                       break;
-               }
-       }
-       ungetch();
-       return vl;
-}
-
-/*
- * nerel : shift { ("<=" | ">=" | "<" | ">") shift }
- */
-static int
-nerel(int mayeval)
-{
-       int vl, vr, c, cr;
-
-       vl = shift(mayeval);
-       while ((c = skipws()) == '<' || c == '>') {
-               if ((cr = getch()) != '=') {
-                       ungetch();
-                       cr = '\0';
-               }
-               vr = shift(mayeval);
-               switch (c) {
-               case '<':
-                       vl = (cr == '\0') ? (vl < vr) : (vl <= vr);
-                       break;
-               case '>':
-                       vl = (cr == '\0') ? (vl > vr) : (vl >= vr);
-                       break;
-               }
-       }
-       ungetch();
-       return vl;
-}
-
-/*
- * shift : primary { ("<<" | ">>") primary }
- */
-static int
-shift(int mayeval)
-{
-       int vl, vr, c;
-
-       vl = primary(mayeval);
-       while (((c = skipws()) == '<' || c == '>') && getch() == c) {
-               vr = primary(mayeval);
-
-               if (c == '<')
-                       vl <<= vr;
-               else
-                       vl >>= vr;
-       }
-
-       if (c == '<' || c == '>')
-               ungetch();
-       ungetch();
-       return vl;
-}
-
-/*
- * primary : term { ("+" | "-") term }
- */
-static int
-primary(int mayeval)
-{
-       int c, vl, vr;
-
-       vl = term(mayeval);
-       while ((c = skipws()) == '+' || c == '-') {
-               vr = term(mayeval);
-
-               if (c == '+')
-                       vl += vr;
-               else
-                       vl -= vr;
-       }
-
-       ungetch();
-       return vl;
-}
-
-/*
- * term : exp { ("*" | "/" | "%") exp }
- */
-static int
-term(int mayeval)
-{
-       int c, vl, vr;
-
-       vl = expx(mayeval);
-       while ((c = skipws()) == '*' || c == '/' || c == '%') {
-               vr = expx(mayeval);
-
-               switch (c) {
-               case '*':
-                       vl *= vr;
-                       break;
-               case '/':
-                       if (!mayeval)
-                               /* short-circuit */;
-                       else if (vr == 0)
-                               errx(1, "division by zero in eval.");
-                       else
-                               vl /= vr;
-                       break;
-               case '%':
-                       if (!mayeval)
-                               /* short-circuit */;
-                       else if (vr == 0)
-                               errx(1, "modulo zero in eval.");
-                       else
-                               vl %= vr;
-                       break;
-               }
-       }
-       ungetch();
-       return vl;
-}
-
-/*
- * exp : unary { "**" exp }
- */
-static int
-expx(int mayeval)
-{
-       int c, vl, vr, n;
-
-       vl = unary(mayeval);
-       while ((c = skipws()) == '*') {
-               if (getch() != '*') {
-                       ungetch();
-                       break;
-               }
-               vr = unary(mayeval);
-               n = 1;
-               while (vr-- > 0)
-                       n *= vl;
-               return n;
-       }
-
-       ungetch();
-       return vl;
-}
-
-/*
- * unary : factor | ("+" | "-" | "~" | "!") unary
- */
-static int
-unary(int mayeval)
-{
-       int val, c;
-
-       if ((c = skipws()) == '+' || c == '-' || c == '~' || c == '!') {
-               val = unary(mayeval);
-
-               switch (c) {
-               case '+':
-                       return val;
-               case '-':
-                       return -val;
-               case '~':
-                       return ~val;
-               case '!':
-                       return !val;
-               }
-       }
-
-       ungetch();
-       return factor(mayeval);
-}
-
-/*
- * factor : constant | '(' query ')'
- */
-static int
-factor(int mayeval)
-{
-       int val;
-
-       if (skipws() == '(') {
-               val = query(mayeval);
-               if (skipws() != ')')
-                       experr("bad factor: missing \")\"");
-               return val;
-       }
-
-       ungetch();
-       return constant(mayeval);
-}
-
-/*
- * constant: num | 'char'
- * Note: constant() handles multi-byte constants
- */
-static int
-constant(int mayeval)
-{
-       int i;
-       int value;
-       int c;
-       int v[sizeof(int)];
-
-       if (skipws() != '\'') {
-               ungetch();
-               return num(mayeval);
-       }
-       for (i = 0; i < (ssize_t)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(mayeval);
-                               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 mayeval __unused)
-{
-       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;
-}
-
-/*
- * Skip over any white space and return terminating char.
- */
-static int
-skipws(void)
-{
-       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)
+int
+expr(const char *toeval)
 {
-       printf("m4: %s in expr %s.\n", msg, where);
-       longjmp(expjump, -1);
+       copy_toeval = toeval;
+       yy_scan_string(toeval);
+       yyparse();
+       return end_result;
 }