1218466Sjilles/*- 2218466Sjilles * Copyright (c) 1993 3218466Sjilles * The Regents of the University of California. All rights reserved. 4218466Sjilles * Copyright (c) 2007 5218466Sjilles * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved. 6218466Sjilles * 7218466Sjilles * This code is derived from software contributed to Berkeley by 8218466Sjilles * Kenneth Almquist. 9218466Sjilles * 10218466Sjilles * Redistribution and use in source and binary forms, with or without 11218466Sjilles * modification, are permitted provided that the following conditions 12218466Sjilles * are met: 13218466Sjilles * 1. Redistributions of source code must retain the above copyright 14218466Sjilles * notice, this list of conditions and the following disclaimer. 15218466Sjilles * 2. Redistributions in binary form must reproduce the above copyright 16218466Sjilles * notice, this list of conditions and the following disclaimer in the 17218466Sjilles * documentation and/or other materials provided with the distribution. 18218466Sjilles * 3. Neither the name of the University nor the names of its contributors 19218466Sjilles * may be used to endorse or promote products derived from this software 20218466Sjilles * without specific prior written permission. 21218466Sjilles * 22218466Sjilles * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23218466Sjilles * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24218466Sjilles * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25218466Sjilles * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26218466Sjilles * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27218466Sjilles * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28218466Sjilles * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29218466Sjilles * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30218466Sjilles * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31218466Sjilles * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32218466Sjilles * SUCH DAMAGE. 33218466Sjilles */ 34218466Sjilles 35218466Sjilles#include <sys/cdefs.h> 36218466Sjilles__FBSDID("$FreeBSD$"); 37218466Sjilles 38223580Sjilles#include <limits.h> 39218466Sjilles#include <errno.h> 40218466Sjilles#include <inttypes.h> 41218466Sjilles#include <stdlib.h> 42218466Sjilles#include <stdio.h> 43218466Sjilles#include "arith.h" 44218466Sjilles#include "arith_yacc.h" 45218466Sjilles#include "expand.h" 46218466Sjilles#include "shell.h" 47218466Sjilles#include "error.h" 48218466Sjilles#include "memalloc.h" 49218466Sjilles#include "output.h" 50218466Sjilles#include "options.h" 51218466Sjilles#include "var.h" 52218466Sjilles 53218466Sjilles#if ARITH_BOR + 11 != ARITH_BORASS || ARITH_ASS + 11 != ARITH_EQ 54218466Sjilles#error Arithmetic tokens are out of order. 55218466Sjilles#endif 56218466Sjilles 57218466Sjillesstatic const char *arith_startbuf; 58218466Sjilles 59218466Sjillesconst char *arith_buf; 60218466Sjillesunion yystype yylval; 61218466Sjilles 62218466Sjillesstatic int last_token; 63218466Sjilles 64218466Sjilles#define ARITH_PRECEDENCE(op, prec) [op - ARITH_BINOP_MIN] = prec 65218466Sjilles 66218466Sjillesstatic const char prec[ARITH_BINOP_MAX - ARITH_BINOP_MIN] = { 67218466Sjilles ARITH_PRECEDENCE(ARITH_MUL, 0), 68218466Sjilles ARITH_PRECEDENCE(ARITH_DIV, 0), 69218466Sjilles ARITH_PRECEDENCE(ARITH_REM, 0), 70218466Sjilles ARITH_PRECEDENCE(ARITH_ADD, 1), 71218466Sjilles ARITH_PRECEDENCE(ARITH_SUB, 1), 72218466Sjilles ARITH_PRECEDENCE(ARITH_LSHIFT, 2), 73218466Sjilles ARITH_PRECEDENCE(ARITH_RSHIFT, 2), 74218466Sjilles ARITH_PRECEDENCE(ARITH_LT, 3), 75218466Sjilles ARITH_PRECEDENCE(ARITH_LE, 3), 76218466Sjilles ARITH_PRECEDENCE(ARITH_GT, 3), 77218466Sjilles ARITH_PRECEDENCE(ARITH_GE, 3), 78218466Sjilles ARITH_PRECEDENCE(ARITH_EQ, 4), 79218466Sjilles ARITH_PRECEDENCE(ARITH_NE, 4), 80218466Sjilles ARITH_PRECEDENCE(ARITH_BAND, 5), 81218466Sjilles ARITH_PRECEDENCE(ARITH_BXOR, 6), 82218466Sjilles ARITH_PRECEDENCE(ARITH_BOR, 7), 83218466Sjilles}; 84218466Sjilles 85218466Sjilles#define ARITH_MAX_PREC 8 86218466Sjilles 87218466Sjillesstatic __dead2 void yyerror(const char *s) 88218466Sjilles{ 89218466Sjilles error("arithmetic expression: %s: \"%s\"", s, arith_startbuf); 90218466Sjilles /* NOTREACHED */ 91218466Sjilles} 92218466Sjilles 93218466Sjillesstatic arith_t arith_lookupvarint(char *varname) 94218466Sjilles{ 95218466Sjilles const char *str; 96218466Sjilles char *p; 97218466Sjilles arith_t result; 98218466Sjilles 99218466Sjilles str = lookupvar(varname); 100221463Sjilles if (uflag && str == NULL) 101221463Sjilles yyerror("variable not set"); 102218466Sjilles if (str == NULL || *str == '\0') 103218466Sjilles str = "0"; 104218466Sjilles errno = 0; 105218466Sjilles result = strtoarith_t(str, &p, 0); 106218466Sjilles if (errno != 0 || *p != '\0') 107218466Sjilles yyerror("variable conversion error"); 108218466Sjilles return result; 109218466Sjilles} 110218466Sjilles 111218466Sjillesstatic inline int arith_prec(int op) 112218466Sjilles{ 113218466Sjilles return prec[op - ARITH_BINOP_MIN]; 114218466Sjilles} 115218466Sjilles 116218466Sjillesstatic inline int higher_prec(int op1, int op2) 117218466Sjilles{ 118218466Sjilles return arith_prec(op1) < arith_prec(op2); 119218466Sjilles} 120218466Sjilles 121218466Sjillesstatic arith_t do_binop(int op, arith_t a, arith_t b) 122218466Sjilles{ 123218466Sjilles 124218466Sjilles switch (op) { 125218466Sjilles default: 126218466Sjilles case ARITH_REM: 127218466Sjilles case ARITH_DIV: 128218466Sjilles if (!b) 129218466Sjilles yyerror("division by zero"); 130218626Sjilles if (a == ARITH_MIN && b == -1) 131218626Sjilles yyerror("divide error"); 132218466Sjilles return op == ARITH_REM ? a % b : a / b; 133218466Sjilles case ARITH_MUL: 134218466Sjilles return a * b; 135218466Sjilles case ARITH_ADD: 136218466Sjilles return a + b; 137218466Sjilles case ARITH_SUB: 138218466Sjilles return a - b; 139218466Sjilles case ARITH_LSHIFT: 140218466Sjilles return a << b; 141218466Sjilles case ARITH_RSHIFT: 142218466Sjilles return a >> b; 143218466Sjilles case ARITH_LT: 144218466Sjilles return a < b; 145218466Sjilles case ARITH_LE: 146218466Sjilles return a <= b; 147218466Sjilles case ARITH_GT: 148218466Sjilles return a > b; 149218466Sjilles case ARITH_GE: 150218466Sjilles return a >= b; 151218466Sjilles case ARITH_EQ: 152218466Sjilles return a == b; 153218466Sjilles case ARITH_NE: 154218466Sjilles return a != b; 155218466Sjilles case ARITH_BAND: 156218466Sjilles return a & b; 157218466Sjilles case ARITH_BXOR: 158218466Sjilles return a ^ b; 159218466Sjilles case ARITH_BOR: 160218466Sjilles return a | b; 161218466Sjilles } 162218466Sjilles} 163218466Sjilles 164218466Sjillesstatic arith_t assignment(int var, int noeval); 165218466Sjilles 166218466Sjillesstatic arith_t primary(int token, union yystype *val, int op, int noeval) 167218466Sjilles{ 168218466Sjilles arith_t result; 169218466Sjilles 170218466Sjillesagain: 171218466Sjilles switch (token) { 172218466Sjilles case ARITH_LPAREN: 173218466Sjilles result = assignment(op, noeval); 174218466Sjilles if (last_token != ARITH_RPAREN) 175218466Sjilles yyerror("expecting ')'"); 176218466Sjilles last_token = yylex(); 177218466Sjilles return result; 178218466Sjilles case ARITH_NUM: 179218466Sjilles last_token = op; 180218466Sjilles return val->val; 181218466Sjilles case ARITH_VAR: 182218466Sjilles last_token = op; 183218466Sjilles return noeval ? val->val : arith_lookupvarint(val->name); 184218466Sjilles case ARITH_ADD: 185218466Sjilles token = op; 186218466Sjilles *val = yylval; 187218466Sjilles op = yylex(); 188218466Sjilles goto again; 189218466Sjilles case ARITH_SUB: 190218466Sjilles *val = yylval; 191218466Sjilles return -primary(op, val, yylex(), noeval); 192218466Sjilles case ARITH_NOT: 193218466Sjilles *val = yylval; 194218466Sjilles return !primary(op, val, yylex(), noeval); 195218466Sjilles case ARITH_BNOT: 196218466Sjilles *val = yylval; 197218466Sjilles return ~primary(op, val, yylex(), noeval); 198218466Sjilles default: 199218466Sjilles yyerror("expecting primary"); 200218466Sjilles } 201218466Sjilles} 202218466Sjilles 203219306Sjillesstatic arith_t binop2(arith_t a, int op, int precedence, int noeval) 204218466Sjilles{ 205218466Sjilles for (;;) { 206218466Sjilles union yystype val; 207218466Sjilles arith_t b; 208218466Sjilles int op2; 209218466Sjilles int token; 210218466Sjilles 211218466Sjilles token = yylex(); 212218466Sjilles val = yylval; 213218466Sjilles 214218466Sjilles b = primary(token, &val, yylex(), noeval); 215218466Sjilles 216218466Sjilles op2 = last_token; 217218466Sjilles if (op2 >= ARITH_BINOP_MIN && op2 < ARITH_BINOP_MAX && 218218466Sjilles higher_prec(op2, op)) { 219218466Sjilles b = binop2(b, op2, arith_prec(op), noeval); 220218466Sjilles op2 = last_token; 221218466Sjilles } 222218466Sjilles 223218466Sjilles a = noeval ? b : do_binop(op, a, b); 224218466Sjilles 225218466Sjilles if (op2 < ARITH_BINOP_MIN || op2 >= ARITH_BINOP_MAX || 226219306Sjilles arith_prec(op2) >= precedence) 227218466Sjilles return a; 228218466Sjilles 229218466Sjilles op = op2; 230218466Sjilles } 231218466Sjilles} 232218466Sjilles 233218466Sjillesstatic arith_t binop(int token, union yystype *val, int op, int noeval) 234218466Sjilles{ 235218466Sjilles arith_t a = primary(token, val, op, noeval); 236218466Sjilles 237218466Sjilles op = last_token; 238218466Sjilles if (op < ARITH_BINOP_MIN || op >= ARITH_BINOP_MAX) 239218466Sjilles return a; 240218466Sjilles 241218466Sjilles return binop2(a, op, ARITH_MAX_PREC, noeval); 242218466Sjilles} 243218466Sjilles 244218466Sjillesstatic arith_t and(int token, union yystype *val, int op, int noeval) 245218466Sjilles{ 246218466Sjilles arith_t a = binop(token, val, op, noeval); 247218466Sjilles arith_t b; 248218466Sjilles 249218466Sjilles op = last_token; 250218466Sjilles if (op != ARITH_AND) 251218466Sjilles return a; 252218466Sjilles 253218466Sjilles token = yylex(); 254218466Sjilles *val = yylval; 255218466Sjilles 256218466Sjilles b = and(token, val, yylex(), noeval | !a); 257218466Sjilles 258218466Sjilles return a && b; 259218466Sjilles} 260218466Sjilles 261218466Sjillesstatic arith_t or(int token, union yystype *val, int op, int noeval) 262218466Sjilles{ 263218466Sjilles arith_t a = and(token, val, op, noeval); 264218466Sjilles arith_t b; 265218466Sjilles 266218466Sjilles op = last_token; 267218466Sjilles if (op != ARITH_OR) 268218466Sjilles return a; 269218466Sjilles 270218466Sjilles token = yylex(); 271218466Sjilles *val = yylval; 272218466Sjilles 273218466Sjilles b = or(token, val, yylex(), noeval | !!a); 274218466Sjilles 275218466Sjilles return a || b; 276218466Sjilles} 277218466Sjilles 278218466Sjillesstatic arith_t cond(int token, union yystype *val, int op, int noeval) 279218466Sjilles{ 280218466Sjilles arith_t a = or(token, val, op, noeval); 281218466Sjilles arith_t b; 282218466Sjilles arith_t c; 283218466Sjilles 284218466Sjilles if (last_token != ARITH_QMARK) 285218466Sjilles return a; 286218466Sjilles 287218466Sjilles b = assignment(yylex(), noeval | !a); 288218466Sjilles 289218466Sjilles if (last_token != ARITH_COLON) 290218466Sjilles yyerror("expecting ':'"); 291218466Sjilles 292218466Sjilles token = yylex(); 293218466Sjilles *val = yylval; 294218466Sjilles 295218466Sjilles c = cond(token, val, yylex(), noeval | !!a); 296218466Sjilles 297218466Sjilles return a ? b : c; 298218466Sjilles} 299218466Sjilles 300218466Sjillesstatic arith_t assignment(int var, int noeval) 301218466Sjilles{ 302218466Sjilles union yystype val = yylval; 303218466Sjilles int op = yylex(); 304218466Sjilles arith_t result; 305218466Sjilles char sresult[DIGITS(result) + 1]; 306218466Sjilles 307218466Sjilles if (var != ARITH_VAR) 308218466Sjilles return cond(var, &val, op, noeval); 309218466Sjilles 310218466Sjilles if (op != ARITH_ASS && (op < ARITH_ASS_MIN || op >= ARITH_ASS_MAX)) 311218466Sjilles return cond(var, &val, op, noeval); 312218466Sjilles 313218466Sjilles result = assignment(yylex(), noeval); 314218466Sjilles if (noeval) 315218466Sjilles return result; 316218466Sjilles 317218466Sjilles if (op != ARITH_ASS) 318218466Sjilles result = do_binop(op - 11, arith_lookupvarint(val.name), result); 319218466Sjilles snprintf(sresult, sizeof(sresult), ARITH_FORMAT_STR, result); 320218466Sjilles setvar(val.name, sresult, 0); 321218466Sjilles return result; 322218466Sjilles} 323218466Sjilles 324218466Sjillesarith_t arith(const char *s) 325218466Sjilles{ 326218466Sjilles struct stackmark smark; 327218466Sjilles arith_t result; 328218466Sjilles 329218466Sjilles setstackmark(&smark); 330218466Sjilles 331218466Sjilles arith_buf = arith_startbuf = s; 332218466Sjilles 333218466Sjilles result = assignment(yylex(), 0); 334218466Sjilles 335218466Sjilles if (last_token) 336218466Sjilles yyerror("expecting EOF"); 337218466Sjilles 338218466Sjilles popstackmark(&smark); 339218466Sjilles 340218466Sjilles return result; 341218466Sjilles} 342218466Sjilles 343218466Sjilles/* 344218466Sjilles * The exp(1) builtin. 345218466Sjilles */ 346218466Sjillesint 347222386Sjillesletcmd(int argc, char **argv) 348218466Sjilles{ 349218466Sjilles const char *p; 350218466Sjilles char *concat; 351218466Sjilles char **ap; 352218466Sjilles arith_t i; 353218466Sjilles 354218466Sjilles if (argc > 1) { 355218466Sjilles p = argv[1]; 356218466Sjilles if (argc > 2) { 357218466Sjilles /* 358218466Sjilles * Concatenate arguments. 359218466Sjilles */ 360218466Sjilles STARTSTACKSTR(concat); 361218466Sjilles ap = argv + 2; 362218466Sjilles for (;;) { 363218466Sjilles while (*p) 364218466Sjilles STPUTC(*p++, concat); 365218466Sjilles if ((p = *ap++) == NULL) 366218466Sjilles break; 367218466Sjilles STPUTC(' ', concat); 368218466Sjilles } 369218466Sjilles STPUTC('\0', concat); 370218466Sjilles p = grabstackstr(concat); 371218466Sjilles } 372218466Sjilles } else 373218466Sjilles p = ""; 374218466Sjilles 375218466Sjilles i = arith(p); 376218466Sjilles 377218466Sjilles out1fmt(ARITH_FORMAT_STR "\n", i); 378218466Sjilles return !i; 379218466Sjilles} 380218466Sjilles 381