arith_yacc.c revision 221463
155714Skris/*- 255714Skris * Copyright (c) 1993 355714Skris * The Regents of the University of California. All rights reserved. 455714Skris * Copyright (c) 2007 555714Skris * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved. 655714Skris * 755714Skris * This code is derived from software contributed to Berkeley by 855714Skris * Kenneth Almquist. 955714Skris * 1055714Skris * Redistribution and use in source and binary forms, with or without 1155714Skris * modification, are permitted provided that the following conditions 1255714Skris * are met: 1355714Skris * 1. Redistributions of source code must retain the above copyright 1455714Skris * notice, this list of conditions and the following disclaimer. 1555714Skris * 2. Redistributions in binary form must reproduce the above copyright 1655714Skris * notice, this list of conditions and the following disclaimer in the 1755714Skris * documentation and/or other materials provided with the distribution. 1855714Skris * 3. Neither the name of the University nor the names of its contributors 1955714Skris * may be used to endorse or promote products derived from this software 2055714Skris * without specific prior written permission. 2155714Skris * 2255714Skris * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2355714Skris * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2455714Skris * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2555714Skris * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2655714Skris * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2755714Skris * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2855714Skris * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2955714Skris * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3055714Skris * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3155714Skris * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3255714Skris * SUCH DAMAGE. 3355714Skris */ 3455714Skris 3555714Skris#include <sys/cdefs.h> 3655714Skris__FBSDID("$FreeBSD: head/bin/sh/arith_yacc.c 221463 2011-05-04 22:12:22Z jilles $"); 3755714Skris 3855714Skris#include <sys/limits.h> 3955714Skris#include <errno.h> 4055714Skris#include <inttypes.h> 4155714Skris#include <stdlib.h> 4255714Skris#include <stdio.h> 4355714Skris#include "arith.h" 4455714Skris#include "arith_yacc.h" 4555714Skris#include "expand.h" 4655714Skris#include "shell.h" 4755714Skris#include "error.h" 4855714Skris#include "memalloc.h" 4955714Skris#include "output.h" 5055714Skris#include "options.h" 5155714Skris#include "var.h" 5255714Skris 5355714Skris#if ARITH_BOR + 11 != ARITH_BORASS || ARITH_ASS + 11 != ARITH_EQ 5455714Skris#error Arithmetic tokens are out of order. 5555714Skris#endif 5655714Skris 5755714Skrisstatic const char *arith_startbuf; 5855714Skris 5955714Skrisconst char *arith_buf; 6055714Skrisunion yystype yylval; 6155714Skris 6255714Skrisstatic int last_token; 6355714Skris 6455714Skris#define ARITH_PRECEDENCE(op, prec) [op - ARITH_BINOP_MIN] = prec 6555714Skris 6668651Skrisstatic const char prec[ARITH_BINOP_MAX - ARITH_BINOP_MIN] = { 6768651Skris ARITH_PRECEDENCE(ARITH_MUL, 0), 6868651Skris ARITH_PRECEDENCE(ARITH_DIV, 0), 6955714Skris ARITH_PRECEDENCE(ARITH_REM, 0), 7055714Skris ARITH_PRECEDENCE(ARITH_ADD, 1), 7155714Skris ARITH_PRECEDENCE(ARITH_SUB, 1), 7255714Skris ARITH_PRECEDENCE(ARITH_LSHIFT, 2), 7355714Skris ARITH_PRECEDENCE(ARITH_RSHIFT, 2), 7455714Skris ARITH_PRECEDENCE(ARITH_LT, 3), 7555714Skris ARITH_PRECEDENCE(ARITH_LE, 3), 7655714Skris ARITH_PRECEDENCE(ARITH_GT, 3), 7755714Skris ARITH_PRECEDENCE(ARITH_GE, 3), 7855714Skris ARITH_PRECEDENCE(ARITH_EQ, 4), 7955714Skris ARITH_PRECEDENCE(ARITH_NE, 4), 8055714Skris ARITH_PRECEDENCE(ARITH_BAND, 5), 8155714Skris ARITH_PRECEDENCE(ARITH_BXOR, 6), 8255714Skris ARITH_PRECEDENCE(ARITH_BOR, 7), 8355714Skris}; 8455714Skris 8555714Skris#define ARITH_MAX_PREC 8 8655714Skris 8755714Skrisstatic __dead2 void yyerror(const char *s) 8855714Skris{ 8955714Skris error("arithmetic expression: %s: \"%s\"", s, arith_startbuf); 9055714Skris /* NOTREACHED */ 9155714Skris} 9255714Skris 9355714Skrisstatic arith_t arith_lookupvarint(char *varname) 9455714Skris{ 9555714Skris const char *str; 9655714Skris char *p; 9755714Skris arith_t result; 9855714Skris 9955714Skris str = lookupvar(varname); 10055714Skris if (uflag && str == NULL) 10155714Skris yyerror("variable not set"); 10255714Skris if (str == NULL || *str == '\0') 10355714Skris str = "0"; 10455714Skris errno = 0; 10555714Skris result = strtoarith_t(str, &p, 0); 10655714Skris if (errno != 0 || *p != '\0') 10755714Skris yyerror("variable conversion error"); 10855714Skris return result; 10955714Skris} 11055714Skris 11155714Skrisstatic inline int arith_prec(int op) 112{ 113 return prec[op - ARITH_BINOP_MIN]; 114} 115 116static inline int higher_prec(int op1, int op2) 117{ 118 return arith_prec(op1) < arith_prec(op2); 119} 120 121static arith_t do_binop(int op, arith_t a, arith_t b) 122{ 123 124 switch (op) { 125 default: 126 case ARITH_REM: 127 case ARITH_DIV: 128 if (!b) 129 yyerror("division by zero"); 130 if (a == ARITH_MIN && b == -1) 131 yyerror("divide error"); 132 return op == ARITH_REM ? a % b : a / b; 133 case ARITH_MUL: 134 return a * b; 135 case ARITH_ADD: 136 return a + b; 137 case ARITH_SUB: 138 return a - b; 139 case ARITH_LSHIFT: 140 return a << b; 141 case ARITH_RSHIFT: 142 return a >> b; 143 case ARITH_LT: 144 return a < b; 145 case ARITH_LE: 146 return a <= b; 147 case ARITH_GT: 148 return a > b; 149 case ARITH_GE: 150 return a >= b; 151 case ARITH_EQ: 152 return a == b; 153 case ARITH_NE: 154 return a != b; 155 case ARITH_BAND: 156 return a & b; 157 case ARITH_BXOR: 158 return a ^ b; 159 case ARITH_BOR: 160 return a | b; 161 } 162} 163 164static arith_t assignment(int var, int noeval); 165 166static arith_t primary(int token, union yystype *val, int op, int noeval) 167{ 168 arith_t result; 169 170again: 171 switch (token) { 172 case ARITH_LPAREN: 173 result = assignment(op, noeval); 174 if (last_token != ARITH_RPAREN) 175 yyerror("expecting ')'"); 176 last_token = yylex(); 177 return result; 178 case ARITH_NUM: 179 last_token = op; 180 return val->val; 181 case ARITH_VAR: 182 last_token = op; 183 return noeval ? val->val : arith_lookupvarint(val->name); 184 case ARITH_ADD: 185 token = op; 186 *val = yylval; 187 op = yylex(); 188 goto again; 189 case ARITH_SUB: 190 *val = yylval; 191 return -primary(op, val, yylex(), noeval); 192 case ARITH_NOT: 193 *val = yylval; 194 return !primary(op, val, yylex(), noeval); 195 case ARITH_BNOT: 196 *val = yylval; 197 return ~primary(op, val, yylex(), noeval); 198 default: 199 yyerror("expecting primary"); 200 } 201} 202 203static arith_t binop2(arith_t a, int op, int precedence, int noeval) 204{ 205 for (;;) { 206 union yystype val; 207 arith_t b; 208 int op2; 209 int token; 210 211 token = yylex(); 212 val = yylval; 213 214 b = primary(token, &val, yylex(), noeval); 215 216 op2 = last_token; 217 if (op2 >= ARITH_BINOP_MIN && op2 < ARITH_BINOP_MAX && 218 higher_prec(op2, op)) { 219 b = binop2(b, op2, arith_prec(op), noeval); 220 op2 = last_token; 221 } 222 223 a = noeval ? b : do_binop(op, a, b); 224 225 if (op2 < ARITH_BINOP_MIN || op2 >= ARITH_BINOP_MAX || 226 arith_prec(op2) >= precedence) 227 return a; 228 229 op = op2; 230 } 231} 232 233static arith_t binop(int token, union yystype *val, int op, int noeval) 234{ 235 arith_t a = primary(token, val, op, noeval); 236 237 op = last_token; 238 if (op < ARITH_BINOP_MIN || op >= ARITH_BINOP_MAX) 239 return a; 240 241 return binop2(a, op, ARITH_MAX_PREC, noeval); 242} 243 244static arith_t and(int token, union yystype *val, int op, int noeval) 245{ 246 arith_t a = binop(token, val, op, noeval); 247 arith_t b; 248 249 op = last_token; 250 if (op != ARITH_AND) 251 return a; 252 253 token = yylex(); 254 *val = yylval; 255 256 b = and(token, val, yylex(), noeval | !a); 257 258 return a && b; 259} 260 261static arith_t or(int token, union yystype *val, int op, int noeval) 262{ 263 arith_t a = and(token, val, op, noeval); 264 arith_t b; 265 266 op = last_token; 267 if (op != ARITH_OR) 268 return a; 269 270 token = yylex(); 271 *val = yylval; 272 273 b = or(token, val, yylex(), noeval | !!a); 274 275 return a || b; 276} 277 278static arith_t cond(int token, union yystype *val, int op, int noeval) 279{ 280 arith_t a = or(token, val, op, noeval); 281 arith_t b; 282 arith_t c; 283 284 if (last_token != ARITH_QMARK) 285 return a; 286 287 b = assignment(yylex(), noeval | !a); 288 289 if (last_token != ARITH_COLON) 290 yyerror("expecting ':'"); 291 292 token = yylex(); 293 *val = yylval; 294 295 c = cond(token, val, yylex(), noeval | !!a); 296 297 return a ? b : c; 298} 299 300static arith_t assignment(int var, int noeval) 301{ 302 union yystype val = yylval; 303 int op = yylex(); 304 arith_t result; 305 char sresult[DIGITS(result) + 1]; 306 307 if (var != ARITH_VAR) 308 return cond(var, &val, op, noeval); 309 310 if (op != ARITH_ASS && (op < ARITH_ASS_MIN || op >= ARITH_ASS_MAX)) 311 return cond(var, &val, op, noeval); 312 313 result = assignment(yylex(), noeval); 314 if (noeval) 315 return result; 316 317 if (op != ARITH_ASS) 318 result = do_binop(op - 11, arith_lookupvarint(val.name), result); 319 snprintf(sresult, sizeof(sresult), ARITH_FORMAT_STR, result); 320 setvar(val.name, sresult, 0); 321 return result; 322} 323 324arith_t arith(const char *s) 325{ 326 struct stackmark smark; 327 arith_t result; 328 329 setstackmark(&smark); 330 331 arith_buf = arith_startbuf = s; 332 333 result = assignment(yylex(), 0); 334 335 if (last_token) 336 yyerror("expecting EOF"); 337 338 popstackmark(&smark); 339 340 return result; 341} 342 343/* 344 * The exp(1) builtin. 345 */ 346int 347expcmd(int argc, char **argv) 348{ 349 const char *p; 350 char *concat; 351 char **ap; 352 arith_t i; 353 354 if (argc > 1) { 355 p = argv[1]; 356 if (argc > 2) { 357 /* 358 * Concatenate arguments. 359 */ 360 STARTSTACKSTR(concat); 361 ap = argv + 2; 362 for (;;) { 363 while (*p) 364 STPUTC(*p++, concat); 365 if ((p = *ap++) == NULL) 366 break; 367 STPUTC(' ', concat); 368 } 369 STPUTC('\0', concat); 370 p = grabstackstr(concat); 371 } 372 } else 373 p = ""; 374 375 i = arith(p); 376 377 out1fmt(ARITH_FORMAT_STR "\n", i); 378 return !i; 379} 380 381