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 87230530Scharnierint letcmd(int, char **); 88230530Scharnier 89218466Sjillesstatic __dead2 void yyerror(const char *s) 90218466Sjilles{ 91218466Sjilles error("arithmetic expression: %s: \"%s\"", s, arith_startbuf); 92218466Sjilles /* NOTREACHED */ 93218466Sjilles} 94218466Sjilles 95218466Sjillesstatic arith_t arith_lookupvarint(char *varname) 96218466Sjilles{ 97218466Sjilles const char *str; 98218466Sjilles char *p; 99218466Sjilles arith_t result; 100218466Sjilles 101218466Sjilles str = lookupvar(varname); 102221463Sjilles if (uflag && str == NULL) 103221463Sjilles yyerror("variable not set"); 104218466Sjilles if (str == NULL || *str == '\0') 105218466Sjilles str = "0"; 106218466Sjilles errno = 0; 107218466Sjilles result = strtoarith_t(str, &p, 0); 108218466Sjilles if (errno != 0 || *p != '\0') 109218466Sjilles yyerror("variable conversion error"); 110218466Sjilles return result; 111218466Sjilles} 112218466Sjilles 113218466Sjillesstatic inline int arith_prec(int op) 114218466Sjilles{ 115218466Sjilles return prec[op - ARITH_BINOP_MIN]; 116218466Sjilles} 117218466Sjilles 118218466Sjillesstatic inline int higher_prec(int op1, int op2) 119218466Sjilles{ 120218466Sjilles return arith_prec(op1) < arith_prec(op2); 121218466Sjilles} 122218466Sjilles 123218466Sjillesstatic arith_t do_binop(int op, arith_t a, arith_t b) 124218466Sjilles{ 125218466Sjilles 126218466Sjilles switch (op) { 127218466Sjilles default: 128218466Sjilles case ARITH_REM: 129218466Sjilles case ARITH_DIV: 130218466Sjilles if (!b) 131218466Sjilles yyerror("division by zero"); 132218626Sjilles if (a == ARITH_MIN && b == -1) 133218626Sjilles yyerror("divide error"); 134218466Sjilles return op == ARITH_REM ? a % b : a / b; 135218466Sjilles case ARITH_MUL: 136227369Sjilles return (uintmax_t)a * (uintmax_t)b; 137218466Sjilles case ARITH_ADD: 138227369Sjilles return (uintmax_t)a + (uintmax_t)b; 139218466Sjilles case ARITH_SUB: 140227369Sjilles return (uintmax_t)a - (uintmax_t)b; 141218466Sjilles case ARITH_LSHIFT: 142218466Sjilles return a << b; 143218466Sjilles case ARITH_RSHIFT: 144218466Sjilles return a >> b; 145218466Sjilles case ARITH_LT: 146218466Sjilles return a < b; 147218466Sjilles case ARITH_LE: 148218466Sjilles return a <= b; 149218466Sjilles case ARITH_GT: 150218466Sjilles return a > b; 151218466Sjilles case ARITH_GE: 152218466Sjilles return a >= b; 153218466Sjilles case ARITH_EQ: 154218466Sjilles return a == b; 155218466Sjilles case ARITH_NE: 156218466Sjilles return a != b; 157218466Sjilles case ARITH_BAND: 158218466Sjilles return a & b; 159218466Sjilles case ARITH_BXOR: 160218466Sjilles return a ^ b; 161218466Sjilles case ARITH_BOR: 162218466Sjilles return a | b; 163218466Sjilles } 164218466Sjilles} 165218466Sjilles 166218466Sjillesstatic arith_t assignment(int var, int noeval); 167218466Sjilles 168218466Sjillesstatic arith_t primary(int token, union yystype *val, int op, int noeval) 169218466Sjilles{ 170218466Sjilles arith_t result; 171218466Sjilles 172218466Sjillesagain: 173218466Sjilles switch (token) { 174218466Sjilles case ARITH_LPAREN: 175218466Sjilles result = assignment(op, noeval); 176218466Sjilles if (last_token != ARITH_RPAREN) 177218466Sjilles yyerror("expecting ')'"); 178218466Sjilles last_token = yylex(); 179218466Sjilles return result; 180218466Sjilles case ARITH_NUM: 181218466Sjilles last_token = op; 182218466Sjilles return val->val; 183218466Sjilles case ARITH_VAR: 184218466Sjilles last_token = op; 185218466Sjilles return noeval ? val->val : arith_lookupvarint(val->name); 186218466Sjilles case ARITH_ADD: 187218466Sjilles token = op; 188218466Sjilles *val = yylval; 189218466Sjilles op = yylex(); 190218466Sjilles goto again; 191218466Sjilles case ARITH_SUB: 192218466Sjilles *val = yylval; 193218466Sjilles return -primary(op, val, yylex(), noeval); 194218466Sjilles case ARITH_NOT: 195218466Sjilles *val = yylval; 196218466Sjilles return !primary(op, val, yylex(), noeval); 197218466Sjilles case ARITH_BNOT: 198218466Sjilles *val = yylval; 199218466Sjilles return ~primary(op, val, yylex(), noeval); 200218466Sjilles default: 201218466Sjilles yyerror("expecting primary"); 202218466Sjilles } 203218466Sjilles} 204218466Sjilles 205219306Sjillesstatic arith_t binop2(arith_t a, int op, int precedence, int noeval) 206218466Sjilles{ 207218466Sjilles for (;;) { 208218466Sjilles union yystype val; 209218466Sjilles arith_t b; 210218466Sjilles int op2; 211218466Sjilles int token; 212218466Sjilles 213218466Sjilles token = yylex(); 214218466Sjilles val = yylval; 215218466Sjilles 216218466Sjilles b = primary(token, &val, yylex(), noeval); 217218466Sjilles 218218466Sjilles op2 = last_token; 219218466Sjilles if (op2 >= ARITH_BINOP_MIN && op2 < ARITH_BINOP_MAX && 220218466Sjilles higher_prec(op2, op)) { 221218466Sjilles b = binop2(b, op2, arith_prec(op), noeval); 222218466Sjilles op2 = last_token; 223218466Sjilles } 224218466Sjilles 225218466Sjilles a = noeval ? b : do_binop(op, a, b); 226218466Sjilles 227218466Sjilles if (op2 < ARITH_BINOP_MIN || op2 >= ARITH_BINOP_MAX || 228219306Sjilles arith_prec(op2) >= precedence) 229218466Sjilles return a; 230218466Sjilles 231218466Sjilles op = op2; 232218466Sjilles } 233218466Sjilles} 234218466Sjilles 235218466Sjillesstatic arith_t binop(int token, union yystype *val, int op, int noeval) 236218466Sjilles{ 237218466Sjilles arith_t a = primary(token, val, op, noeval); 238218466Sjilles 239218466Sjilles op = last_token; 240218466Sjilles if (op < ARITH_BINOP_MIN || op >= ARITH_BINOP_MAX) 241218466Sjilles return a; 242218466Sjilles 243218466Sjilles return binop2(a, op, ARITH_MAX_PREC, noeval); 244218466Sjilles} 245218466Sjilles 246218466Sjillesstatic arith_t and(int token, union yystype *val, int op, int noeval) 247218466Sjilles{ 248218466Sjilles arith_t a = binop(token, val, op, noeval); 249218466Sjilles arith_t b; 250218466Sjilles 251218466Sjilles op = last_token; 252218466Sjilles if (op != ARITH_AND) 253218466Sjilles return a; 254218466Sjilles 255218466Sjilles token = yylex(); 256218466Sjilles *val = yylval; 257218466Sjilles 258218466Sjilles b = and(token, val, yylex(), noeval | !a); 259218466Sjilles 260218466Sjilles return a && b; 261218466Sjilles} 262218466Sjilles 263218466Sjillesstatic arith_t or(int token, union yystype *val, int op, int noeval) 264218466Sjilles{ 265218466Sjilles arith_t a = and(token, val, op, noeval); 266218466Sjilles arith_t b; 267218466Sjilles 268218466Sjilles op = last_token; 269218466Sjilles if (op != ARITH_OR) 270218466Sjilles return a; 271218466Sjilles 272218466Sjilles token = yylex(); 273218466Sjilles *val = yylval; 274218466Sjilles 275218466Sjilles b = or(token, val, yylex(), noeval | !!a); 276218466Sjilles 277218466Sjilles return a || b; 278218466Sjilles} 279218466Sjilles 280218466Sjillesstatic arith_t cond(int token, union yystype *val, int op, int noeval) 281218466Sjilles{ 282218466Sjilles arith_t a = or(token, val, op, noeval); 283218466Sjilles arith_t b; 284218466Sjilles arith_t c; 285218466Sjilles 286218466Sjilles if (last_token != ARITH_QMARK) 287218466Sjilles return a; 288218466Sjilles 289218466Sjilles b = assignment(yylex(), noeval | !a); 290218466Sjilles 291218466Sjilles if (last_token != ARITH_COLON) 292218466Sjilles yyerror("expecting ':'"); 293218466Sjilles 294218466Sjilles token = yylex(); 295218466Sjilles *val = yylval; 296218466Sjilles 297218466Sjilles c = cond(token, val, yylex(), noeval | !!a); 298218466Sjilles 299218466Sjilles return a ? b : c; 300218466Sjilles} 301218466Sjilles 302218466Sjillesstatic arith_t assignment(int var, int noeval) 303218466Sjilles{ 304218466Sjilles union yystype val = yylval; 305218466Sjilles int op = yylex(); 306218466Sjilles arith_t result; 307218466Sjilles char sresult[DIGITS(result) + 1]; 308218466Sjilles 309218466Sjilles if (var != ARITH_VAR) 310218466Sjilles return cond(var, &val, op, noeval); 311218466Sjilles 312218466Sjilles if (op != ARITH_ASS && (op < ARITH_ASS_MIN || op >= ARITH_ASS_MAX)) 313218466Sjilles return cond(var, &val, op, noeval); 314218466Sjilles 315218466Sjilles result = assignment(yylex(), noeval); 316218466Sjilles if (noeval) 317218466Sjilles return result; 318218466Sjilles 319218466Sjilles if (op != ARITH_ASS) 320218466Sjilles result = do_binop(op - 11, arith_lookupvarint(val.name), result); 321218466Sjilles snprintf(sresult, sizeof(sresult), ARITH_FORMAT_STR, result); 322218466Sjilles setvar(val.name, sresult, 0); 323218466Sjilles return result; 324218466Sjilles} 325218466Sjilles 326218466Sjillesarith_t arith(const char *s) 327218466Sjilles{ 328218466Sjilles struct stackmark smark; 329218466Sjilles arith_t result; 330218466Sjilles 331218466Sjilles setstackmark(&smark); 332218466Sjilles 333218466Sjilles arith_buf = arith_startbuf = s; 334218466Sjilles 335218466Sjilles result = assignment(yylex(), 0); 336218466Sjilles 337218466Sjilles if (last_token) 338218466Sjilles yyerror("expecting EOF"); 339218466Sjilles 340218466Sjilles popstackmark(&smark); 341218466Sjilles 342218466Sjilles return result; 343218466Sjilles} 344218466Sjilles 345218466Sjilles/* 346218466Sjilles * The exp(1) builtin. 347218466Sjilles */ 348218466Sjillesint 349222386Sjillesletcmd(int argc, char **argv) 350218466Sjilles{ 351218466Sjilles const char *p; 352218466Sjilles char *concat; 353218466Sjilles char **ap; 354218466Sjilles arith_t i; 355218466Sjilles 356218466Sjilles if (argc > 1) { 357218466Sjilles p = argv[1]; 358218466Sjilles if (argc > 2) { 359218466Sjilles /* 360218466Sjilles * Concatenate arguments. 361218466Sjilles */ 362218466Sjilles STARTSTACKSTR(concat); 363218466Sjilles ap = argv + 2; 364218466Sjilles for (;;) { 365218466Sjilles while (*p) 366218466Sjilles STPUTC(*p++, concat); 367218466Sjilles if ((p = *ap++) == NULL) 368218466Sjilles break; 369218466Sjilles STPUTC(' ', concat); 370218466Sjilles } 371218466Sjilles STPUTC('\0', concat); 372218466Sjilles p = grabstackstr(concat); 373218466Sjilles } 374218466Sjilles } else 375218466Sjilles p = ""; 376218466Sjilles 377218466Sjilles i = arith(p); 378218466Sjilles 379218466Sjilles out1fmt(ARITH_FORMAT_STR "\n", i); 380218466Sjilles return !i; 381218466Sjilles} 382