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>
37 #include "long-options.h"
40 #define NEW(type) ((type *) xmalloc (sizeof (type)))
41 #define OLD(x) free ((char *) x)
43 /* The kinds of value we can have. */
49 typedef enum valtype TYPE
;
54 TYPE type
; /* Which kind. */
56 { /* The value itself. */
61 typedef struct valinfo VALUE
;
63 /* The arguments given to the program, minus the program name. */
66 /* The name this program was run with. */
73 static VALUE
*docolon
__P ((VALUE
*sv
, VALUE
*pv
));
74 static VALUE
*eval
__P ((void));
75 static VALUE
*int_value
__P ((int i
));
76 static VALUE
*str_value
__P ((char *s
));
77 static int isstring
__P ((VALUE
*v
));
78 static int nextarg
__P ((char *str
));
79 static int nomoreargs
__P ((void));
80 static int null
__P ((VALUE
*v
));
81 static int toarith
__P ((VALUE
*v
));
82 static void freev
__P ((VALUE
*v
));
83 static void printv
__P ((VALUE
*v
));
84 static void tostring
__P ((VALUE
*v
));
94 fprintf (stderr
, _("Try `%s --help' for more information.\n"),
99 Usage: %s EXPRESSION\n\
102 program_name
, program_name
);
105 --help display this help and exit\n\
106 --version output version information and exit\n\
110 Print the value of EXPRESSION to standard output. A blank line below\n\
111 separates increasing precedence groups. EXPRESSION may be:\n\
113 ARG1 | ARG2 ARG1 if it is neither null nor 0, otherwise ARG2\n\
115 ARG1 & ARG2 ARG1 if neither argument is null or 0, otherwise 0\n\
117 ARG1 < ARG2 ARG1 is less than ARG2\n\
118 ARG1 <= ARG2 ARG1 is less than or equal to ARG2\n\
119 ARG1 = ARG2 ARG1 is equal to ARG2\n\
120 ARG1 != ARG2 ARG1 is unequal to ARG2\n\
121 ARG1 >= ARG2 ARG1 is greater than or equal to ARG2\n\
122 ARG1 > ARG2 ARG1 is greater than ARG2\n\
124 ARG1 + ARG2 arithmetic sum of ARG1 and ARG2\n\
125 ARG1 - ARG2 arithmetic difference of ARG1 and ARG2\n\
127 ARG1 * ARG2 arithmetic product of ARG1 and ARG2\n\
128 ARG1 / ARG2 arithmetic quotient of ARG1 divided by ARG2\n\
129 ARG1 %% ARG2 arithmetic remainder of ARG1 divided by ARG2\n\
131 STRING : REGEXP anchored pattern match of REGEXP in STRING\n\
133 match STRING REGEXP same as STRING : REGEXP\n\
134 substr STRING POS LENGTH substring of STRING, POS counted from 1\n\
135 index STRING CHARS index in STRING where any CHARS is found, or 0\n\
136 length STRING length of STRING\n\
138 ( EXPRESSION ) value of EXPRESSION\n\
142 Beware that many operators need to be escaped or quoted for shells.\n\
143 Comparisons are arithmetic if both ARGs are numbers, else lexicographical.\n\
144 Pattern matches return the string matched between \\( and \\) or null; if\n\
145 \\( and \\) are not used, they return the number of characters matched or 0.\n\
152 main (int argc
, char **argv
)
156 program_name
= argv
[0];
157 setlocale (LC_ALL
, "");
158 bindtextdomain (PACKAGE
, LOCALEDIR
);
159 textdomain (PACKAGE
);
161 parse_long_options (argc
, argv
, "expr", PACKAGE_VERSION
, usage
);
165 error (0, 0, _("too few arguments"));
173 error (2, 0, _("syntax error"));
179 /* Return a VALUE for I. */
192 /* Return a VALUE for S. */
201 v
->u
.s
= xstrdup (s
);
205 /* Free VALUE V, including structure components. */
210 if (v
->type
== string
)
223 printf ("%d\n", v
->u
.i
);
226 printf ("%s\n", v
->u
.s
);
233 /* Return nonzero if V is a null-string or zero-number. */
243 return v
->u
.s
[0] == '\0' || strcmp(v
->u
.s
, "0") == 0;
249 /* Return nonzero if V is a string value. */
254 return v
->type
== string
;
257 /* Coerce V to a string value (can't fail). */
267 temp
= xmalloc (4 * (sizeof (int) / sizeof (char)));
268 sprintf (temp
, "%d", v
->u
.i
);
279 /* Coerce V to an integer value. Return 1 on success, 0 on failure. */
295 /* Don't interpret the empty string as an integer. */
304 i
= i
* 10 + *cp
- '0';
309 v
->u
.i
= i
* (neg
? -1 : 1);
317 /* Return nonzero if the next token matches STR exactly.
318 STR must not be NULL. */
325 return strcmp (*args
, str
) == 0;
328 /* Return nonzero if there no more tokens. */
336 /* The comparison operator handling functions. */
338 #define cmpf(name, rel) \
340 int name (l, r) VALUE *l; VALUE *r; \
342 if (isstring (l) || isstring (r)) \
346 return strcmp (l->u.s, r->u.s) rel 0; \
349 return l->u.i rel r->u.i; \
352 cmpf (less_equal
, <=)
355 cmpf (greater_equal
, >=)
356 cmpf (greater_than
, >)
360 /* The arithmetic operator handling functions. */
362 #define arithf(name, op) \
364 int name (l, r) VALUE *l; VALUE *r; \
366 if (!toarith (l) || !toarith (r)) \
367 error (2, 0, _("non-numeric argument")); \
368 return l->u.i op r->u.i; \
371 #define arithdivf(name, op) \
372 int name (l, r) VALUE *l; VALUE *r; \
374 if (!toarith (l) || !toarith (r)) \
375 error (2, 0, _("non-numeric argument")); \
377 error (2, 0, _("division by zero")); \
378 return l->u.i op r->u.i; \
384 arithdivf (divide
, /)
391 /* Print evaluation trace and args remaining. */
400 for (a
= args
; *a
; a
++)
406 /* Do the : operator.
407 SV is the VALUE for the lhs (the string),
408 PV is the VALUE for the rhs (the pattern). */
411 docolon (VALUE
*sv
, VALUE
*pv
)
415 struct re_pattern_buffer re_buffer
;
416 struct re_registers re_regs
;
422 len
= strlen (pv
->u
.s
);
423 memset (&re_buffer
, 0, sizeof (re_buffer
));
424 memset (&re_regs
, 0, sizeof (re_regs
));
425 re_buffer
.allocated
= 2 * len
;
426 re_buffer
.buffer
= (unsigned char *) xmalloc (re_buffer
.allocated
);
427 re_buffer
.translate
= 0;
428 re_syntax_options
= RE_SYNTAX_POSIX_MINIMAL_BASIC
;
429 errmsg
= re_compile_pattern (pv
->u
.s
, len
, &re_buffer
);
431 error (2, 0, "%s", errmsg
);
433 len
= re_match (&re_buffer
, sv
->u
.s
, strlen (sv
->u
.s
), 0, &re_regs
);
436 /* Were \(...\) used? */
437 if (re_buffer
.re_nsub
> 0)/* was (re_regs.start[1] >= 0) */
439 sv
->u
.s
[re_regs
.end
[1]] = '\0';
440 v
= str_value (sv
->u
.s
+ re_regs
.start
[1]);
447 /* Match failed -- return the right kind of null. */
448 if (strstr (pv
->u
.s
, "\\("))
453 free (re_buffer
.buffer
);
457 /* Handle bare operands and ( expr ) syntax. */
468 error (2, 0, _("syntax error"));
475 error (2, 0, _("syntax error"));
481 error (2, 0, _("syntax error"));
483 return str_value (*args
++);
486 /* Handle match, substr, index, and length keywords. */
500 if (nextarg ("length"))
505 v
= int_value (strlen (r
->u
.s
));
509 else if (nextarg ("match"))
519 else if (nextarg ("index"))
526 v
= int_value (strcspn (l
->u
.s
, r
->u
.s
) + 1);
527 if (v
->u
.i
== (int) strlen (l
->u
.s
) + 1)
533 else if (nextarg ("substr"))
540 if (!toarith (i1
) || !toarith (i2
)
541 || i1
->u
.i
> (int) strlen (l
->u
.s
)
542 || i1
->u
.i
<= 0 || i2
->u
.i
<= 0)
548 v
->u
.s
= strncpy ((char *) xmalloc (i2
->u
.i
+ 1),
549 l
->u
.s
+ i1
->u
.i
- 1, i2
->u
.i
);
561 /* Handle : operator (pattern matching).
562 Calls docolon to do the real work. */
591 /* Handle *, /, % operators. */
609 else if (nextarg ("/"))
611 else if (nextarg ("%"))
624 /* Handle +, - operators. */
642 else if (nextarg ("-"))
655 /* Handle comparisons. */
673 else if (nextarg ("<="))
675 else if (nextarg ("=") || nextarg ("=="))
677 else if (nextarg ("!="))
679 else if (nextarg (">="))
681 else if (nextarg (">"))
714 if (null (l
) || null (r
))