arith_yacc.c revision 218466
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: head/bin/sh/arith_yacc.c 218466 2011-02-08 23:18:06Z jilles $"); 37 38#include <sys/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 57static const char *arith_startbuf; 58 59const char *arith_buf; 60union yystype yylval; 61 62static int last_token; 63 64#define ARITH_PRECEDENCE(op, prec) [op - ARITH_BINOP_MIN] = prec 65 66static 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 87static __dead2 void yyerror(const char *s) 88{ 89 error("arithmetic expression: %s: \"%s\"", s, arith_startbuf); 90 /* NOTREACHED */ 91} 92 93static arith_t arith_lookupvarint(char *varname) 94{ 95 const char *str; 96 char *p; 97 arith_t result; 98 99 str = lookupvar(varname); 100 if (str == NULL || *str == '\0') 101 str = "0"; 102 errno = 0; 103 result = strtoarith_t(str, &p, 0); 104 if (errno != 0 || *p != '\0') 105 yyerror("variable conversion error"); 106 return result; 107} 108 109static inline int arith_prec(int op) 110{ 111 return prec[op - ARITH_BINOP_MIN]; 112} 113 114static inline int higher_prec(int op1, int op2) 115{ 116 return arith_prec(op1) < arith_prec(op2); 117} 118 119static arith_t do_binop(int op, arith_t a, arith_t b) 120{ 121 122 switch (op) { 123 default: 124 case ARITH_REM: 125 case ARITH_DIV: 126 if (!b) 127 yyerror("division by zero"); 128 return op == ARITH_REM ? a % b : a / b; 129 case ARITH_MUL: 130 return a * b; 131 case ARITH_ADD: 132 return a + b; 133 case ARITH_SUB: 134 return a - b; 135 case ARITH_LSHIFT: 136 return a << b; 137 case ARITH_RSHIFT: 138 return a >> b; 139 case ARITH_LT: 140 return a < b; 141 case ARITH_LE: 142 return a <= b; 143 case ARITH_GT: 144 return a > b; 145 case ARITH_GE: 146 return a >= b; 147 case ARITH_EQ: 148 return a == b; 149 case ARITH_NE: 150 return a != b; 151 case ARITH_BAND: 152 return a & b; 153 case ARITH_BXOR: 154 return a ^ b; 155 case ARITH_BOR: 156 return a | b; 157 } 158} 159 160static arith_t assignment(int var, int noeval); 161 162static arith_t primary(int token, union yystype *val, int op, int noeval) 163{ 164 arith_t result; 165 166again: 167 switch (token) { 168 case ARITH_LPAREN: 169 result = assignment(op, noeval); 170 if (last_token != ARITH_RPAREN) 171 yyerror("expecting ')'"); 172 last_token = yylex(); 173 return result; 174 case ARITH_NUM: 175 last_token = op; 176 return val->val; 177 case ARITH_VAR: 178 last_token = op; 179 return noeval ? val->val : arith_lookupvarint(val->name); 180 case ARITH_ADD: 181 token = op; 182 *val = yylval; 183 op = yylex(); 184 goto again; 185 case ARITH_SUB: 186 *val = yylval; 187 return -primary(op, val, yylex(), noeval); 188 case ARITH_NOT: 189 *val = yylval; 190 return !primary(op, val, yylex(), noeval); 191 case ARITH_BNOT: 192 *val = yylval; 193 return ~primary(op, val, yylex(), noeval); 194 default: 195 yyerror("expecting primary"); 196 } 197} 198 199static arith_t binop2(arith_t a, int op, int prec, int noeval) 200{ 201 for (;;) { 202 union yystype val; 203 arith_t b; 204 int op2; 205 int token; 206 207 token = yylex(); 208 val = yylval; 209 210 b = primary(token, &val, yylex(), noeval); 211 212 op2 = last_token; 213 if (op2 >= ARITH_BINOP_MIN && op2 < ARITH_BINOP_MAX && 214 higher_prec(op2, op)) { 215 b = binop2(b, op2, arith_prec(op), noeval); 216 op2 = last_token; 217 } 218 219 a = noeval ? b : do_binop(op, a, b); 220 221 if (op2 < ARITH_BINOP_MIN || op2 >= ARITH_BINOP_MAX || 222 arith_prec(op2) >= prec) 223 return a; 224 225 op = op2; 226 } 227} 228 229static arith_t binop(int token, union yystype *val, int op, int noeval) 230{ 231 arith_t a = primary(token, val, op, noeval); 232 233 op = last_token; 234 if (op < ARITH_BINOP_MIN || op >= ARITH_BINOP_MAX) 235 return a; 236 237 return binop2(a, op, ARITH_MAX_PREC, noeval); 238} 239 240static arith_t and(int token, union yystype *val, int op, int noeval) 241{ 242 arith_t a = binop(token, val, op, noeval); 243 arith_t b; 244 245 op = last_token; 246 if (op != ARITH_AND) 247 return a; 248 249 token = yylex(); 250 *val = yylval; 251 252 b = and(token, val, yylex(), noeval | !a); 253 254 return a && b; 255} 256 257static arith_t or(int token, union yystype *val, int op, int noeval) 258{ 259 arith_t a = and(token, val, op, noeval); 260 arith_t b; 261 262 op = last_token; 263 if (op != ARITH_OR) 264 return a; 265 266 token = yylex(); 267 *val = yylval; 268 269 b = or(token, val, yylex(), noeval | !!a); 270 271 return a || b; 272} 273 274static arith_t cond(int token, union yystype *val, int op, int noeval) 275{ 276 arith_t a = or(token, val, op, noeval); 277 arith_t b; 278 arith_t c; 279 280 if (last_token != ARITH_QMARK) 281 return a; 282 283 b = assignment(yylex(), noeval | !a); 284 285 if (last_token != ARITH_COLON) 286 yyerror("expecting ':'"); 287 288 token = yylex(); 289 *val = yylval; 290 291 c = cond(token, val, yylex(), noeval | !!a); 292 293 return a ? b : c; 294} 295 296static arith_t assignment(int var, int noeval) 297{ 298 union yystype val = yylval; 299 int op = yylex(); 300 arith_t result; 301 char sresult[DIGITS(result) + 1]; 302 303 if (var != ARITH_VAR) 304 return cond(var, &val, op, noeval); 305 306 if (op != ARITH_ASS && (op < ARITH_ASS_MIN || op >= ARITH_ASS_MAX)) 307 return cond(var, &val, op, noeval); 308 309 result = assignment(yylex(), noeval); 310 if (noeval) 311 return result; 312 313 if (op != ARITH_ASS) 314 result = do_binop(op - 11, arith_lookupvarint(val.name), result); 315 snprintf(sresult, sizeof(sresult), ARITH_FORMAT_STR, result); 316 setvar(val.name, sresult, 0); 317 return result; 318} 319 320arith_t arith(const char *s) 321{ 322 struct stackmark smark; 323 arith_t result; 324 325 setstackmark(&smark); 326 327 arith_buf = arith_startbuf = s; 328 329 result = assignment(yylex(), 0); 330 331 if (last_token) 332 yyerror("expecting EOF"); 333 334 popstackmark(&smark); 335 336 return result; 337} 338 339/* 340 * The exp(1) builtin. 341 */ 342int 343expcmd(int argc, char **argv) 344{ 345 const char *p; 346 char *concat; 347 char **ap; 348 arith_t i; 349 350 if (argc > 1) { 351 p = argv[1]; 352 if (argc > 2) { 353 /* 354 * Concatenate arguments. 355 */ 356 STARTSTACKSTR(concat); 357 ap = argv + 2; 358 for (;;) { 359 while (*p) 360 STPUTC(*p++, concat); 361 if ((p = *ap++) == NULL) 362 break; 363 STPUTC(' ', concat); 364 } 365 STPUTC('\0', concat); 366 p = grabstackstr(concat); 367 } 368 } else 369 p = ""; 370 371 i = arith(p); 372 373 out1fmt(ARITH_FORMAT_STR "\n", i); 374 return !i; 375} 376 377