1*784b5b67Skamil /* $NetBSD: expr.y,v 1.46 2020/06/11 13:08:07 kamil Exp $ */
23a4441e3Sjdolecek
33a4441e3Sjdolecek /*_
43a4441e3Sjdolecek * Copyright (c) 2000 The NetBSD Foundation, Inc.
53a4441e3Sjdolecek * All rights reserved.
63a4441e3Sjdolecek *
73a4441e3Sjdolecek * This code is derived from software contributed to The NetBSD Foundation
8a15c6f03Sgrant * by Jaromir Dolecek <jdolecek@NetBSD.org> and J.T. Conklin <jtc@NetBSD.org>.
93a4441e3Sjdolecek *
103a4441e3Sjdolecek * Redistribution and use in source and binary forms, with or without
113a4441e3Sjdolecek * modification, are permitted provided that the following conditions
123a4441e3Sjdolecek * are met:
133a4441e3Sjdolecek * 1. Redistributions of source code must retain the above copyright
143a4441e3Sjdolecek * notice, this list of conditions and the following disclaimer.
153a4441e3Sjdolecek * 2. Redistributions in binary form must reproduce the above copyright
163a4441e3Sjdolecek * notice, this list of conditions and the following disclaimer in the
173a4441e3Sjdolecek * documentation and/or other materials provided with the distribution.
183a4441e3Sjdolecek *
198eba9df2Smartin * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
208eba9df2Smartin * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
218eba9df2Smartin * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
228eba9df2Smartin * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
238eba9df2Smartin * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
248eba9df2Smartin * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
258eba9df2Smartin * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
268eba9df2Smartin * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
278eba9df2Smartin * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
288eba9df2Smartin * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
298eba9df2Smartin * POSSIBILITY OF SUCH DAMAGE.
303a4441e3Sjdolecek */
313a4441e3Sjdolecek
323a4441e3Sjdolecek %{
333a4441e3Sjdolecek #include <sys/cdefs.h>
343a4441e3Sjdolecek #ifndef lint
35*784b5b67Skamil __RCSID("$NetBSD: expr.y,v 1.46 2020/06/11 13:08:07 kamil Exp $");
363a4441e3Sjdolecek #endif /* not lint */
373a4441e3Sjdolecek
383a4441e3Sjdolecek #include <sys/types.h>
397a64806dSwiz
403a4441e3Sjdolecek #include <err.h>
413a4441e3Sjdolecek #include <errno.h>
423a4441e3Sjdolecek #include <limits.h>
433a4441e3Sjdolecek #include <locale.h>
443a4441e3Sjdolecek #include <regex.h>
453a4441e3Sjdolecek #include <stdarg.h>
463a4441e3Sjdolecek #include <stdio.h>
473a4441e3Sjdolecek #include <stdlib.h>
483a4441e3Sjdolecek #include <string.h>
493a4441e3Sjdolecek
505888f4d2Sjdolecek static const char * const *av;
513a4441e3Sjdolecek
52370cd318Sjoerg static void yyerror(const char *, ...) __dead;
533a4441e3Sjdolecek static int yylex(void);
543a4441e3Sjdolecek static int is_zero_or_null(const char *);
553a4441e3Sjdolecek static int is_integer(const char *);
56a7755cceSjmc static int64_t perform_arith_op(const char *, const char *, const char *);
57a7755cceSjmc
583a4441e3Sjdolecek #define YYSTYPE const char *
593a4441e3Sjdolecek
603a4441e3Sjdolecek %}
61fb2525abSjdolecek %token STRING
62401ea1afSthorpej %left SPEC_OR
63401ea1afSthorpej %left SPEC_AND
64a7755cceSjmc %left COMPARE
65a7755cceSjmc %left ADD_SUB_OPERATOR
66a7755cceSjmc %left MUL_DIV_MOD_OPERATOR
67a7755cceSjmc %left SPEC_REG
68c92704dcSjdolecek %left LENGTH
693a4441e3Sjdolecek %left LEFT_PARENT RIGHT_PARENT
703a4441e3Sjdolecek
713a4441e3Sjdolecek %%
723a4441e3Sjdolecek
733a4441e3Sjdolecek exp: expr = {
743a4441e3Sjdolecek (void) printf("%s\n", $1);
753a4441e3Sjdolecek return (is_zero_or_null($1));
763a4441e3Sjdolecek }
773a4441e3Sjdolecek ;
783a4441e3Sjdolecek
793a4441e3Sjdolecek expr: item { $$ = $1; }
803a4441e3Sjdolecek | expr SPEC_OR expr = {
813a4441e3Sjdolecek /*
823a4441e3Sjdolecek * Return evaluation of first expression if it is neither
833a4441e3Sjdolecek * an empty string nor zero; otherwise, returns the evaluation
843a4441e3Sjdolecek * of second expression.
853a4441e3Sjdolecek */
863a4441e3Sjdolecek if (!is_zero_or_null($1))
873a4441e3Sjdolecek $$ = $1;
883a4441e3Sjdolecek else
893a4441e3Sjdolecek $$ = $3;
903a4441e3Sjdolecek }
913a4441e3Sjdolecek | expr SPEC_AND expr = {
923a4441e3Sjdolecek /*
933a4441e3Sjdolecek * Returns the evaluation of first expr if neither expression
943a4441e3Sjdolecek * evaluates to an empty string or zero; otherwise, returns
953a4441e3Sjdolecek * zero.
963a4441e3Sjdolecek */
973a4441e3Sjdolecek if (!is_zero_or_null($1) && !is_zero_or_null($3))
983a4441e3Sjdolecek $$ = $1;
993a4441e3Sjdolecek else
1003a4441e3Sjdolecek $$ = "0";
1013a4441e3Sjdolecek }
1023a4441e3Sjdolecek | expr SPEC_REG expr = {
1033a4441e3Sjdolecek /*
1043a4441e3Sjdolecek * The ``:'' operator matches first expr against the second,
1053a4441e3Sjdolecek * which must be a regular expression.
1063a4441e3Sjdolecek */
1073a4441e3Sjdolecek regex_t rp;
1083a4441e3Sjdolecek regmatch_t rm[2];
1093a4441e3Sjdolecek int eval;
1103a4441e3Sjdolecek
1113a4441e3Sjdolecek /* compile regular expression */
112217903eeSjdolecek if ((eval = regcomp(&rp, $3, REG_BASIC)) != 0) {
113a82fc402Sjdolecek char errbuf[256];
1143a4441e3Sjdolecek (void)regerror(eval, &rp, errbuf, sizeof(errbuf));
1153a4441e3Sjdolecek yyerror("%s", errbuf);
1163a4441e3Sjdolecek /* NOT REACHED */
1173a4441e3Sjdolecek }
1183a4441e3Sjdolecek
1193a4441e3Sjdolecek /* compare string against pattern -- remember that patterns
1203a4441e3Sjdolecek are anchored to the beginning of the line */
1213a4441e3Sjdolecek if (regexec(&rp, $1, 2, rm, 0) == 0 && rm[0].rm_so == 0) {
1223a4441e3Sjdolecek char *val;
1233a4441e3Sjdolecek if (rm[1].rm_so >= 0) {
124fd6eeb2eSjdolecek (void) asprintf(&val, "%.*s",
125a82fc402Sjdolecek (int) (rm[1].rm_eo - rm[1].rm_so),
126a82fc402Sjdolecek $1 + rm[1].rm_so);
1273a4441e3Sjdolecek } else {
1283a4441e3Sjdolecek (void) asprintf(&val, "%d",
1293a4441e3Sjdolecek (int)(rm[0].rm_eo - rm[0].rm_so));
1303a4441e3Sjdolecek }
1312174dda2Srumble if (val == NULL)
1322174dda2Srumble err(1, NULL);
1333a4441e3Sjdolecek $$ = val;
1343a4441e3Sjdolecek } else {
1353a4441e3Sjdolecek if (rp.re_nsub == 0) {
1363a4441e3Sjdolecek $$ = "0";
1373a4441e3Sjdolecek } else {
1383a4441e3Sjdolecek $$ = "";
1393a4441e3Sjdolecek }
1403a4441e3Sjdolecek }
1413a4441e3Sjdolecek
1423a4441e3Sjdolecek }
143a7755cceSjmc | expr ADD_SUB_OPERATOR expr = {
144a7755cceSjmc /* Returns the results of addition, subtraction */
145a7755cceSjmc char *val;
146a7755cceSjmc int64_t res;
147a7755cceSjmc
148a7755cceSjmc res = perform_arith_op($1, $2, $3);
149a7755cceSjmc (void) asprintf(&val, "%lld", (long long int) res);
1502174dda2Srumble if (val == NULL)
1512174dda2Srumble err(1, NULL);
152a7755cceSjmc $$ = val;
153a7755cceSjmc }
154a7755cceSjmc
155a7755cceSjmc | expr MUL_DIV_MOD_OPERATOR expr = {
1563a4441e3Sjdolecek /*
157a7755cceSjmc * Returns the results of multiply, divide or remainder of
158a7755cceSjmc * numeric-valued arguments.
1593a4441e3Sjdolecek */
1603a4441e3Sjdolecek char *val;
161a7755cceSjmc int64_t res;
1623a4441e3Sjdolecek
163a7755cceSjmc res = perform_arith_op($1, $2, $3);
1643a4441e3Sjdolecek (void) asprintf(&val, "%lld", (long long int) res);
1652174dda2Srumble if (val == NULL)
1662174dda2Srumble err(1, NULL);
1673a4441e3Sjdolecek $$ = val;
1683a4441e3Sjdolecek
1693a4441e3Sjdolecek }
1703a4441e3Sjdolecek | expr COMPARE expr = {
1713a4441e3Sjdolecek /*
1723a4441e3Sjdolecek * Returns the results of integer comparison if both arguments
1733a4441e3Sjdolecek * are integers; otherwise, returns the results of string
1743a4441e3Sjdolecek * comparison using the locale-specific collation sequence.
1753a4441e3Sjdolecek * The result of each comparison is 1 if the specified relation
1763a4441e3Sjdolecek * is true, or 0 if the relation is false.
1773a4441e3Sjdolecek */
1783a4441e3Sjdolecek
1793a4441e3Sjdolecek int64_t l, r;
1803a4441e3Sjdolecek int res;
1813a4441e3Sjdolecek
1825760da63Slukem res = 0;
1835760da63Slukem
1843a4441e3Sjdolecek /*
1853a4441e3Sjdolecek * Slight hack to avoid differences in the compare code
1863a4441e3Sjdolecek * between string and numeric compare.
1873a4441e3Sjdolecek */
1883a4441e3Sjdolecek if (is_integer($1) && is_integer($3)) {
1893a4441e3Sjdolecek /* numeric comparison */
1903a4441e3Sjdolecek l = strtoll($1, NULL, 10);
1913a4441e3Sjdolecek r = strtoll($3, NULL, 10);
1923a4441e3Sjdolecek } else {
1933a4441e3Sjdolecek /* string comparison */
1943a4441e3Sjdolecek l = strcoll($1, $3);
1953a4441e3Sjdolecek r = 0;
1963a4441e3Sjdolecek }
1973a4441e3Sjdolecek
1983a4441e3Sjdolecek switch($2[0]) {
1993a4441e3Sjdolecek case '=': /* equal */
2003a4441e3Sjdolecek res = (l == r);
2013a4441e3Sjdolecek break;
2023a4441e3Sjdolecek case '>': /* greater or greater-equal */
2033a4441e3Sjdolecek if ($2[1] == '=')
2043a4441e3Sjdolecek res = (l >= r);
2053a4441e3Sjdolecek else
2063a4441e3Sjdolecek res = (l > r);
2073a4441e3Sjdolecek break;
2083a4441e3Sjdolecek case '<': /* lower or lower-equal */
2093a4441e3Sjdolecek if ($2[1] == '=')
2103a4441e3Sjdolecek res = (l <= r);
2113a4441e3Sjdolecek else
2123a4441e3Sjdolecek res = (l < r);
2133a4441e3Sjdolecek break;
2143a4441e3Sjdolecek case '!': /* not equal */
2153a4441e3Sjdolecek /* the check if this is != was done in yylex() */
2163a4441e3Sjdolecek res = (l != r);
2173a4441e3Sjdolecek }
2183a4441e3Sjdolecek
2193a4441e3Sjdolecek $$ = (res) ? "1" : "0";
2203a4441e3Sjdolecek
2213a4441e3Sjdolecek }
2223a4441e3Sjdolecek | LEFT_PARENT expr RIGHT_PARENT { $$ = $2; }
223c92704dcSjdolecek | LENGTH expr {
224c92704dcSjdolecek /*
225c92704dcSjdolecek * Return length of 'expr' in bytes.
226c92704dcSjdolecek */
227c92704dcSjdolecek char *ln;
228c92704dcSjdolecek
229c92704dcSjdolecek asprintf(&ln, "%ld", (long) strlen($2));
2302174dda2Srumble if (ln == NULL)
2312174dda2Srumble err(1, NULL);
232c92704dcSjdolecek $$ = ln;
233c92704dcSjdolecek }
2343a4441e3Sjdolecek ;
2353a4441e3Sjdolecek
2363a4441e3Sjdolecek item: STRING
237a7755cceSjmc | ADD_SUB_OPERATOR
238a7755cceSjmc | MUL_DIV_MOD_OPERATOR
2393a4441e3Sjdolecek | COMPARE
2403a4441e3Sjdolecek | SPEC_OR
2413a4441e3Sjdolecek | SPEC_AND
2423a4441e3Sjdolecek | SPEC_REG
243c92704dcSjdolecek | LENGTH
2443a4441e3Sjdolecek ;
2453a4441e3Sjdolecek %%
2463a4441e3Sjdolecek
2473a4441e3Sjdolecek /*
2483a4441e3Sjdolecek * Returns 1 if the string is empty or contains only numeric zero.
2493a4441e3Sjdolecek */
2503a4441e3Sjdolecek static int
2513a4441e3Sjdolecek is_zero_or_null(const char *str)
2523a4441e3Sjdolecek {
2533a4441e3Sjdolecek char *endptr;
2543a4441e3Sjdolecek
2553a4441e3Sjdolecek return str[0] == '\0'
2563a4441e3Sjdolecek || ( strtoll(str, &endptr, 10) == 0LL
2573a4441e3Sjdolecek && endptr[0] == '\0');
2583a4441e3Sjdolecek }
2593a4441e3Sjdolecek
2603a4441e3Sjdolecek /*
2613a4441e3Sjdolecek * Returns 1 if the string is an integer.
2623a4441e3Sjdolecek */
2633a4441e3Sjdolecek static int
is_integer(const char * str)2643a4441e3Sjdolecek is_integer(const char *str)
2653a4441e3Sjdolecek {
2663a4441e3Sjdolecek char *endptr;
2673a4441e3Sjdolecek
2683a4441e3Sjdolecek (void) strtoll(str, &endptr, 10);
2693a4441e3Sjdolecek /* note we treat empty string as valid number */
2703a4441e3Sjdolecek return (endptr[0] == '\0');
2713a4441e3Sjdolecek }
2723a4441e3Sjdolecek
273a7755cceSjmc static int64_t
perform_arith_op(const char * left,const char * op,const char * right)274a7755cceSjmc perform_arith_op(const char *left, const char *op, const char *right)
275a7755cceSjmc {
2767806b479Skamil int64_t res, l, r;
277a7755cceSjmc
2785760da63Slukem res = 0;
2795760da63Slukem
280a7755cceSjmc if (!is_integer(left)) {
281a7755cceSjmc yyerror("non-integer argument '%s'", left);
282a7755cceSjmc /* NOTREACHED */
283a7755cceSjmc }
284a7755cceSjmc if (!is_integer(right)) {
285a7755cceSjmc yyerror("non-integer argument '%s'", right);
286a7755cceSjmc /* NOTREACHED */
287a7755cceSjmc }
288a7755cceSjmc
289a7755cceSjmc errno = 0;
290a7755cceSjmc l = strtoll(left, NULL, 10);
291a7755cceSjmc if (errno == ERANGE) {
292a7755cceSjmc yyerror("value '%s' is %s is %lld", left,
293a7755cceSjmc (l > 0) ? "too big, maximum" : "too small, minimum",
294a7755cceSjmc (l > 0) ? LLONG_MAX : LLONG_MIN);
295a7755cceSjmc /* NOTREACHED */
296a7755cceSjmc }
297a7755cceSjmc
298a7755cceSjmc errno = 0;
299a7755cceSjmc r = strtoll(right, NULL, 10);
300a7755cceSjmc if (errno == ERANGE) {
301a7755cceSjmc yyerror("value '%s' is %s is %lld", right,
302a7755cceSjmc (l > 0) ? "too big, maximum" : "too small, minimum",
303a7755cceSjmc (l > 0) ? LLONG_MAX : LLONG_MIN);
304a7755cceSjmc /* NOTREACHED */
305a7755cceSjmc }
306a7755cceSjmc
307a7755cceSjmc switch(op[0]) {
308a7755cceSjmc case '+':
30964e6a11aSjmc /*
3107806b479Skamil * Check for over-& underflow.
31164e6a11aSjmc */
3122537a420Skamil if ((l >= 0 && r <= INT64_MAX - l) ||
3132537a420Skamil (l <= 0 && r >= INT64_MIN - l)) {
3147806b479Skamil res = l + r;
3157806b479Skamil } else {
316a7755cceSjmc yyerror("integer overflow or underflow occurred for "
317a7755cceSjmc "operation '%s %s %s'", left, op, right);
3187806b479Skamil }
319a7755cceSjmc break;
320a7755cceSjmc case '-':
32164e6a11aSjmc /*
3227806b479Skamil * Check for over-& underflow.
32364e6a11aSjmc */
3247806b479Skamil if ((r > 0 && l < INT64_MIN + r) ||
3257806b479Skamil (r < 0 && l > INT64_MAX + r)) {
326a7755cceSjmc yyerror("integer overflow or underflow occurred for "
327a7755cceSjmc "operation '%s %s %s'", left, op, right);
3287806b479Skamil } else {
3297806b479Skamil res = l - r;
3307806b479Skamil }
331a7755cceSjmc break;
332a7755cceSjmc case '/':
33364e6a11aSjmc if (r == 0)
334a7755cceSjmc yyerror("second argument to '%s' must not be zero", op);
3357806b479Skamil if (l == INT64_MIN && r == -1)
3367806b479Skamil yyerror("integer overflow or underflow occurred for "
3377806b479Skamil "operation '%s %s %s'", left, op, right);
338a7755cceSjmc res = l / r;
339a7755cceSjmc
340a7755cceSjmc break;
341a7755cceSjmc case '%':
34264e6a11aSjmc if (r == 0)
343a7755cceSjmc yyerror("second argument to '%s' must not be zero", op);
3447806b479Skamil if (l == INT64_MIN && r == -1)
3457806b479Skamil yyerror("integer overflow or underflow occurred for "
3467806b479Skamil "operation '%s %s %s'", left, op, right);
347a7755cceSjmc res = l % r;
348a7755cceSjmc break;
349a7755cceSjmc case '*':
3507806b479Skamil /*
3517806b479Skamil * Check for over-& underflow.
3527806b479Skamil */
3537806b479Skamil
3542b5da4d0Skamil /*
3552b5da4d0Skamil * Simplify the conditions:
3562b5da4d0Skamil * - remove the case of both negative arguments
3572b5da4d0Skamil * unless the operation will cause an overflow
3582b5da4d0Skamil */
3597806b479Skamil if (l < 0 && r < 0 && l != INT64_MIN && r != INT64_MIN) {
3607806b479Skamil l = -l;
3617806b479Skamil r = -r;
362a7755cceSjmc }
363a7755cceSjmc
364*784b5b67Skamil /* - remove the case of negative l and positive r */
3652b5da4d0Skamil if (l < 0 && r >= 0) {
3662b5da4d0Skamil /* Use res as a temporary variable */
3672b5da4d0Skamil res = l;
3682b5da4d0Skamil l = r;
3692b5da4d0Skamil r = res;
3702b5da4d0Skamil }
3712b5da4d0Skamil
3727806b479Skamil if ((l < 0 && r < 0) ||
3732b5da4d0Skamil (r > 0 && l > INT64_MAX / r) ||
3742597218cSkamil (r <= 0 && l != 0 && r < INT64_MIN / l)) {
37564e6a11aSjmc yyerror("integer overflow or underflow occurred for "
37664e6a11aSjmc "operation '%s %s %s'", left, op, right);
37764e6a11aSjmc /* NOTREACHED */
3787806b479Skamil } else {
3797806b479Skamil res = l * r;
3807806b479Skamil }
381a7755cceSjmc break;
382a7755cceSjmc }
383a7755cceSjmc return res;
384a7755cceSjmc }
3853a4441e3Sjdolecek
3865888f4d2Sjdolecek static const char *x = "|&=<>+-*/%:()";
3875888f4d2Sjdolecek static const int x_token[] = {
388a7755cceSjmc SPEC_OR, SPEC_AND, COMPARE, COMPARE, COMPARE, ADD_SUB_OPERATOR,
389a7755cceSjmc ADD_SUB_OPERATOR, MUL_DIV_MOD_OPERATOR, MUL_DIV_MOD_OPERATOR,
390a7755cceSjmc MUL_DIV_MOD_OPERATOR, SPEC_REG, LEFT_PARENT, RIGHT_PARENT
3913a4441e3Sjdolecek };
3923a4441e3Sjdolecek
3935888f4d2Sjdolecek static int handle_ddash = 1;
3945888f4d2Sjdolecek
3953a4441e3Sjdolecek int
yylex(void)3963a4441e3Sjdolecek yylex(void)
3973a4441e3Sjdolecek {
3983a4441e3Sjdolecek const char *p = *av++;
3995888f4d2Sjdolecek int retval;
4003a4441e3Sjdolecek
4015888f4d2Sjdolecek if (!p)
4025888f4d2Sjdolecek retval = 0;
4035888f4d2Sjdolecek else if (p[1] == '\0') {
4043a4441e3Sjdolecek const char *w = strchr(x, p[0]);
4053a4441e3Sjdolecek if (w) {
4063a4441e3Sjdolecek retval = x_token[w-x];
4073a4441e3Sjdolecek } else {
4083a4441e3Sjdolecek retval = STRING;
4093a4441e3Sjdolecek }
4103a4441e3Sjdolecek } else if (p[1] == '=' && p[2] == '\0'
4113a4441e3Sjdolecek && (p[0] == '>' || p[0] == '<' || p[0] == '!'))
4123a4441e3Sjdolecek retval = COMPARE;
4135888f4d2Sjdolecek else if (handle_ddash && p[0] == '-' && p[1] == '-' && p[2] == '\0') {
4145888f4d2Sjdolecek /* ignore "--" if passed as first argument and isn't followed
4155888f4d2Sjdolecek * by another STRING */
4165888f4d2Sjdolecek retval = yylex();
4175888f4d2Sjdolecek if (retval != STRING && retval != LEFT_PARENT
4185888f4d2Sjdolecek && retval != RIGHT_PARENT) {
4195888f4d2Sjdolecek /* is not followed by string or parenthesis, use as
4205888f4d2Sjdolecek * STRING */
4215888f4d2Sjdolecek retval = STRING;
4225888f4d2Sjdolecek av--; /* was increased in call to yylex() above */
4235888f4d2Sjdolecek p = "--";
4245888f4d2Sjdolecek } else {
4255888f4d2Sjdolecek /* "--" is to be ignored */
4265888f4d2Sjdolecek p = yylval;
4275888f4d2Sjdolecek }
428c92704dcSjdolecek } else if (strcmp(p, "length") == 0)
429c92704dcSjdolecek retval = LENGTH;
430c92704dcSjdolecek else
4313a4441e3Sjdolecek retval = STRING;
4323a4441e3Sjdolecek
4335888f4d2Sjdolecek handle_ddash = 0;
4343a4441e3Sjdolecek yylval = p;
4353a4441e3Sjdolecek
4363a4441e3Sjdolecek return retval;
4373a4441e3Sjdolecek }
4383a4441e3Sjdolecek
4393a4441e3Sjdolecek /*
4403a4441e3Sjdolecek * Print error message and exit with error 2 (syntax error).
4413a4441e3Sjdolecek */
44266dd2755Sjoerg static __printflike(1, 2) void
yyerror(const char * fmt,...)4433a4441e3Sjdolecek yyerror(const char *fmt, ...)
4443a4441e3Sjdolecek {
4453a4441e3Sjdolecek va_list arg;
4463a4441e3Sjdolecek
4473a4441e3Sjdolecek va_start(arg, fmt);
4483a4441e3Sjdolecek verrx(2, fmt, arg);
4493a4441e3Sjdolecek va_end(arg);
4503a4441e3Sjdolecek }
4513a4441e3Sjdolecek
4523a4441e3Sjdolecek int
main(int argc,const char * const * argv)4535888f4d2Sjdolecek main(int argc, const char * const *argv)
4543a4441e3Sjdolecek {
4557a64806dSwiz setprogname(argv[0]);
4563a4441e3Sjdolecek (void)setlocale(LC_ALL, "");
4573a4441e3Sjdolecek
45857921160Sjoerg if (argc == 1) {
45957921160Sjoerg (void)fprintf(stderr, "usage: %s expression\n",
46057921160Sjoerg getprogname());
46157921160Sjoerg exit(2);
46257921160Sjoerg }
46357921160Sjoerg
4643a4441e3Sjdolecek av = argv + 1;
4653a4441e3Sjdolecek
466721572cdSchristos return yyparse();
4673a4441e3Sjdolecek }
468