prettiness police
[unix-history] / usr / src / bin / test / test.c
index 2196370..a3f5539 100644 (file)
@@ -1,6 +1,6 @@
-/*
- * Copyright (c) 1988 The Regents of the University of California.
- * All rights reserved.
+/*-
+ * Copyright (c) 1992, 1993, 1994
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  *
  * This code is derived from software contributed to Berkeley by
  * Kenneth Almquist.
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-char    copyright[] =
-"@(#) Copyright (c) 1988 The Regents of the University of California.\n\
- All rights reserved.\n";
-#endif                         /* not lint */
+static char copyright[] =
+"@(#) Copyright (c) 1992, 1993, 1994\n\
      The Regents of the University of California.  All rights reserved.\n";
+#endif /* not lint */
 
 #ifndef lint
 
 #ifndef lint
-static char sccsid[] = "@(#)test.c     1.2 (Berkeley) %G%";
-#endif                         /* not lint */
+static char sccsid[] = "@(#)test.c     8.3 (Berkeley) %G%";
+#endif /* not lint */
 
 
-#include <stdio.h>
-#include <errno.h>
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <sys/types.h>
 #include <sys/stat.h>
+
+#include <ctype.h>
+#include <err.h>
+#include <errno.h>
+#include <limits.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
 #include "operators.h"
 #include "operators.h"
-#include "extern.h"
 
 
-#define STACKSIZE 12
-#define NESTINCR 16
+#define        STACKSIZE       12
+#define        NESTINCR        16
 
 /* data types */
 
 /* data types */
-#define STRING 0
-#define INTEGER 1
-#define BOOLEAN 2
-
-#define INITARGS(argv) if (argv[0] == NULL) {fputs("Argc is zero\n", stderr); exit(2);} else
+#define        STRING  0
+#define        INTEGER 1
+#define        BOOLEAN 2
 
 
-#define IS_BANG(s) (s[0] == '!' && s[1] == '\0')
-#define equal(s1, s2)   (strcmp(s1, s2) == 0)
+#define        IS_BANG(s) (s[0] == '!' && s[1] == '\0')
 
 /*
  * This structure hold a value.  The type keyword specifies the type of
  * the value, and the union u holds the value.  The value of a boolean
  * is stored in u.num (1 = TRUE, 0 = FALSE).
  */
 
 /*
  * This structure hold a value.  The type keyword specifies the type of
  * the value, and the union u holds the value.  The value of a boolean
  * is stored in u.num (1 = TRUE, 0 = FALSE).
  */
-
 struct value {
 struct value {
-       int     type;
+       int type;
        union {
        union {
-               char   *string;
-               long    num;
-       }       u;
+               char *string;
+               long num;
+       } u;
 };
 
 struct operator {
 };
 
 struct operator {
-       short   op;             /* which operator */
-       short   pri;            /* priority of operator */
+       short op;               /* Which operator. */
+       short pri;              /* Priority of operator. */
 };
 
 struct filestat {
 };
 
 struct filestat {
-       char   *name;           /* name of file */
-       int     rcode;          /* return code from stat */
-       struct stat stat;       /* status info on file */
+       char *name;             /* Name of file. */
+       int rcode;              /* Return code from stat. */
+       struct stat stat;       /* Status info on file. */
 };
 
 };
 
-static int expr_is_false __P((struct value *));
-static void expr_operator __P((int, struct value *, struct filestat *));
-static int lookup_op __P((char *, char *const *));
-static long atol __P((const char *));
-static int posix_binary_op __P((char **));
-static int posix_unary_op __P((char **));
-static int int_tcheck __P((char *));
+static int     expr_is_false __P((struct value *));
+static void    expr_operator __P((int, struct value *, struct filestat *));
+static void    get_int __P((char *, long *));
+static int     lookup_op __P((char *, const char *const *));
+static void    overflow __P((void));
+static int     posix_binary_op __P((char **));
+static int     posix_unary_op __P((char **));
+static void    syntax __P((void));
 
 int
 main(argc, argv)
 
 int
 main(argc, argv)
-       int     argc;
-       char  **argv;
+       int argc;
+       char *argv[];
 {
 {
-       char  **ap;
-       char   *opname;
-       char    c;
-       char   *p;
-       int     nest;           /* parentheses nesting */
-       int     op;
-       int     pri;
-       int     skipping;
-       int     binary;
        struct operator opstack[STACKSIZE];
        struct operator *opsp;
        struct value valstack[STACKSIZE + 1];
        struct value *valsp;
        struct filestat fs;
        struct operator opstack[STACKSIZE];
        struct operator *opsp;
        struct value valstack[STACKSIZE + 1];
        struct value *valsp;
        struct filestat fs;
-       int     ret_val;
+       char  c, **ap, *opname, *p;
+       int binary, nest, op, pri, ret_val, skipping;
+
+       if ((p = argv[0]) == NULL)
+               errx(2, "test: argc is zero");
 
 
-       INITARGS(argv);
-       if (**argv == '[') {
-               if (!equal(argv[argc - 1], "]"))
-                       error("missing ]");
-               argv[argc - 1] = NULL;
+       if (*p != '\0' && p[strlen(p) - 1] == '[') {
+               if (strcmp(argv[--argc], "]"))
+                       errx(2, "missing ]");
+               argv[argc] = NULL;
        }
        ap = argv + 1;
        fs.name = NULL;
 
        }
        ap = argv + 1;
        fs.name = NULL;
 
-       /* Test(1) implements an inherently ambiguous grammer.  In order to
-        * assure some degree of consistency, we special case the POSIX
-        * requirements to assure correct evaluation for POSIX following
-        * scripts.  The following special cases comply with POSIX
-        * P1003.2/D11.2 Section 4.62.4. */
-       switch (argc - 1) {
-       case 0:         /* % test */
-               return 1;
+       /*
+        * Test(1) implements an inherently ambiguous grammer.  In order to
+        * assure some degree of consistency, we special case the POSIX 1003.2
+        * requirements to assure correct evaluation for POSIX scripts.  The
+        * following special cases comply with POSIX P1003.2/D11.2 Section
+        * 4.62.4.
+        */
+       switch(argc - 1) {
+       case 0:                         /* % test */
+               return (1);
                break;
                break;
-       case 1:         /* % test arg */
-               return (*argv[1] == '\0') ? 1 : 0;
+       case 1:                         /* % test arg */
+               return (argv[1] == NULL || *argv[1] == '\0') ? 1 : 0;
                break;
                break;
-       case 2:         /* % test op arg */
+       case 2:                         /* % test op arg */
                opname = argv[1];
                if (IS_BANG(opname))
                opname = argv[1];
                if (IS_BANG(opname))
-                       return (*argv[2] == '\0') ? 1 : 0;
+                       return (*argv[2] == '\0') ? 0 : 1;
                else {
                        ret_val = posix_unary_op(&argv[1]);
                        if (ret_val >= 0)
                else {
                        ret_val = posix_unary_op(&argv[1]);
                        if (ret_val >= 0)
-                               return ret_val;
+                               return (ret_val);
                }
                break;
                }
                break;
-       case 3:         /* % test arg1 op arg2 */
+       case 3:                         /* % test arg1 op arg2 */
                if (IS_BANG(argv[1])) {
                        ret_val = posix_unary_op(&argv[1]);
                        if (ret_val >= 0)
                if (IS_BANG(argv[1])) {
                        ret_val = posix_unary_op(&argv[1]);
                        if (ret_val >= 0)
-                               return !ret_val;
+                               return (!ret_val);
                } else {
                        ret_val = posix_binary_op(&argv[1]);
                        if (ret_val >= 0)
                } else {
                        ret_val = posix_binary_op(&argv[1]);
                        if (ret_val >= 0)
-                               return ret_val;
+                               return (ret_val);
                }
                break;
                }
                break;
-       case 4:         /* % test ! arg1 op arg2 */
+       case 4:                         /* % test ! arg1 op arg2 */
                if (IS_BANG(argv[1])) {
                        ret_val = posix_binary_op(&argv[2]);
                        if (ret_val >= 0)
                if (IS_BANG(argv[1])) {
                        ret_val = posix_binary_op(&argv[2]);
                        if (ret_val >= 0)
-                               return !ret_val;
+                               return (!ret_val);
                }
                break;
        default:
                break;
        }
 
                }
                break;
        default:
                break;
        }
 
-       /* We use operator precedence parsing, evaluating the expression as
+       /*
+        * We use operator precedence parsing, evaluating the expression as
         * we parse it.  Parentheses are handled by bumping up the priority
         * of operators using the variable "nest."  We use the variable
         * "skipping" to turn off evaluation temporarily for the short
         * circuit boolean operators.  (It is important do the short circuit
         * evaluation because under NFS a stat operation can take infinitely
         * we parse it.  Parentheses are handled by bumping up the priority
         * of operators using the variable "nest."  We use the variable
         * "skipping" to turn off evaluation temporarily for the short
         * circuit boolean operators.  (It is important do the short circuit
         * evaluation because under NFS a stat operation can take infinitely
-        * long.) */
-
+        * long.)
+        */
        opsp = opstack + STACKSIZE;
        valsp = valstack;
        opsp = opstack + STACKSIZE;
        valsp = valstack;
-       nest = 0;
-       skipping = 0;
+       nest = skipping = 0;
        if (*ap == NULL) {
                valstack[0].type = BOOLEAN;
                valstack[0].u.num = 0;
        if (*ap == NULL) {
                valstack[0].type = BOOLEAN;
                valstack[0].u.num = 0;
@@ -165,18 +165,17 @@ main(argc, argv)
        for (;;) {
                opname = *ap++;
                if (opname == NULL)
        for (;;) {
                opname = *ap++;
                if (opname == NULL)
-                       goto syntax;
+                       syntax();
                if (opname[0] == '(' && opname[1] == '\0') {
                        nest += NESTINCR;
                        continue;
                } else if (*ap && (op = lookup_op(opname, unary_op)) >= 0) {
                        if (opsp == &opstack[0])
                if (opname[0] == '(' && opname[1] == '\0') {
                        nest += NESTINCR;
                        continue;
                } else if (*ap && (op = lookup_op(opname, unary_op)) >= 0) {
                        if (opsp == &opstack[0])
-                               goto overflow;
+                               overflow();
                        --opsp;
                        opsp->op = op;
                        opsp->pri = op_priority[op] + nest;
                        continue;
                        --opsp;
                        opsp->op = op;
                        opsp->pri = op_priority[op] + nest;
                        continue;
-
                } else {
                        valsp->type = STRING;
                        valsp->u.string = opname;
                } else {
                        valsp->type = STRING;
                        valsp->u.string = opname;
@@ -186,19 +185,19 @@ main(argc, argv)
                        opname = *ap++;
                        if (opname == NULL) {
                                if (nest != 0)
                        opname = *ap++;
                        if (opname == NULL) {
                                if (nest != 0)
-                                       goto syntax;
+                                       syntax();
                                pri = 0;
                                break;
                        }
                        if (opname[0] != ')' || opname[1] != '\0') {
                                if ((op = lookup_op(opname, binary_op)) < 0)
                                pri = 0;
                                break;
                        }
                        if (opname[0] != ')' || opname[1] != '\0') {
                                if ((op = lookup_op(opname, binary_op)) < 0)
-                                       goto syntax;
+                                       syntax();
                                op += FIRST_BINARY_OP;
                                pri = op_priority[op] + nest;
                                break;
                        }
                        if ((nest -= NESTINCR) < 0)
                                op += FIRST_BINARY_OP;
                                pri = op_priority[op] + nest;
                                break;
                        }
                        if ((nest -= NESTINCR) < 0)
-                               goto syntax;
+                               syntax();
                }
                while (opsp < &opstack[STACKSIZE] && opsp->pri >= pri) {
                        binary = opsp->op;
                }
                while (opsp < &opstack[STACKSIZE] && opsp->pri >= pri) {
                        binary = opsp->op;
@@ -206,20 +205,21 @@ main(argc, argv)
                                valsp--;
                                c = op_argflag[opsp->op];
                                if (c == OP_INT) {
                                valsp--;
                                c = op_argflag[opsp->op];
                                if (c == OP_INT) {
-                                       if (valsp->type == STRING &&
-                                           int_tcheck(valsp->u.string))
-                                               valsp->u.num =
-                                                   atol(valsp->u.string);
+                                       if (valsp->type == STRING)
+                                               get_int(valsp->u.string,
+                                                   &valsp->u.num);
                                        valsp->type = INTEGER;
                                } else if (c >= OP_STRING) {    
                                                    /* OP_STRING or OP_FILE */
                                        if (valsp->type == INTEGER) {
                                        valsp->type = INTEGER;
                                } else if (c >= OP_STRING) {    
                                                    /* OP_STRING or OP_FILE */
                                        if (valsp->type == INTEGER) {
-                                               p = stalloc(32);
+                                               if ((p = malloc(32)) == NULL)
+                                                       err(2, NULL);
 #ifdef SHELL
                                                fmtstr(p, 32, "%d", 
                                                    valsp->u.num);
 #else
 #ifdef SHELL
                                                fmtstr(p, 32, "%d", 
                                                    valsp->u.num);
 #else
-                                               sprintf(p, "%d", valsp->u.num);
+                                               (void)sprintf(p,
+                                                   "%d", valsp->u.num);
 #endif
                                                valsp->u.string = p;
                                        } else if (valsp->type == BOOLEAN) {
 #endif
                                                valsp->u.string = p;
                                        } else if (valsp->type == BOOLEAN) {
@@ -230,10 +230,8 @@ main(argc, argv)
                                                        valsp->u.string = "";
                                        }
                                        valsp->type = STRING;
                                                        valsp->u.string = "";
                                        }
                                        valsp->type = STRING;
-                                       if (c == OP_FILE
-                                           && (fs.name == NULL 
-                                               || !equal(fs.name, 
-                                                    valsp->u.string))) {
+                                       if (c == OP_FILE && (fs.name == NULL ||
+                                           strcmp(fs.name, valsp->u.string))) {
                                                fs.name = valsp->u.string;
                                                fs.rcode = 
                                                    stat(valsp->u.string, 
                                                fs.name = valsp->u.string;
                                                fs.rcode = 
                                                    stat(valsp->u.string, 
@@ -248,13 +246,13 @@ main(argc, argv)
                                expr_operator(opsp->op, valsp, &fs);
                        else if (opsp->op == AND1 || opsp->op == OR1)
                                skipping--;
                                expr_operator(opsp->op, valsp, &fs);
                        else if (opsp->op == AND1 || opsp->op == OR1)
                                skipping--;
-                       valsp++;/* push value */
-                       opsp++; /* pop operator */
+                       valsp++;                /* push value */
+                       opsp++;                 /* pop operator */
                }
                if (opname == NULL)
                        break;
                if (opsp == &opstack[0])
                }
                if (opname == NULL)
                        break;
                if (opsp == &opstack[0])
-                       goto overflow;
+                       overflow();
                if (op == AND1 || op == AND2) {
                        op = AND1;
                        if (skipping || expr_is_false(valsp - 1))
                if (op == AND1 || op == AND2) {
                        op = AND1;
                        if (skipping || expr_is_false(valsp - 1))
@@ -269,27 +267,22 @@ main(argc, argv)
                opsp->op = op;
                opsp->pri = pri;
        }
                opsp->op = op;
                opsp->pri = pri;
        }
-done:
-       return expr_is_false(&valstack[0]);
-
-syntax:   error("syntax error");
-overflow: error("Expression too complex");
-
+done:  return (expr_is_false(&valstack[0]));
 }
 
 }
 
-
 static int
 expr_is_false(val)
        struct value *val;
 {
 static int
 expr_is_false(val)
        struct value *val;
 {
+
        if (val->type == STRING) {
                if (val->u.string[0] == '\0')
        if (val->type == STRING) {
                if (val->u.string[0] == '\0')
-                       return 1;
+                       return (1);
        } else {                /* INTEGER or BOOLEAN */
                if (val->u.num == 0)
        } else {                /* INTEGER or BOOLEAN */
                if (val->u.num == 0)
-                       return 1;
+                       return (1);
        }
        }
-       return 0;
+       return (0);
 }
 
 
 }
 
 
@@ -301,14 +294,13 @@ expr_is_false(val)
  * Fs is a pointer to a structure which holds the value of the last call
  * to stat, to avoid repeated stat calls on the same file.
  */
  * Fs is a pointer to a structure which holds the value of the last call
  * to stat, to avoid repeated stat calls on the same file.
  */
-
 static void
 expr_operator(op, sp, fs)
 static void
 expr_operator(op, sp, fs)
-       int     op;
+       int op;
        struct value *sp;
        struct filestat *fs;
 {
        struct value *sp;
        struct filestat *fs;
 {
-       int     i;
+       int i;
 
        switch (op) {
        case NOT:
 
        switch (op) {
        case NOT:
@@ -321,15 +313,14 @@ expr_operator(op, sp, fs)
                else
                        goto true;
        case ISREAD:
                else
                        goto true;
        case ISREAD:
-               i = 04;
+               i = S_IROTH;
                goto permission;
        case ISWRITE:
                goto permission;
        case ISWRITE:
-               i = 02;
+               i = S_IWOTH;
                goto permission;
        case ISEXEC:
                goto permission;
        case ISEXEC:
-               i = 01;
-permission:
-               if (fs->stat.st_uid == geteuid())
+               i = S_IXOTH;
+permission:    if (fs->stat.st_uid == geteuid())
                        i <<= 6;
                else if (fs->stat.st_gid == getegid())
                        i <<= 3;
                        i <<= 6;
                else if (fs->stat.st_gid == getegid())
                        i <<= 3;
@@ -346,21 +337,17 @@ permission:
        case ISBLOCK:
                i = S_IFBLK;
                goto filetype;
        case ISBLOCK:
                i = S_IFBLK;
                goto filetype;
+       case ISSYMLINK:
+               i = S_IFLNK;
+               (void)lstat(sp->u.string, &fs->stat);
+               goto filetype;
        case ISFIFO:
        case ISFIFO:
-#ifdef S_IFIFO
                i = S_IFIFO;
                goto filetype;
                i = S_IFIFO;
                goto filetype;
-#else
-               goto false;
-#endif
-filetype:
-               if ((fs->stat.st_mode & S_IFMT) == i && fs->rcode >= 0) {
-       true:
-                       sp->u.num = 1;
-               } else {
-       false:
-                       sp->u.num = 0;
-               }
+filetype:      if ((fs->stat.st_mode & S_IFMT) == i && fs->rcode >= 0)
+true:                  sp->u.num = 1;
+               else
+false:                 sp->u.num = 0;
                sp->type = BOOLEAN;
                break;
        case ISSETUID:
                sp->type = BOOLEAN;
                break;
        case ISSETUID:
@@ -371,8 +358,7 @@ filetype:
                goto filebit;
        case ISSTICKY:
                i = S_ISVTX;
                goto filebit;
        case ISSTICKY:
                i = S_ISVTX;
-filebit:
-               if (fs->stat.st_mode & i && fs->rcode >= 0)
+filebit:       if (fs->stat.st_mode & i && fs->rcode >= 0)
                        goto true;
                goto false;
        case ISSIZE:
                        goto true;
                goto false;
        case ISSIZE:
@@ -393,15 +379,17 @@ filebit:
                break;
        case OR1:
        case AND1:
                break;
        case OR1:
        case AND1:
-               /* These operators are mostly handled by the parser.  If we
+               /*
+                * These operators are mostly handled by the parser.  If we
                 * get here it means that both operands were evaluated, so
                 * get here it means that both operands were evaluated, so
-                * the value is the value of the second operand. */
+                * the value is the value of the second operand.
+                */
                *sp = *(sp + 1);
                break;
        case STREQ:
        case STRNE:
                i = 0;
                *sp = *(sp + 1);
                break;
        case STREQ:
        case STRNE:
                i = 0;
-               if (equal(sp->u.string, (sp + 1)->u.string))
+               if (!strcmp(sp->u.string, (sp + 1)->u.string))
                        i++;
                if (op == STRNE)
                        i = 1 - i;
                        i++;
                if (op == STRNE)
                        i = 1 - i;
@@ -436,35 +424,34 @@ filebit:
        }
 }
 
        }
 }
 
-
 static int
 lookup_op(name, table)
 static int
 lookup_op(name, table)
-       char   *name;
-       char   *const * table;
+       char *name;
+       const char *const * table;
 {
 {
-       register char *const * tp;
-       register char const *p;
-       char    c = name[1];
-
-       for (tp = table; (p = *tp) != NULL; tp++) {
-               if (p[1] == c && equal(p, name))
-                       return tp - table;
-       }
-       return -1;
+       const char *const * tp;
+       const char *p;
+       char c;
+
+       c = name[1];
+       for (tp = table; (p = *tp) != NULL; tp++)
+               if (p[1] == c && !strcmp(p, name))
+                       return (tp - table);
+       return (-1);
 }
 
 static int
 posix_unary_op(argv)
 }
 
 static int
 posix_unary_op(argv)
-       char  **argv;
+       char **argv;
 {
 {
-       int     op, c;
-       char   *opname;
        struct filestat fs;
        struct value valp;
        struct filestat fs;
        struct value valp;
+       int op, c;
+       char *opname;
 
        opname = *argv;
        if ((op = lookup_op(opname, unary_op)) < 0)
 
        opname = *argv;
        if ((op = lookup_op(opname, unary_op)) < 0)
-               return -1;
+               return (-1);
        c = op_argflag[op];
        opname = argv[1];
        valp.u.string = opname;
        c = op_argflag[op];
        opname = argv[1];
        valp.u.string = opname;
@@ -472,30 +459,32 @@ posix_unary_op(argv)
                fs.name = opname;
                fs.rcode = stat(opname, &fs.stat);
        } else if (c != OP_STRING)
                fs.name = opname;
                fs.rcode = stat(opname, &fs.stat);
        } else if (c != OP_STRING)
-               return -1;
+               return (-1);
 
        expr_operator(op, &valp, &fs);
        return (valp.u.num == 0);
 }
 
 
        expr_operator(op, &valp, &fs);
        return (valp.u.num == 0);
 }
 
-
 static int
 posix_binary_op(argv)
        char  **argv;
 {
 static int
 posix_binary_op(argv)
        char  **argv;
 {
-       int     op, c;
-       char   *opname;
        struct value v[2];
        struct value v[2];
+       int op, c;
+       char *opname;
 
        opname = argv[1];
        if ((op = lookup_op(opname, binary_op)) < 0)
 
        opname = argv[1];
        if ((op = lookup_op(opname, binary_op)) < 0)
-               return -1;
+               return (-1);
        op += FIRST_BINARY_OP;
        c = op_argflag[op];
 
        op += FIRST_BINARY_OP;
        c = op_argflag[op];
 
-       if (c == OP_INT && int_tcheck(argv[0]) && int_tcheck(argv[2])) {
-               v[0].u.num = atol(argv[0]);
-               v[1].u.num = atol(argv[2]);
+       if (c == OP_INT) {
+               get_int(argv[0], &v[0].u.num);
+               get_int(argv[2], &v[1].u.num);
+       } else {
+               v[0].u.string = argv[0];
+               v[1].u.string = argv[2];
        }
        expr_operator(op, v, NULL);
        return (v[0].u.num == 0);
        }
        expr_operator(op, v, NULL);
        return (v[0].u.num == 0);
@@ -504,18 +493,42 @@ posix_binary_op(argv)
 /*
  * Integer type checking.
  */
 /*
  * Integer type checking.
  */
-static int
-int_tcheck(v)
-       char   *v;
+static void
+get_int(v, lp)
+       char *v;
+       long *lp;
 {
 {
-       char   *p;
-       char    outbuf[512];
-
-       for (p = v; *p != '\0'; p++)
-               if (*p < '0' || *p > '9') {
-                       snprintf(outbuf, sizeof(outbuf),
-                         "Illegal operand \"%s\" -- expected integer.", v);
-                       error(outbuf);
+       long val;
+       char *ep;
+
+       for (; *v && isspace(*v); ++v);
+       if (isdigit(*v)) {
+               errno = 0;
+               val = strtol(v, &ep, 10);
+               if (*ep != '\0')
+                       errx(2, "%s: trailing non-numeric characters", v);
+               if (errno == ERANGE) {
+                       if (val == LONG_MIN)
+                               errx(2, "%s: underflow", v);
+                       if (val == LONG_MAX)
+                               errx(2, "%s: overflow", v);
                }
                }
-       return 1;
+               *lp = val;
+               return;
+       }
+       errx(2, "%s: expected integer", v);
+}
+
+static void
+syntax()
+{
+
+       err(2, "syntax error");
+}
+
+static void
+overflow()
+{
+
+       err(2, "expression is too complex");
 }
 }