1 /*- 2 * Copyright (c) 1993 3 * The Regents of the University of California. All rights reserved. 4 * Copyright (c) 2007 5 * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * Kenneth Almquist. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 35 #include <sys/cdefs.h> 36 __FBSDID("$FreeBSD$"); 37 38 #include <limits.h> 39 #include <errno.h> 40 #include <inttypes.h> 41 #include <stdlib.h> 42 #include <stdio.h> 43 #include "arith.h" 44 #include "arith_yacc.h" 45 #include "expand.h" 46 #include "shell.h" 47 #include "error.h" 48 #include "memalloc.h" 49 #include "output.h" 50 #include "options.h" 51 #include "var.h" 52 53 #if ARITH_BOR + 11 != ARITH_BORASS || ARITH_ASS + 11 != ARITH_EQ 54 #error Arithmetic tokens are out of order. 55 #endif 56 57 static const char *arith_startbuf; 58 59 const char *arith_buf; 60 union yystype yylval; 61 62 static int last_token; 63 64 #define ARITH_PRECEDENCE(op, prec) [op - ARITH_BINOP_MIN] = prec 65 66 static const char prec[ARITH_BINOP_MAX - ARITH_BINOP_MIN] = { 67 ARITH_PRECEDENCE(ARITH_MUL, 0), 68 ARITH_PRECEDENCE(ARITH_DIV, 0), 69 ARITH_PRECEDENCE(ARITH_REM, 0), 70 ARITH_PRECEDENCE(ARITH_ADD, 1), 71 ARITH_PRECEDENCE(ARITH_SUB, 1), 72 ARITH_PRECEDENCE(ARITH_LSHIFT, 2), 73 ARITH_PRECEDENCE(ARITH_RSHIFT, 2), 74 ARITH_PRECEDENCE(ARITH_LT, 3), 75 ARITH_PRECEDENCE(ARITH_LE, 3), 76 ARITH_PRECEDENCE(ARITH_GT, 3), 77 ARITH_PRECEDENCE(ARITH_GE, 3), 78 ARITH_PRECEDENCE(ARITH_EQ, 4), 79 ARITH_PRECEDENCE(ARITH_NE, 4), 80 ARITH_PRECEDENCE(ARITH_BAND, 5), 81 ARITH_PRECEDENCE(ARITH_BXOR, 6), 82 ARITH_PRECEDENCE(ARITH_BOR, 7), 83 }; 84 85 #define ARITH_MAX_PREC 8 86 87 int letcmd(int, char **); 88 89 static __dead2 void yyerror(const char *s) 90 { 91 error("arithmetic expression: %s: \"%s\"", s, arith_startbuf); 92 /* NOTREACHED */ 93 } 94 95 static arith_t arith_lookupvarint(char *varname) 96 { 97 const char *str; 98 char *p; 99 arith_t result; 100 101 str = lookupvar(varname); 102 if (uflag && str == NULL) 103 yyerror("variable not set"); 104 if (str == NULL || *str == '\0') 105 str = "0"; 106 errno = 0; 107 result = strtoarith_t(str, &p, 0); 108 if (errno != 0 || *p != '\0') 109 yyerror("variable conversion error"); 110 return result; 111 } 112 113 static inline int arith_prec(int op) 114 { 115 return prec[op - ARITH_BINOP_MIN]; 116 } 117 118 static inline int higher_prec(int op1, int op2) 119 { 120 return arith_prec(op1) < arith_prec(op2); 121 } 122 123 static arith_t do_binop(int op, arith_t a, arith_t b) 124 { 125 126 switch (op) { 127 default: 128 case ARITH_REM: 129 case ARITH_DIV: 130 if (!b) 131 yyerror("division by zero"); 132 if (a == ARITH_MIN && b == -1) 133 yyerror("divide error"); 134 return op == ARITH_REM ? a % b : a / b; 135 case ARITH_MUL: 136 return (uintmax_t)a * (uintmax_t)b; 137 case ARITH_ADD: 138 return (uintmax_t)a + (uintmax_t)b; 139 case ARITH_SUB: 140 return (uintmax_t)a - (uintmax_t)b; 141 case ARITH_LSHIFT: 142 return (uintmax_t)a << 143 ((uintmax_t)b & (sizeof(uintmax_t) * CHAR_BIT - 1)); 144 case ARITH_RSHIFT: 145 return a >> ((uintmax_t)b & (sizeof(uintmax_t) * CHAR_BIT - 1)); 146 case ARITH_LT: 147 return a < b; 148 case ARITH_LE: 149 return a <= b; 150 case ARITH_GT: 151 return a > b; 152 case ARITH_GE: 153 return a >= b; 154 case ARITH_EQ: 155 return a == b; 156 case ARITH_NE: 157 return a != b; 158 case ARITH_BAND: 159 return a & b; 160 case ARITH_BXOR: 161 return a ^ b; 162 case ARITH_BOR: 163 return a | b; 164 } 165 } 166 167 static arith_t assignment(int var, int noeval); 168 169 static arith_t primary(int token, union yystype *val, int op, int noeval) 170 { 171 arith_t result; 172 173 again: 174 switch (token) { 175 case ARITH_LPAREN: 176 result = assignment(op, noeval); 177 if (last_token != ARITH_RPAREN) 178 yyerror("expecting ')'"); 179 last_token = yylex(); 180 return result; 181 case ARITH_NUM: 182 last_token = op; 183 return val->val; 184 case ARITH_VAR: 185 last_token = op; 186 return noeval ? val->val : arith_lookupvarint(val->name); 187 case ARITH_ADD: 188 token = op; 189 *val = yylval; 190 op = yylex(); 191 goto again; 192 case ARITH_SUB: 193 *val = yylval; 194 return -primary(op, val, yylex(), noeval); 195 case ARITH_NOT: 196 *val = yylval; 197 return !primary(op, val, yylex(), noeval); 198 case ARITH_BNOT: 199 *val = yylval; 200 return ~primary(op, val, yylex(), noeval); 201 default: 202 yyerror("expecting primary"); 203 } 204 } 205 206 static arith_t binop2(arith_t a, int op, int precedence, int noeval) 207 { 208 for (;;) { 209 union yystype val; 210 arith_t b; 211 int op2; 212 int token; 213 214 token = yylex(); 215 val = yylval; 216 217 b = primary(token, &val, yylex(), noeval); 218 219 op2 = last_token; 220 if (op2 >= ARITH_BINOP_MIN && op2 < ARITH_BINOP_MAX && 221 higher_prec(op2, op)) { 222 b = binop2(b, op2, arith_prec(op), noeval); 223 op2 = last_token; 224 } 225 226 a = noeval ? b : do_binop(op, a, b); 227 228 if (op2 < ARITH_BINOP_MIN || op2 >= ARITH_BINOP_MAX || 229 arith_prec(op2) >= precedence) 230 return a; 231 232 op = op2; 233 } 234 } 235 236 static arith_t binop(int token, union yystype *val, int op, int noeval) 237 { 238 arith_t a = primary(token, val, op, noeval); 239 240 op = last_token; 241 if (op < ARITH_BINOP_MIN || op >= ARITH_BINOP_MAX) 242 return a; 243 244 return binop2(a, op, ARITH_MAX_PREC, noeval); 245 } 246 247 static arith_t and(int token, union yystype *val, int op, int noeval) 248 { 249 arith_t a = binop(token, val, op, noeval); 250 arith_t b; 251 252 op = last_token; 253 if (op != ARITH_AND) 254 return a; 255 256 token = yylex(); 257 *val = yylval; 258 259 b = and(token, val, yylex(), noeval | !a); 260 261 return a && b; 262 } 263 264 static arith_t or(int token, union yystype *val, int op, int noeval) 265 { 266 arith_t a = and(token, val, op, noeval); 267 arith_t b; 268 269 op = last_token; 270 if (op != ARITH_OR) 271 return a; 272 273 token = yylex(); 274 *val = yylval; 275 276 b = or(token, val, yylex(), noeval | !!a); 277 278 return a || b; 279 } 280 281 static arith_t cond(int token, union yystype *val, int op, int noeval) 282 { 283 arith_t a = or(token, val, op, noeval); 284 arith_t b; 285 arith_t c; 286 287 if (last_token != ARITH_QMARK) 288 return a; 289 290 b = assignment(yylex(), noeval | !a); 291 292 if (last_token != ARITH_COLON) 293 yyerror("expecting ':'"); 294 295 token = yylex(); 296 *val = yylval; 297 298 c = cond(token, val, yylex(), noeval | !!a); 299 300 return a ? b : c; 301 } 302 303 static arith_t assignment(int var, int noeval) 304 { 305 union yystype val = yylval; 306 int op = yylex(); 307 arith_t result; 308 char sresult[DIGITS(result) + 1]; 309 310 if (var != ARITH_VAR) 311 return cond(var, &val, op, noeval); 312 313 if (op != ARITH_ASS && (op < ARITH_ASS_MIN || op >= ARITH_ASS_MAX)) 314 return cond(var, &val, op, noeval); 315 316 result = assignment(yylex(), noeval); 317 if (noeval) 318 return result; 319 320 if (op != ARITH_ASS) 321 result = do_binop(op - 11, arith_lookupvarint(val.name), result); 322 snprintf(sresult, sizeof(sresult), ARITH_FORMAT_STR, result); 323 setvar(val.name, sresult, 0); 324 return result; 325 } 326 327 arith_t arith(const char *s) 328 { 329 struct stackmark smark; 330 arith_t result; 331 332 setstackmark(&smark); 333 334 arith_buf = arith_startbuf = s; 335 336 result = assignment(yylex(), 0); 337 338 if (last_token) 339 yyerror("expecting EOF"); 340 341 popstackmark(&smark); 342 343 return result; 344 } 345 346 /* 347 * The exp(1) builtin. 348 */ 349 int 350 letcmd(int argc, char **argv) 351 { 352 const char *p; 353 char *concat; 354 char **ap; 355 arith_t i; 356 357 if (argc > 1) { 358 p = argv[1]; 359 if (argc > 2) { 360 /* 361 * Concatenate arguments. 362 */ 363 STARTSTACKSTR(concat); 364 ap = argv + 2; 365 for (;;) { 366 while (*p) 367 STPUTC(*p++, concat); 368 if ((p = *ap++) == NULL) 369 break; 370 STPUTC(' ', concat); 371 } 372 STPUTC('\0', concat); 373 p = grabstackstr(concat); 374 } 375 } else 376 p = ""; 377 378 i = arith(p); 379 380 out1fmt(ARITH_FORMAT_STR "\n", i); 381 return !i; 382 } 383