maint: remove unnecessary inttostr usage in printf
[coreutils.git] / src / expr.c
blob3ecec07350b4e1815cc9286d93963bdd2821df07
1 /* expr -- evaluate expressions.
2 Copyright (C) 1986-2024 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 "long-options.h"
39 #include "mcel.h"
40 #include "strnumcmp.h"
41 #include "xstrtol.h"
43 /* Various parts of this code assume size_t fits into unsigned long
44 int, the widest unsigned type that GMP supports. */
45 static_assert (SIZE_MAX <= ULONG_MAX);
47 /* The official name of this program (e.g., no 'g' prefix). */
48 #define PROGRAM_NAME "expr"
50 #define AUTHORS \
51 proper_name ("Mike Parker"), \
52 proper_name ("James Youngman"), \
53 proper_name ("Paul Eggert")
55 /* Exit statuses. */
56 enum
58 /* Invalid expression: e.g., its form does not conform to the
59 grammar for expressions. Our grammar is an extension of the
60 POSIX grammar. */
61 EXPR_INVALID = 2,
63 /* An internal error occurred, e.g., arithmetic overflow, storage
64 exhaustion. */
65 EXPR_FAILURE
68 /* The kinds of value we can have. */
69 enum valtype
71 integer,
72 string
74 typedef enum valtype TYPE;
76 /* A value is.... */
77 struct valinfo
79 TYPE type; /* Which kind. */
80 union
81 { /* The value itself. */
82 mpz_t i;
83 char *s;
84 } u;
86 typedef struct valinfo VALUE;
88 /* The arguments given to the program, minus the program name. */
89 static char **args;
91 static VALUE *eval (bool);
92 static bool nomoreargs (void);
93 static bool null (VALUE *v);
94 static void printv (VALUE *v);
98 Find the first occurrence in the character string STRING of any character
99 in the character string ACCEPT.
101 Copied from gnulib's mbscspn, with two differences:
102 1. Returns 1-based position of first found character, or zero if not found.
103 2. Returned value is the logical character index, NOT byte offset.
105 Examples:
106 mbs_logical_cspn ('hello','a') => 0
107 mbs_logical_cspn ('hello','h') => 1
108 mbs_logical_cspn ('hello','oe') => 1
109 mbs_logical_cspn ('hello','lo') => 3
111 In UTF-8 \xCE\xB1 is a single character (greek alpha):
112 mbs_logical_cspn ('\xCE\xB1bc','\xCE\xB1') => 1
113 mbs_logical_cspn ('\xCE\xB1bc','c') => 3 */
114 static size_t
115 mbs_logical_cspn (char const *s, char const *accept)
117 size_t idx = 0;
119 if (accept[0] == '\0')
120 return 0;
122 /* General case. */
123 if (MB_CUR_MAX > 1)
125 for (char const *p = s; *p; )
127 ++idx;
128 mcel_t g = mcel_scanz (p);
129 if (g.len == 1)
131 if (mbschr (accept, *p))
132 return idx;
134 else
135 for (char const *a = accept; *a; )
137 mcel_t h = mcel_scanz (a);
138 if (mcel_cmp (g, h) == 0)
139 return idx;
140 a += h.len;
142 p += g.len;
145 else
147 /* single-byte locale,
148 convert returned byte offset to 1-based index or zero if not found. */
149 size_t i = strcspn (s, accept);
150 if (s[i])
151 return i + 1;
154 /* not found */
155 return 0;
158 /* Extract the substring of S, from logical character
159 position POS and LEN characters.
160 first character position is 1.
161 POS and LEN refer to logical characters, not octets.
163 Upon exit, sets v->s to the new string.
164 The new string might be empty if POS/LEN are invalid. */
165 static char *
166 mbs_logical_substr (char const *s, size_t pos, size_t len)
168 size_t mb_cur_max = MB_CUR_MAX;
169 idx_t llen = mb_cur_max <= 1 ? strlen (s) : mbslen (s); /* logical length */
171 /* characters to copy */
172 size_t vlen = MIN (len, pos <= llen ? llen - pos + 1 : 0);
174 char const *substart = s;
175 idx_t sublen = 0;
176 if (pos == 0 || len == SIZE_MAX)
178 /* The request is invalid. Silently yield an empty string. */
180 else if (mb_cur_max <= 1)
182 substart += pos - 1;
183 sublen = vlen;
185 else
186 for (idx_t idx = 1; *s && vlen; idx++)
188 idx_t char_bytes = mcel_scanz (s).len;
190 /* Skip until we reach the starting position. */
191 if (pos <= idx)
193 if (pos == idx)
194 substart = s;
196 /* Add one character's length in bytes. */
197 vlen--;
198 sublen += char_bytes;
201 s += char_bytes;
204 return ximemdup0 (substart, sublen);
207 /* Return the number of logical characters (possibly multibyte)
208 that are in string S in the first OFS octets.
210 Example in UTF-8:
211 "\xE2\x9D\xA7" is "U+2767 ROTATED FLORAL HEART BULLET".
212 In the string below, there are only two characters
213 up to the first 4 bytes (The U+2767 which occupies 3 bytes and 'x'):
214 mbs_count_to_offset ("\xE2\x9D\xA7xyz", 4) => 2 */
215 static size_t
216 mbs_offset_to_chars (char const *s, size_t ofs)
218 size_t c = 0;
219 for (size_t d = 0; d < ofs && s[d]; d += mcel_scanz (s + d).len)
220 c++;
221 return c;
226 void
227 usage (int status)
229 if (status != EXIT_SUCCESS)
230 emit_try_help ();
231 else
233 printf (_("\
234 Usage: %s EXPRESSION\n\
235 or: %s OPTION\n\
237 program_name, program_name);
238 putchar ('\n');
239 fputs (HELP_OPTION_DESCRIPTION, stdout);
240 fputs (VERSION_OPTION_DESCRIPTION, stdout);
241 fputs (_("\
243 Print the value of EXPRESSION to standard output. A blank line below\n\
244 separates increasing precedence groups. EXPRESSION may be:\n\
246 ARG1 | ARG2 ARG1 if it is neither null nor 0, otherwise ARG2\n\
248 ARG1 & ARG2 ARG1 if neither argument is null or 0, otherwise 0\n\
249 "), stdout);
250 fputs (_("\
252 ARG1 < ARG2 ARG1 is less than ARG2\n\
253 ARG1 <= ARG2 ARG1 is less than or equal to ARG2\n\
254 ARG1 = ARG2 ARG1 is equal to ARG2\n\
255 ARG1 != ARG2 ARG1 is unequal to ARG2\n\
256 ARG1 >= ARG2 ARG1 is greater than or equal to ARG2\n\
257 ARG1 > ARG2 ARG1 is greater than ARG2\n\
258 "), stdout);
259 fputs (_("\
261 ARG1 + ARG2 arithmetic sum of ARG1 and ARG2\n\
262 ARG1 - ARG2 arithmetic difference of ARG1 and ARG2\n\
263 "), stdout);
264 /* Tell xgettext that the "% A" below is not a printf-style
265 format string: xgettext:no-c-format */
266 fputs (_("\
268 ARG1 * ARG2 arithmetic product of ARG1 and ARG2\n\
269 ARG1 / ARG2 arithmetic quotient of ARG1 divided by ARG2\n\
270 ARG1 % ARG2 arithmetic remainder of ARG1 divided by ARG2\n\
271 "), stdout);
272 fputs (_("\
274 STRING : REGEXP anchored pattern match of REGEXP in STRING\n\
276 match STRING REGEXP same as STRING : REGEXP\n\
277 substr STRING POS LENGTH substring of STRING, POS counted from 1\n\
278 index STRING CHARS index in STRING where any CHARS is found, or 0\n\
279 length STRING length of STRING\n\
280 "), stdout);
281 fputs (_("\
282 + TOKEN interpret TOKEN as a string, even if it is a\n\
283 keyword like 'match' or an operator like '/'\n\
285 ( EXPRESSION ) value of EXPRESSION\n\
286 "), stdout);
287 fputs (_("\
289 Beware that many operators need to be escaped or quoted for shells.\n\
290 Comparisons are arithmetic if both ARGs are numbers, else lexicographical.\n\
291 Pattern matches return the string matched between \\( and \\) or null; if\n\
292 \\( and \\) are not used, they return the number of characters matched or 0.\n\
293 "), stdout);
294 fputs (_("\
296 Exit status is 0 if EXPRESSION is neither null nor 0, 1 if EXPRESSION is null\n\
297 or 0, 2 if EXPRESSION is syntactically invalid, and 3 if an error occurred.\n\
298 "), stdout);
299 emit_ancillary_info (PROGRAM_NAME);
301 exit (status);
306 main (int argc, char **argv)
308 VALUE *v;
310 initialize_main (&argc, &argv);
311 set_program_name (argv[0]);
312 setlocale (LC_ALL, "");
313 bindtextdomain (PACKAGE, LOCALEDIR);
314 textdomain (PACKAGE);
316 initialize_exit_failure (EXPR_FAILURE);
317 atexit (close_stdout);
319 parse_long_options (argc, argv, PROGRAM_NAME, PACKAGE_NAME, VERSION,
320 usage, AUTHORS, (char const *) nullptr);
322 /* The above handles --help and --version.
323 Since there is no other invocation of getopt, handle '--' here. */
324 if (1 < argc && STREQ (argv[1], "--"))
326 --argc;
327 ++argv;
330 if (argc <= 1)
332 error (0, 0, _("missing operand"));
333 usage (EXPR_INVALID);
336 args = argv + 1;
338 v = eval (true);
339 if (!nomoreargs ())
340 error (EXPR_INVALID, 0, _("syntax error: unexpected argument %s"),
341 quotearg_n_style (0, locale_quoting_style, *args));
343 printv (v);
345 main_exit (null (v));
348 /* Return a VALUE for I. */
350 static VALUE *
351 int_value (unsigned long int i)
353 VALUE *v = xmalloc (sizeof *v);
354 v->type = integer;
355 mpz_init_set_ui (v->u.i, i);
356 return v;
359 /* Return a VALUE for S. */
361 static VALUE *
362 str_value (char const *s)
364 VALUE *v = xmalloc (sizeof *v);
365 v->type = string;
366 v->u.s = xstrdup (s);
367 return v;
370 /* Free VALUE V, including structure components. */
372 static void
373 freev (VALUE *v)
375 if (v->type == string)
376 free (v->u.s);
377 else
378 mpz_clear (v->u.i);
379 free (v);
382 /* Print VALUE V. */
384 static void
385 printv (VALUE *v)
387 switch (v->type)
389 case integer:
390 mpz_out_str (stdout, 10, v->u.i);
391 putchar ('\n');
392 break;
393 case string:
394 puts (v->u.s);
395 break;
396 default:
397 unreachable ();
401 /* Return true if V is a null-string or zero-number. */
403 ATTRIBUTE_PURE
404 static bool
405 null (VALUE *v)
407 switch (v->type)
409 case integer:
410 return mpz_sgn (v->u.i) == 0;
411 case string:
413 char const *cp = v->u.s;
414 if (*cp == '\0')
415 return true;
417 cp += (*cp == '-');
421 if (*cp != '0')
422 return false;
424 while (*++cp);
426 return true;
428 default:
429 unreachable ();
433 /* Return true if CP takes the form of an integer. */
435 ATTRIBUTE_PURE
436 static bool
437 looks_like_integer (char const *cp)
439 cp += (*cp == '-');
442 if (! ISDIGIT (*cp))
443 return false;
444 while (*++cp);
446 return true;
449 /* Coerce V to a string value (can't fail). */
451 static void
452 tostring (VALUE *v)
454 switch (v->type)
456 case integer:
458 char *s = mpz_get_str (nullptr, 10, v->u.i);
459 mpz_clear (v->u.i);
460 v->u.s = s;
461 v->type = string;
463 break;
464 case string:
465 break;
466 default:
467 unreachable ();
471 /* Coerce V to an integer value. Return true on success, false on failure. */
473 static bool
474 toarith (VALUE *v)
476 switch (v->type)
478 case integer:
479 return true;
480 case string:
482 char *s = v->u.s;
484 if (! looks_like_integer (s))
485 return false;
486 if (mpz_init_set_str (v->u.i, s, 10) != 0)
487 error (EXPR_FAILURE, ERANGE, "%s", (s));
488 free (s);
489 v->type = integer;
490 return true;
492 default:
493 unreachable ();
497 /* Extract a size_t value from an integer value I.
498 If the value is negative, return SIZE_MAX.
499 If the value is too large, return SIZE_MAX - 1. */
500 static size_t
501 getsize (mpz_t i)
503 if (mpz_sgn (i) < 0)
504 return SIZE_MAX;
505 if (mpz_fits_ulong_p (i))
507 unsigned long int ul = mpz_get_ui (i);
508 if (ul < SIZE_MAX)
509 return ul;
511 return SIZE_MAX - 1;
514 /* Return true and advance if the next token matches STR exactly.
515 STR must not be null. */
517 static bool
518 nextarg (char const *str)
520 if (*args == nullptr)
521 return false;
522 else
524 bool r = STREQ (*args, str);
525 args += r;
526 return r;
530 /* Return true if there no more tokens. */
532 static bool
533 nomoreargs (void)
535 return *args == 0;
538 /* Report missing operand.
539 There is an implicit assumption that there was a previous argument,
540 and (args-1) is valid. */
541 static void
542 require_more_args (void)
544 if (nomoreargs ())
545 error (EXPR_INVALID, 0, _("syntax error: missing argument after %s"),
546 quotearg_n_style (0, locale_quoting_style, *(args - 1)));
550 #ifdef EVAL_TRACE
551 /* Print evaluation trace and args remaining. */
553 static void
554 trace (fxn)
555 char *fxn;
557 char **a;
559 printf ("%s:", fxn);
560 for (a = args; *a; a++)
561 printf (" %s", *a);
562 putchar ('\n');
564 #endif
566 /* Do the : operator.
567 SV is the VALUE for the lhs (the string),
568 PV is the VALUE for the rhs (the pattern). */
570 static VALUE *
571 docolon (VALUE *sv, VALUE *pv)
573 VALUE *v;
574 char const *errmsg;
575 struct re_pattern_buffer re_buffer;
576 char fastmap[UCHAR_MAX + 1];
577 struct re_registers re_regs;
578 regoff_t matchlen;
580 tostring (sv);
581 tostring (pv);
583 re_regs.num_regs = 0;
584 re_regs.start = nullptr;
585 re_regs.end = nullptr;
587 re_buffer.buffer = nullptr;
588 re_buffer.allocated = 0;
589 re_buffer.fastmap = fastmap;
590 re_buffer.translate = nullptr;
591 re_syntax_options =
592 RE_SYNTAX_POSIX_BASIC & ~RE_CONTEXT_INVALID_DUP & ~RE_NO_EMPTY_RANGES;
593 errmsg = re_compile_pattern (pv->u.s, strlen (pv->u.s), &re_buffer);
594 if (errmsg)
595 error (EXPR_INVALID, 0, "%s", (errmsg));
596 re_buffer.newline_anchor = 0;
598 matchlen = re_match (&re_buffer, sv->u.s, strlen (sv->u.s), 0, &re_regs);
599 if (0 <= matchlen)
601 /* Were \(...\) used? */
602 if (re_buffer.re_nsub > 0)
604 if (re_regs.end[1] < 0)
605 v = str_value ("");
606 else
608 sv->u.s[re_regs.end[1]] = '\0';
609 v = str_value (sv->u.s + re_regs.start[1]);
612 else
614 /* In multibyte locales, convert the matched offset (=number of bytes)
615 to the number of matched characters. */
616 size_t i = (MB_CUR_MAX == 1
617 ? matchlen
618 : mbs_offset_to_chars (sv->u.s, matchlen));
619 v = int_value (i);
622 else if (matchlen == -1)
624 /* Match failed -- return the right kind of null. */
625 if (re_buffer.re_nsub > 0)
626 v = str_value ("");
627 else
628 v = int_value (0);
630 else
631 error (EXPR_FAILURE,
632 matchlen == -2 ? errno : EOVERFLOW,
633 _("error in regular expression matcher"));
635 if (0 < re_regs.num_regs)
637 free (re_regs.start);
638 free (re_regs.end);
640 re_buffer.fastmap = nullptr;
641 regfree (&re_buffer);
642 return v;
645 /* Handle bare operands and ( expr ) syntax. */
647 static VALUE *
648 eval7 (bool evaluate)
650 VALUE *v;
652 #ifdef EVAL_TRACE
653 trace ("eval7");
654 #endif
655 require_more_args ();
657 if (nextarg ("("))
659 v = eval (evaluate);
660 if (nomoreargs ())
661 error (EXPR_INVALID, 0, _("syntax error: expecting ')' after %s"),
662 quotearg_n_style (0, locale_quoting_style, *(args - 1)));
663 if (!nextarg (")"))
664 error (EXPR_INVALID, 0, _("syntax error: expecting ')' instead of %s"),
665 quotearg_n_style (0, locale_quoting_style, *args));
666 return v;
669 if (nextarg (")"))
670 error (EXPR_INVALID, 0, _("syntax error: unexpected ')'"));
672 return str_value (*args++);
675 /* Handle match, substr, index, and length keywords, and quoting "+". */
677 static VALUE *
678 eval6 (bool evaluate)
680 VALUE *l;
681 VALUE *r;
682 VALUE *v;
683 VALUE *i1;
684 VALUE *i2;
686 #ifdef EVAL_TRACE
687 trace ("eval6");
688 #endif
689 if (nextarg ("+"))
691 require_more_args ();
692 return str_value (*args++);
694 else if (nextarg ("length"))
696 r = eval6 (evaluate);
697 tostring (r);
698 v = int_value (mbslen (r->u.s));
699 freev (r);
700 return v;
702 else if (nextarg ("match"))
704 l = eval6 (evaluate);
705 r = eval6 (evaluate);
706 if (evaluate)
708 v = docolon (l, r);
709 freev (l);
711 else
712 v = l;
713 freev (r);
714 return v;
716 else if (nextarg ("index"))
718 size_t pos;
720 l = eval6 (evaluate);
721 r = eval6 (evaluate);
722 tostring (l);
723 tostring (r);
724 pos = mbs_logical_cspn (l->u.s, r->u.s);
725 v = int_value (pos);
726 freev (l);
727 freev (r);
728 return v;
730 else if (nextarg ("substr"))
732 l = eval6 (evaluate);
733 i1 = eval6 (evaluate);
734 i2 = eval6 (evaluate);
735 tostring (l);
737 if (!toarith (i1) || !toarith (i2))
738 v = str_value ("");
739 else
741 size_t pos = getsize (i1->u.i);
742 size_t len = getsize (i2->u.i);
744 char *s = mbs_logical_substr (l->u.s, pos, len);
745 v = str_value (s);
746 free (s);
748 freev (l);
749 freev (i1);
750 freev (i2);
751 return v;
753 else
754 return eval7 (evaluate);
757 /* Handle : operator (pattern matching).
758 Calls docolon to do the real work. */
760 static VALUE *
761 eval5 (bool evaluate)
763 VALUE *l;
764 VALUE *r;
765 VALUE *v;
767 #ifdef EVAL_TRACE
768 trace ("eval5");
769 #endif
770 l = eval6 (evaluate);
771 while (true)
773 if (nextarg (":"))
775 r = eval6 (evaluate);
776 if (evaluate)
778 v = docolon (l, r);
779 freev (l);
780 l = v;
782 freev (r);
784 else
785 return l;
789 /* Handle *, /, % operators. */
791 static VALUE *
792 eval4 (bool evaluate)
794 VALUE *l;
795 VALUE *r;
796 enum { multiply, divide, mod } fxn;
798 #ifdef EVAL_TRACE
799 trace ("eval4");
800 #endif
801 l = eval5 (evaluate);
802 while (true)
804 if (nextarg ("*"))
805 fxn = multiply;
806 else if (nextarg ("/"))
807 fxn = divide;
808 else if (nextarg ("%"))
809 fxn = mod;
810 else
811 return l;
812 r = eval5 (evaluate);
813 if (evaluate)
815 if (!toarith (l) || !toarith (r))
816 error (EXPR_INVALID, 0, _("non-integer argument"));
817 if (fxn != multiply && mpz_sgn (r->u.i) == 0)
818 error (EXPR_INVALID, 0, _("division by zero"));
819 ((fxn == multiply ? mpz_mul
820 : fxn == divide ? mpz_tdiv_q
821 : mpz_tdiv_r)
822 (l->u.i, l->u.i, r->u.i));
824 freev (r);
828 /* Handle +, - operators. */
830 static VALUE *
831 eval3 (bool evaluate)
833 VALUE *l;
834 VALUE *r;
835 enum { plus, minus } fxn;
837 #ifdef EVAL_TRACE
838 trace ("eval3");
839 #endif
840 l = eval4 (evaluate);
841 while (true)
843 if (nextarg ("+"))
844 fxn = plus;
845 else if (nextarg ("-"))
846 fxn = minus;
847 else
848 return l;
849 r = eval4 (evaluate);
850 if (evaluate)
852 if (!toarith (l) || !toarith (r))
853 error (EXPR_INVALID, 0, _("non-integer argument"));
854 (fxn == plus ? mpz_add : mpz_sub) (l->u.i, l->u.i, r->u.i);
856 freev (r);
860 /* Handle comparisons. */
862 static VALUE *
863 eval2 (bool evaluate)
865 VALUE *l;
867 #ifdef EVAL_TRACE
868 trace ("eval2");
869 #endif
870 l = eval3 (evaluate);
871 while (true)
873 VALUE *r;
874 enum
876 less_than, less_equal, equal, not_equal, greater_equal, greater_than
877 } fxn;
878 bool val = false;
880 if (nextarg ("<"))
881 fxn = less_than;
882 else if (nextarg ("<="))
883 fxn = less_equal;
884 else if (nextarg ("=") || nextarg ("=="))
885 fxn = equal;
886 else if (nextarg ("!="))
887 fxn = not_equal;
888 else if (nextarg (">="))
889 fxn = greater_equal;
890 else if (nextarg (">"))
891 fxn = greater_than;
892 else
893 return l;
894 r = eval3 (evaluate);
896 if (evaluate)
898 int cmp;
899 tostring (l);
900 tostring (r);
902 if (looks_like_integer (l->u.s) && looks_like_integer (r->u.s))
903 cmp = strintcmp (l->u.s, r->u.s);
904 else
906 errno = 0;
907 cmp = strcoll (l->u.s, r->u.s);
909 if (errno)
911 error (0, errno, _("string comparison failed"));
912 error (0, 0, _("set LC_ALL='C' to work around the problem"));
913 error (EXPR_INVALID, 0,
914 _("the strings compared were %s and %s"),
915 quotearg_n_style (0, locale_quoting_style, l->u.s),
916 quotearg_n_style (1, locale_quoting_style, r->u.s));
920 switch (fxn)
922 case less_than: val = (cmp < 0); break;
923 case less_equal: val = (cmp <= 0); break;
924 case equal: val = (cmp == 0); break;
925 case not_equal: val = (cmp != 0); break;
926 case greater_equal: val = (cmp >= 0); break;
927 case greater_than: val = (cmp > 0); break;
928 default: unreachable ();
932 freev (l);
933 freev (r);
934 l = int_value (val);
938 /* Handle &. */
940 static VALUE *
941 eval1 (bool evaluate)
943 VALUE *l;
944 VALUE *r;
946 #ifdef EVAL_TRACE
947 trace ("eval1");
948 #endif
949 l = eval2 (evaluate);
950 while (true)
952 if (nextarg ("&"))
954 r = eval2 (evaluate && !null (l));
955 if (null (l) || null (r))
957 freev (l);
958 freev (r);
959 l = int_value (0);
961 else
962 freev (r);
964 else
965 return l;
969 /* Handle |. */
971 static VALUE *
972 eval (bool evaluate)
974 VALUE *l;
975 VALUE *r;
977 #ifdef EVAL_TRACE
978 trace ("eval");
979 #endif
980 l = eval1 (evaluate);
981 while (true)
983 if (nextarg ("|"))
985 r = eval1 (evaluate && null (l));
986 if (null (l))
988 freev (l);
989 l = r;
990 if (null (l))
992 freev (l);
993 l = int_value (0);
996 else
997 freev (r);
999 else
1000 return l;