split: port ‘split -n N /dev/null’ better to macOS
[coreutils.git] / src / expr.c
blob19475f349543775c394983c71e9f95698c0b9855
1 /* expr -- evaluate expressions.
2 Copyright (C) 1986-2023 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 3 of the License, or
7 (at your option) any later version.
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, see <https://www.gnu.org/licenses/>. */
17 /* Author: Mike Parker.
18 Modified for arbitrary-precision calculation by James Youngman.
20 This program evaluates expressions. Each token (operator, operand,
21 parenthesis) of the expression must be a separate 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. */
31 #include <config.h>
32 #include <stdio.h>
33 #include <sys/types.h>
34 #include "system.h"
36 #include <gmp.h>
37 #include <regex.h>
38 #include "die.h"
39 #include "error.h"
40 #include "long-options.h"
41 #include "mbuiter.h"
42 #include "strnumcmp.h"
43 #include "xstrtol.h"
45 /* Various parts of this code assume size_t fits into unsigned long
46 int, the widest unsigned type that GMP supports. */
47 static_assert (SIZE_MAX <= ULONG_MAX);
49 /* The official name of this program (e.g., no 'g' prefix). */
50 #define PROGRAM_NAME "expr"
52 #define AUTHORS \
53 proper_name ("Mike Parker"), \
54 proper_name ("James Youngman"), \
55 proper_name ("Paul Eggert")
57 /* Exit statuses. */
58 enum
60 /* Invalid expression: e.g., its form does not conform to the
61 grammar for expressions. Our grammar is an extension of the
62 POSIX grammar. */
63 EXPR_INVALID = 2,
65 /* An internal error occurred, e.g., arithmetic overflow, storage
66 exhaustion. */
67 EXPR_FAILURE
70 /* The kinds of value we can have. */
71 enum valtype
73 integer,
74 string
76 typedef enum valtype TYPE;
78 /* A value is.... */
79 struct valinfo
81 TYPE type; /* Which kind. */
82 union
83 { /* The value itself. */
84 mpz_t i;
85 char *s;
86 } u;
88 typedef struct valinfo VALUE;
90 /* The arguments given to the program, minus the program name. */
91 static char **args;
93 static VALUE *eval (bool);
94 static bool nomoreargs (void);
95 static bool null (VALUE *v);
96 static void printv (VALUE *v);
100 Find the first occurrence in the character string STRING of any character
101 in the character string ACCEPT.
103 Copied from gnulib's mbscspn, with two differences:
104 1. Returns 1-based position of first found character, or zero if not found.
105 2. Returned value is the logical character index, NOT byte offset.
107 Examples:
108 mbs_logical_cspn ('hello','a') => 0
109 mbs_logical_cspn ('hello','h') => 1
110 mbs_logical_cspn ('hello','oe') => 1
111 mbs_logical_cspn ('hello','lo') => 3
113 In UTF-8 \xCE\xB1 is a single character (greek alpha):
114 mbs_logical_cspn ('\xCE\xB1bc','\xCE\xB1') => 1
115 mbs_logical_cspn ('\xCE\xB1bc','c') => 3 */
116 static size_t
117 mbs_logical_cspn (char const *s, char const *accept)
119 size_t idx = 0;
121 if (accept[0] == '\0')
122 return 0;
124 /* General case. */
125 if (MB_CUR_MAX > 1)
127 mbui_iterator_t iter;
129 for (mbui_init (iter, s); mbui_avail (iter); mbui_advance (iter))
131 ++idx;
132 if (mb_len (mbui_cur (iter)) == 1)
134 if (mbschr (accept, *mbui_cur_ptr (iter)))
135 return idx;
137 else
139 mbui_iterator_t aiter;
141 for (mbui_init (aiter, accept);
142 mbui_avail (aiter);
143 mbui_advance (aiter))
144 if (mb_equal (mbui_cur (aiter), mbui_cur (iter)))
145 return idx;
149 /* not found */
150 return 0;
152 else
154 /* single-byte locale,
155 convert returned byte offset to 1-based index or zero if not found. */
156 size_t i = strcspn (s, accept);
157 return (s[i] ? i + 1 : 0);
161 /* Extract the substring of S, from logical character
162 position POS and LEN characters.
163 first character position is 1.
164 POS and LEN refer to logical characters, not octets.
166 Upon exit, sets v->s to the new string.
167 The new string might be empty if POS/LEN are invalid. */
168 static char *
169 mbs_logical_substr (char const *s, size_t pos, size_t len)
171 char *v, *vlim;
173 size_t blen = strlen (s); /* byte length */
174 size_t llen = (MB_CUR_MAX > 1) ? mbslen (s) : blen; /* logical length */
176 if (llen < pos || pos == 0 || len == 0 || len == SIZE_MAX)
177 return xstrdup ("");
179 /* characters to copy */
180 size_t vlen = MIN (len, llen - pos + 1);
182 if (MB_CUR_MAX == 1)
184 /* Single-byte case */
185 v = xmalloc (vlen + 1);
186 vlim = mempcpy (v, s + pos - 1, vlen);
188 else
190 /* Multibyte case */
192 /* FIXME: this is wasteful. Some memory can be saved by counting
193 how many bytes the matching characters occupy. */
194 vlim = v = xmalloc (blen + 1);
196 mbui_iterator_t iter;
197 size_t idx=1;
198 for (mbui_init (iter, s);
199 mbui_avail (iter) && vlen > 0;
200 mbui_advance (iter), ++idx)
202 /* Skip until we reach the starting position */
203 if (idx < pos)
204 continue;
206 /* Copy one character */
207 --vlen;
208 vlim = mempcpy (vlim, mbui_cur_ptr (iter), mb_len (mbui_cur (iter)));
211 *vlim = '\0';
212 return v;
215 /* Return the number of logical characters (possibly multibyte)
216 that are in string S in the first OFS octets.
218 Example in UTF-8:
219 "\xE2\x9D\xA7" is "U+2767 ROTATED FLORAL HEART BULLET".
220 In the string below, there are only two characters
221 up to the first 4 bytes (The U+2767 which occupies 3 bytes and 'x'):
222 mbs_count_to_offset ("\xE2\x9D\xA7xyz", 4) => 2 */
223 static size_t
224 mbs_offset_to_chars (char const *s, size_t ofs)
226 mbui_iterator_t iter;
227 size_t c = 0;
228 for (mbui_init (iter, s); mbui_avail (iter); mbui_advance (iter))
230 ptrdiff_t d = mbui_cur_ptr (iter) - s;
231 if (d >= ofs)
232 break;
233 ++c;
235 return c;
240 void
241 usage (int status)
243 if (status != EXIT_SUCCESS)
244 emit_try_help ();
245 else
247 printf (_("\
248 Usage: %s EXPRESSION\n\
249 or: %s OPTION\n\
251 program_name, program_name);
252 putchar ('\n');
253 fputs (HELP_OPTION_DESCRIPTION, stdout);
254 fputs (VERSION_OPTION_DESCRIPTION, stdout);
255 fputs (_("\
257 Print the value of EXPRESSION to standard output. A blank line below\n\
258 separates increasing precedence groups. EXPRESSION may be:\n\
260 ARG1 | ARG2 ARG1 if it is neither null nor 0, otherwise ARG2\n\
262 ARG1 & ARG2 ARG1 if neither argument is null or 0, otherwise 0\n\
263 "), stdout);
264 fputs (_("\
266 ARG1 < ARG2 ARG1 is less than ARG2\n\
267 ARG1 <= ARG2 ARG1 is less than or equal to ARG2\n\
268 ARG1 = ARG2 ARG1 is equal to ARG2\n\
269 ARG1 != ARG2 ARG1 is unequal to ARG2\n\
270 ARG1 >= ARG2 ARG1 is greater than or equal to ARG2\n\
271 ARG1 > ARG2 ARG1 is greater than ARG2\n\
272 "), stdout);
273 fputs (_("\
275 ARG1 + ARG2 arithmetic sum of ARG1 and ARG2\n\
276 ARG1 - ARG2 arithmetic difference of ARG1 and ARG2\n\
277 "), stdout);
278 /* Tell xgettext that the "% A" below is not a printf-style
279 format string: xgettext:no-c-format */
280 fputs (_("\
282 ARG1 * ARG2 arithmetic product of ARG1 and ARG2\n\
283 ARG1 / ARG2 arithmetic quotient of ARG1 divided by ARG2\n\
284 ARG1 % ARG2 arithmetic remainder of ARG1 divided by ARG2\n\
285 "), stdout);
286 fputs (_("\
288 STRING : REGEXP anchored pattern match of REGEXP in STRING\n\
290 match STRING REGEXP same as STRING : REGEXP\n\
291 substr STRING POS LENGTH substring of STRING, POS counted from 1\n\
292 index STRING CHARS index in STRING where any CHARS is found, or 0\n\
293 length STRING length of STRING\n\
294 "), stdout);
295 fputs (_("\
296 + TOKEN interpret TOKEN as a string, even if it is a\n\
297 keyword like 'match' or an operator like '/'\n\
299 ( EXPRESSION ) value of EXPRESSION\n\
300 "), stdout);
301 fputs (_("\
303 Beware that many operators need to be escaped or quoted for shells.\n\
304 Comparisons are arithmetic if both ARGs are numbers, else lexicographical.\n\
305 Pattern matches return the string matched between \\( and \\) or null; if\n\
306 \\( and \\) are not used, they return the number of characters matched or 0.\n\
307 "), stdout);
308 fputs (_("\
310 Exit status is 0 if EXPRESSION is neither null nor 0, 1 if EXPRESSION is null\n\
311 or 0, 2 if EXPRESSION is syntactically invalid, and 3 if an error occurred.\n\
312 "), stdout);
313 emit_ancillary_info (PROGRAM_NAME);
315 exit (status);
320 main (int argc, char **argv)
322 VALUE *v;
324 initialize_main (&argc, &argv);
325 set_program_name (argv[0]);
326 setlocale (LC_ALL, "");
327 bindtextdomain (PACKAGE, LOCALEDIR);
328 textdomain (PACKAGE);
330 initialize_exit_failure (EXPR_FAILURE);
331 atexit (close_stdout);
333 parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, VERSION,
334 usage, AUTHORS, (char const *) NULL);
336 /* The above handles --help and --version.
337 Since there is no other invocation of getopt, handle '--' here. */
338 unsigned int u_argc = argc;
339 if (1 < u_argc && STREQ (argv[1], "--"))
341 --u_argc;
342 ++argv;
345 if (u_argc <= 1)
347 error (0, 0, _("missing operand"));
348 usage (EXPR_INVALID);
351 args = argv + 1;
353 v = eval (true);
354 if (!nomoreargs ())
355 die (EXPR_INVALID, 0, _("syntax error: unexpected argument %s"),
356 quotearg_n_style (0, locale_quoting_style, *args));
358 printv (v);
360 main_exit (null (v));
363 /* Return a VALUE for I. */
365 static VALUE *
366 int_value (unsigned long int i)
368 VALUE *v = xmalloc (sizeof *v);
369 v->type = integer;
370 mpz_init_set_ui (v->u.i, i);
371 return v;
374 /* Return a VALUE for S. */
376 static VALUE *
377 str_value (char const *s)
379 VALUE *v = xmalloc (sizeof *v);
380 v->type = string;
381 v->u.s = xstrdup (s);
382 return v;
385 /* Free VALUE V, including structure components. */
387 static void
388 freev (VALUE *v)
390 if (v->type == string)
391 free (v->u.s);
392 else
393 mpz_clear (v->u.i);
394 free (v);
397 /* Print VALUE V. */
399 static void
400 printv (VALUE *v)
402 switch (v->type)
404 case integer:
405 mpz_out_str (stdout, 10, v->u.i);
406 putchar ('\n');
407 break;
408 case string:
409 puts (v->u.s);
410 break;
411 default:
412 abort ();
416 /* Return true if V is a null-string or zero-number. */
418 ATTRIBUTE_PURE
419 static bool
420 null (VALUE *v)
422 switch (v->type)
424 case integer:
425 return mpz_sgn (v->u.i) == 0;
426 case string:
428 char const *cp = v->u.s;
429 if (*cp == '\0')
430 return true;
432 cp += (*cp == '-');
436 if (*cp != '0')
437 return false;
439 while (*++cp);
441 return true;
443 default:
444 abort ();
448 /* Return true if CP takes the form of an integer. */
450 ATTRIBUTE_PURE
451 static bool
452 looks_like_integer (char const *cp)
454 cp += (*cp == '-');
457 if (! ISDIGIT (*cp))
458 return false;
459 while (*++cp);
461 return true;
464 /* Coerce V to a string value (can't fail). */
466 static void
467 tostring (VALUE *v)
469 switch (v->type)
471 case integer:
473 char *s = mpz_get_str (NULL, 10, v->u.i);
474 mpz_clear (v->u.i);
475 v->u.s = s;
476 v->type = string;
478 break;
479 case string:
480 break;
481 default:
482 abort ();
486 /* Coerce V to an integer value. Return true on success, false on failure. */
488 static bool
489 toarith (VALUE *v)
491 switch (v->type)
493 case integer:
494 return true;
495 case string:
497 char *s = v->u.s;
499 if (! looks_like_integer (s))
500 return false;
501 if (mpz_init_set_str (v->u.i, s, 10) != 0)
502 die (EXPR_FAILURE, ERANGE, "%s", (s));
503 free (s);
504 v->type = integer;
505 return true;
507 default:
508 abort ();
512 /* Extract a size_t value from an integer value I.
513 If the value is negative, return SIZE_MAX.
514 If the value is too large, return SIZE_MAX - 1. */
515 static size_t
516 getsize (mpz_t i)
518 if (mpz_sgn (i) < 0)
519 return SIZE_MAX;
520 if (mpz_fits_ulong_p (i))
522 unsigned long int ul = mpz_get_ui (i);
523 if (ul < SIZE_MAX)
524 return ul;
526 return SIZE_MAX - 1;
529 /* Return true and advance if the next token matches STR exactly.
530 STR must not be NULL. */
532 static bool
533 nextarg (char const *str)
535 if (*args == NULL)
536 return false;
537 else
539 bool r = STREQ (*args, str);
540 args += r;
541 return r;
545 /* Return true if there no more tokens. */
547 static bool
548 nomoreargs (void)
550 return *args == 0;
553 /* Report missing operand.
554 There is an implicit assumption that there was a previous argument,
555 and (args-1) is valid. */
556 static void
557 require_more_args (void)
559 if (nomoreargs ())
560 die (EXPR_INVALID, 0, _("syntax error: missing argument after %s"),
561 quotearg_n_style (0, locale_quoting_style, *(args - 1)));
565 #ifdef EVAL_TRACE
566 /* Print evaluation trace and args remaining. */
568 static void
569 trace (fxn)
570 char *fxn;
572 char **a;
574 printf ("%s:", fxn);
575 for (a = args; *a; a++)
576 printf (" %s", *a);
577 putchar ('\n');
579 #endif
581 /* Do the : operator.
582 SV is the VALUE for the lhs (the string),
583 PV is the VALUE for the rhs (the pattern). */
585 static VALUE *
586 docolon (VALUE *sv, VALUE *pv)
588 VALUE *v;
589 char const *errmsg;
590 struct re_pattern_buffer re_buffer;
591 char fastmap[UCHAR_MAX + 1];
592 struct re_registers re_regs;
593 regoff_t matchlen;
595 tostring (sv);
596 tostring (pv);
598 re_regs.num_regs = 0;
599 re_regs.start = NULL;
600 re_regs.end = NULL;
602 re_buffer.buffer = NULL;
603 re_buffer.allocated = 0;
604 re_buffer.fastmap = fastmap;
605 re_buffer.translate = NULL;
606 re_syntax_options =
607 RE_SYNTAX_POSIX_BASIC & ~RE_CONTEXT_INVALID_DUP & ~RE_NO_EMPTY_RANGES;
608 errmsg = re_compile_pattern (pv->u.s, strlen (pv->u.s), &re_buffer);
609 if (errmsg)
610 die (EXPR_INVALID, 0, "%s", (errmsg));
611 re_buffer.newline_anchor = 0;
613 matchlen = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
614 if (0 <= matchlen)
616 /* Were \(...\) used? */
617 if (re_buffer.re_nsub > 0)
619 if (re_regs.end[1] < 0)
620 v = str_value ("");
621 else
623 sv->u.s[re_regs.end[1]] = '\0';
624 v = str_value (sv->u.s + re_regs.start[1]);
627 else
629 /* In multibyte locales, convert the matched offset (=number of bytes)
630 to the number of matched characters. */
631 size_t i = (MB_CUR_MAX == 1
632 ? matchlen
633 : mbs_offset_to_chars (sv->u.s, matchlen));
634 v = int_value (i);
637 else if (matchlen == -1)
639 /* Match failed -- return the right kind of null. */
640 if (re_buffer.re_nsub > 0)
641 v = str_value ("");
642 else
643 v = int_value (0);
645 else
646 die (EXPR_FAILURE,
647 (matchlen == -2 ? errno : EOVERFLOW),
648 _("error in regular expression matcher"));
650 if (0 < re_regs.num_regs)
652 free (re_regs.start);
653 free (re_regs.end);
655 re_buffer.fastmap = NULL;
656 regfree (&re_buffer);
657 return v;
660 /* Handle bare operands and ( expr ) syntax. */
662 static VALUE *
663 eval7 (bool evaluate)
665 VALUE *v;
667 #ifdef EVAL_TRACE
668 trace ("eval7");
669 #endif
670 require_more_args ();
672 if (nextarg ("("))
674 v = eval (evaluate);
675 if (nomoreargs ())
676 die (EXPR_INVALID, 0, _("syntax error: expecting ')' after %s"),
677 quotearg_n_style (0, locale_quoting_style, *(args - 1)));
678 if (!nextarg (")"))
679 die (EXPR_INVALID, 0, _("syntax error: expecting ')' instead of %s"),
680 quotearg_n_style (0, locale_quoting_style, *args));
681 return v;
684 if (nextarg (")"))
685 die (EXPR_INVALID, 0, _("syntax error: unexpected ')'"));
687 return str_value (*args++);
690 /* Handle match, substr, index, and length keywords, and quoting "+". */
692 static VALUE *
693 eval6 (bool evaluate)
695 VALUE *l;
696 VALUE *r;
697 VALUE *v;
698 VALUE *i1;
699 VALUE *i2;
701 #ifdef EVAL_TRACE
702 trace ("eval6");
703 #endif
704 if (nextarg ("+"))
706 require_more_args ();
707 return str_value (*args++);
709 else if (nextarg ("length"))
711 r = eval6 (evaluate);
712 tostring (r);
713 v = int_value (mbslen (r->u.s));
714 freev (r);
715 return v;
717 else if (nextarg ("match"))
719 l = eval6 (evaluate);
720 r = eval6 (evaluate);
721 if (evaluate)
723 v = docolon (l, r);
724 freev (l);
726 else
727 v = l;
728 freev (r);
729 return v;
731 else if (nextarg ("index"))
733 size_t pos;
735 l = eval6 (evaluate);
736 r = eval6 (evaluate);
737 tostring (l);
738 tostring (r);
739 pos = mbs_logical_cspn (l->u.s, r->u.s);
740 v = int_value (pos);
741 freev (l);
742 freev (r);
743 return v;
745 else if (nextarg ("substr"))
747 l = eval6 (evaluate);
748 i1 = eval6 (evaluate);
749 i2 = eval6 (evaluate);
750 tostring (l);
752 if (!toarith (i1) || !toarith (i2))
753 v = str_value ("");
754 else
756 size_t pos = getsize (i1->u.i);
757 size_t len = getsize (i2->u.i);
759 char *s = mbs_logical_substr (l->u.s, pos, len);
760 v = str_value (s);
761 free (s);
763 freev (l);
764 freev (i1);
765 freev (i2);
766 return v;
768 else
769 return eval7 (evaluate);
772 /* Handle : operator (pattern matching).
773 Calls docolon to do the real work. */
775 static VALUE *
776 eval5 (bool evaluate)
778 VALUE *l;
779 VALUE *r;
780 VALUE *v;
782 #ifdef EVAL_TRACE
783 trace ("eval5");
784 #endif
785 l = eval6 (evaluate);
786 while (true)
788 if (nextarg (":"))
790 r = eval6 (evaluate);
791 if (evaluate)
793 v = docolon (l, r);
794 freev (l);
795 l = v;
797 freev (r);
799 else
800 return l;
804 /* Handle *, /, % operators. */
806 static VALUE *
807 eval4 (bool evaluate)
809 VALUE *l;
810 VALUE *r;
811 enum { multiply, divide, mod } fxn;
813 #ifdef EVAL_TRACE
814 trace ("eval4");
815 #endif
816 l = eval5 (evaluate);
817 while (true)
819 if (nextarg ("*"))
820 fxn = multiply;
821 else if (nextarg ("/"))
822 fxn = divide;
823 else if (nextarg ("%"))
824 fxn = mod;
825 else
826 return l;
827 r = eval5 (evaluate);
828 if (evaluate)
830 if (!toarith (l) || !toarith (r))
831 die (EXPR_INVALID, 0, _("non-integer argument"));
832 if (fxn != multiply && mpz_sgn (r->u.i) == 0)
833 die (EXPR_INVALID, 0, _("division by zero"));
834 ((fxn == multiply ? mpz_mul
835 : fxn == divide ? mpz_tdiv_q
836 : mpz_tdiv_r)
837 (l->u.i, l->u.i, r->u.i));
839 freev (r);
843 /* Handle +, - operators. */
845 static VALUE *
846 eval3 (bool evaluate)
848 VALUE *l;
849 VALUE *r;
850 enum { plus, minus } fxn;
852 #ifdef EVAL_TRACE
853 trace ("eval3");
854 #endif
855 l = eval4 (evaluate);
856 while (true)
858 if (nextarg ("+"))
859 fxn = plus;
860 else if (nextarg ("-"))
861 fxn = minus;
862 else
863 return l;
864 r = eval4 (evaluate);
865 if (evaluate)
867 if (!toarith (l) || !toarith (r))
868 die (EXPR_INVALID, 0, _("non-integer argument"));
869 (fxn == plus ? mpz_add : mpz_sub) (l->u.i, l->u.i, r->u.i);
871 freev (r);
875 /* Handle comparisons. */
877 static VALUE *
878 eval2 (bool evaluate)
880 VALUE *l;
882 #ifdef EVAL_TRACE
883 trace ("eval2");
884 #endif
885 l = eval3 (evaluate);
886 while (true)
888 VALUE *r;
889 enum
891 less_than, less_equal, equal, not_equal, greater_equal, greater_than
892 } fxn;
893 bool val = false;
895 if (nextarg ("<"))
896 fxn = less_than;
897 else if (nextarg ("<="))
898 fxn = less_equal;
899 else if (nextarg ("=") || nextarg ("=="))
900 fxn = equal;
901 else if (nextarg ("!="))
902 fxn = not_equal;
903 else if (nextarg (">="))
904 fxn = greater_equal;
905 else if (nextarg (">"))
906 fxn = greater_than;
907 else
908 return l;
909 r = eval3 (evaluate);
911 if (evaluate)
913 int cmp;
914 tostring (l);
915 tostring (r);
917 if (looks_like_integer (l->u.s) && looks_like_integer (r->u.s))
918 cmp = strintcmp (l->u.s, r->u.s);
919 else
921 errno = 0;
922 cmp = strcoll (l->u.s, r->u.s);
924 if (errno)
926 error (0, errno, _("string comparison failed"));
927 error (0, 0, _("set LC_ALL='C' to work around the problem"));
928 die (EXPR_INVALID, 0,
929 _("the strings compared were %s and %s"),
930 quotearg_n_style (0, locale_quoting_style, l->u.s),
931 quotearg_n_style (1, locale_quoting_style, r->u.s));
935 switch (fxn)
937 case less_than: val = (cmp < 0); break;
938 case less_equal: val = (cmp <= 0); break;
939 case equal: val = (cmp == 0); break;
940 case not_equal: val = (cmp != 0); break;
941 case greater_equal: val = (cmp >= 0); break;
942 case greater_than: val = (cmp > 0); break;
943 default: abort ();
947 freev (l);
948 freev (r);
949 l = int_value (val);
953 /* Handle &. */
955 static VALUE *
956 eval1 (bool evaluate)
958 VALUE *l;
959 VALUE *r;
961 #ifdef EVAL_TRACE
962 trace ("eval1");
963 #endif
964 l = eval2 (evaluate);
965 while (true)
967 if (nextarg ("&"))
969 r = eval2 (evaluate && !null (l));
970 if (null (l) || null (r))
972 freev (l);
973 freev (r);
974 l = int_value (0);
976 else
977 freev (r);
979 else
980 return l;
984 /* Handle |. */
986 static VALUE *
987 eval (bool evaluate)
989 VALUE *l;
990 VALUE *r;
992 #ifdef EVAL_TRACE
993 trace ("eval");
994 #endif
995 l = eval1 (evaluate);
996 while (true)
998 if (nextarg ("|"))
1000 r = eval1 (evaluate && null (l));
1001 if (null (l))
1003 freev (l);
1004 l = r;
1005 if (null (l))
1007 freev (l);
1008 l = int_value (0);
1011 else
1012 freev (r);
1014 else
1015 return l;