1 /* expr -- evaluate expressions.
2 Copyright (C) 86, 91, 92, 93, 94, 1995 Free Software Foundation, Inc.
4 This program is free software; you can redistribute it and/or modify
5 it under the terms of the GNU General Public License as published by
6 the Free Software Foundation; either version 2, or (at your option)
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 GNU General Public License for more details.
14 You should have received a copy of the GNU General Public License
15 along with this program; if not, write to the Free Software
16 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
18 /* Author: Mike Parker.
20 This program evaluates expressions. Each token (operator, operand,
21 parenthesis) of the expression must be a seperate argument. The
22 parser used is a reasonably general one, though any incarnation of
23 it is language-specific. It is especially nice for expressions.
25 No parse tree is needed; a new node is evaluated immediately.
26 One function can handle multiple operators all of equal precedence,
27 provided they all associate ((x op x) op x).
29 Define EVAL_TRACE to print an evaluation trace. */
33 #include <sys/types.h>
38 #include "long-options.h"
41 #define NEW(type) ((type *) xmalloc (sizeof (type)))
42 #define OLD(x) free ((char *) x)
44 /* The kinds of value we can have. */
50 typedef enum valtype TYPE;
55 TYPE type; /* Which kind. */
57 { /* The value itself. */
62 typedef struct valinfo VALUE;
64 /* The arguments given to the program, minus the program name. */
67 /* The name this program was run with. */
74 static VALUE *docolon __P ((VALUE *sv, VALUE *pv));
75 static VALUE *eval __P ((void));
76 static VALUE *int_value __P ((int i));
77 static VALUE *str_value __P ((char *s));
78 static int isstring __P ((VALUE *v));
79 static int nextarg __P ((char *str));
80 static int nomoreargs __P ((void));
81 static int null __P ((VALUE *v));
82 static int toarith __P ((VALUE *v));
83 static void freev __P ((VALUE *v));
84 static void printv __P ((VALUE *v));
85 static void tostring __P ((VALUE *v));
95 fprintf (stderr, _("Try `%s --help' for more information.\n"),
100 Usage: %s EXPRESSION\n\
103 program_name, program_name);
106 --help display this help and exit\n\
107 --version output version information and exit\n\
111 Print the value of EXPRESSION to standard output. A blank line below\n\
112 separates increasing precedence groups. EXPRESSION may be:\n\
114 ARG1 | ARG2 ARG1 if it is neither null nor 0, otherwise ARG2\n\
116 ARG1 & ARG2 ARG1 if neither argument is null or 0, otherwise 0\n\
118 ARG1 < ARG2 ARG1 is less than ARG2\n\
119 ARG1 <= ARG2 ARG1 is less than or equal to ARG2\n\
120 ARG1 = ARG2 ARG1 is equal to ARG2\n\
121 ARG1 != ARG2 ARG1 is unequal to ARG2\n\
122 ARG1 >= ARG2 ARG1 is greater than or equal to ARG2\n\
123 ARG1 > ARG2 ARG1 is greater than ARG2\n\
125 ARG1 + ARG2 arithmetic sum of ARG1 and ARG2\n\
126 ARG1 - ARG2 arithmetic difference of ARG1 and ARG2\n\
128 ARG1 * ARG2 arithmetic product of ARG1 and ARG2\n\
129 ARG1 / ARG2 arithmetic quotient of ARG1 divided by ARG2\n\
130 ARG1 %% ARG2 arithmetic remainder of ARG1 divided by ARG2\n\
132 STRING : REGEXP anchored pattern match of REGEXP in STRING\n\
134 match STRING REGEXP same as STRING : REGEXP\n\
135 substr STRING POS LENGTH substring of STRING, POS counted from 1\n\
136 index STRING CHARS index in STRING where any CHARS is found, or 0\n\
137 length STRING length of STRING\n\
139 ( EXPRESSION ) value of EXPRESSION\n\
143 Beware that many operators need to be escaped or quoted for shells.\n\
144 Comparisons are arithmetic if both ARGs are numbers, else lexicographical.\n\
145 Pattern matches return the string matched between \\( and \\) or null; if\n\
146 \\( and \\) are not used, they return the number of characters matched or 0.\n\
153 main (int argc, char **argv)
157 program_name = argv[0];
158 setlocale (LC_ALL, "");
159 bindtextdomain (PACKAGE, LOCALEDIR);
160 textdomain (PACKAGE);
162 parse_long_options (argc, argv, "expr", version_string, usage);
166 error (0, 0, _("too few arguments"));
174 error (2, 0, _("syntax error"));
180 /* Return a VALUE for I. */
193 /* Return a VALUE for S. */
202 v->u.s = xstrdup (s);
206 /* Free VALUE V, including structure components. */
211 if (v->type == string)
224 printf ("%d\n", v->u.i);
227 printf ("%s\n", v->u.s);
234 /* Return nonzero if V is a null-string or zero-number. */
244 return v->u.s[0] == '\0' || strcmp(v->u.s, "0") == 0;
250 /* Return nonzero if V is a string value. */
255 return v->type == string;
258 /* Coerce V to a string value (can't fail). */
268 temp = xmalloc (4 * (sizeof (int) / sizeof (char)));
269 sprintf (temp, "%d", v->u.i);
280 /* Coerce V to an integer value. Return 1 on success, 0 on failure. */
296 /* Don't interpret the empty string as an integer. */
305 i = i * 10 + *cp - '0';
310 v->u.i = i * (neg ? -1 : 1);
318 /* Return nonzero if the next token matches STR exactly.
319 STR must not be NULL. */
326 return strcmp (*args, str) == 0;
329 /* Return nonzero if there no more tokens. */
337 /* The comparison operator handling functions. */
339 #define cmpf(name, rel) \
341 int name (l, r) VALUE *l; VALUE *r; \
343 if (isstring (l) || isstring (r)) \
347 return strcmp (l->u.s, r->u.s) rel 0; \
350 return l->u.i rel r->u.i; \
353 cmpf (less_equal, <=)
356 cmpf (greater_equal, >=)
357 cmpf (greater_than, >)
361 /* The arithmetic operator handling functions. */
363 #define arithf(name, op) \
365 int name (l, r) VALUE *l; VALUE *r; \
367 if (!toarith (l) || !toarith (r)) \
368 error (2, 0, _("non-numeric argument")); \
369 return l->u.i op r->u.i; \
372 #define arithdivf(name, op) \
373 int name (l, r) VALUE *l; VALUE *r; \
375 if (!toarith (l) || !toarith (r)) \
376 error (2, 0, _("non-numeric argument")); \
378 error (2, 0, _("division by zero")); \
379 return l->u.i op r->u.i; \
385 arithdivf (divide, /)
392 /* Print evaluation trace and args remaining. */
401 for (a = args; *a; a++)
407 /* Do the : operator.
408 SV is the VALUE for the lhs (the string),
409 PV is the VALUE for the rhs (the pattern). */
412 docolon (VALUE *sv, VALUE *pv)
416 struct re_pattern_buffer re_buffer;
417 struct re_registers re_regs;
423 len = strlen (pv->u.s);
424 memset (&re_buffer, 0, sizeof (re_buffer));
425 memset (&re_regs, 0, sizeof (re_regs));
426 re_buffer.allocated = 2 * len;
427 re_buffer.buffer = (unsigned char *) xmalloc (re_buffer.allocated);
428 re_buffer.translate = 0;
429 re_syntax_options = RE_SYNTAX_POSIX_MINIMAL_BASIC;
430 errmsg = re_compile_pattern (pv->u.s, len, &re_buffer);
432 error (2, 0, "%s", errmsg);
434 len = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
437 /* Were \(...\) used? */
438 if (re_buffer.re_nsub > 0)/* was (re_regs.start[1] >= 0) */
440 sv->u.s[re_regs.end[1]] = '\0';
441 v = str_value (sv->u.s + re_regs.start[1]);
448 /* Match failed -- return the right kind of null. */
449 if (strstr (pv->u.s, "\\("))
454 free (re_buffer.buffer);
458 /* Handle bare operands and ( expr ) syntax. */
469 error (2, 0, _("syntax error"));
476 error (2, 0, _("syntax error"));
482 error (2, 0, _("syntax error"));
484 return str_value (*args++);
487 /* Handle match, substr, index, and length keywords. */
501 if (nextarg ("length"))
506 v = int_value (strlen (r->u.s));
510 else if (nextarg ("match"))
520 else if (nextarg ("index"))
527 v = int_value (strcspn (l->u.s, r->u.s) + 1);
528 if (v->u.i == (int) strlen (l->u.s) + 1)
534 else if (nextarg ("substr"))
541 if (!toarith (i1) || !toarith (i2)
542 || i1->u.i > (int) strlen (l->u.s)
543 || i1->u.i <= 0 || i2->u.i <= 0)
549 v->u.s = strncpy ((char *) xmalloc (i2->u.i + 1),
550 l->u.s + i1->u.i - 1, i2->u.i);
562 /* Handle : operator (pattern matching).
563 Calls docolon to do the real work. */
592 /* Handle *, /, % operators. */
610 else if (nextarg ("/"))
612 else if (nextarg ("%"))
625 /* Handle +, - operators. */
643 else if (nextarg ("-"))
656 /* Handle comparisons. */
674 else if (nextarg ("<="))
676 else if (nextarg ("=") || nextarg ("=="))
678 else if (nextarg ("!="))
680 else if (nextarg (">="))
682 else if (nextarg (">"))
715 if (null (l) || null (r))