arith_yacc.c revision 222386
1279377Simp/*- 2279377Simp * Copyright (c) 1993 3279377Simp * The Regents of the University of California. All rights reserved. 4279377Simp * Copyright (c) 2007 5279377Simp * Herbert Xu <herbert@gondor.apana.org.au>. All rights reserved. 6279377Simp * 7279377Simp * This code is derived from software contributed to Berkeley by 8279377Simp * Kenneth Almquist. 9279377Simp * 10279377Simp * Redistribution and use in source and binary forms, with or without 11279377Simp * modification, are permitted provided that the following conditions 12279377Simp * are met: 13279377Simp * 1. Redistributions of source code must retain the above copyright 14279377Simp * notice, this list of conditions and the following disclaimer. 15279377Simp * 2. Redistributions in binary form must reproduce the above copyright 16279377Simp * notice, this list of conditions and the following disclaimer in the 17279377Simp * documentation and/or other materials provided with the distribution. 18279377Simp * 3. Neither the name of the University nor the names of its contributors 19279377Simp * may be used to endorse or promote products derived from this software 20279377Simp * without specific prior written permission. 21279377Simp * 22279377Simp * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23279377Simp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24279377Simp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25279377Simp * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26279377Simp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27279377Simp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28279377Simp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29279377Simp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30279377Simp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31279377Simp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32279377Simp * SUCH DAMAGE. 33279377Simp */ 34279377Simp 35279377Simp#include <sys/cdefs.h> 36279377Simp__FBSDID("$FreeBSD: head/bin/sh/arith_yacc.c 222386 2011-05-27 20:53:07Z jilles $"); 37279377Simp 38279377Simp#include <sys/limits.h> 39279377Simp#include <errno.h> 40279377Simp#include <inttypes.h> 41279377Simp#include <stdlib.h> 42279377Simp#include <stdio.h> 43279377Simp#include "arith.h" 44279377Simp#include "arith_yacc.h" 45279377Simp#include "expand.h" 46279377Simp#include "shell.h" 47295436Sandrew#include "error.h" 48279377Simp#include "memalloc.h" 49279377Simp#include "output.h" 50279377Simp#include "options.h" 51295436Sandrew#include "var.h" 52295436Sandrew 53295436Sandrew#if ARITH_BOR + 11 != ARITH_BORASS || ARITH_ASS + 11 != ARITH_EQ 54295436Sandrew#error Arithmetic tokens are out of order. 55295436Sandrew#endif 56295436Sandrew 57295436Sandrewstatic const char *arith_startbuf; 58295436Sandrew 59279377Simpconst char *arith_buf; 60279377Simpunion yystype yylval; 61279377Simp 62279377Simpstatic int last_token; 63279377Simp 64279377Simp#define ARITH_PRECEDENCE(op, prec) [op - ARITH_BINOP_MIN] = prec 65279377Simp 66295436Sandrewstatic const char prec[ARITH_BINOP_MAX - ARITH_BINOP_MIN] = { 67295436Sandrew ARITH_PRECEDENCE(ARITH_MUL, 0), 68295436Sandrew ARITH_PRECEDENCE(ARITH_DIV, 0), 69295436Sandrew ARITH_PRECEDENCE(ARITH_REM, 0), 70295436Sandrew ARITH_PRECEDENCE(ARITH_ADD, 1), 71295436Sandrew ARITH_PRECEDENCE(ARITH_SUB, 1), 72295436Sandrew ARITH_PRECEDENCE(ARITH_LSHIFT, 2), 73295436Sandrew ARITH_PRECEDENCE(ARITH_RSHIFT, 2), 74295436Sandrew ARITH_PRECEDENCE(ARITH_LT, 3), 75295436Sandrew ARITH_PRECEDENCE(ARITH_LE, 3), 76295436Sandrew ARITH_PRECEDENCE(ARITH_GT, 3), 77295436Sandrew ARITH_PRECEDENCE(ARITH_GE, 3), 78295436Sandrew ARITH_PRECEDENCE(ARITH_EQ, 4), 79295436Sandrew ARITH_PRECEDENCE(ARITH_NE, 4), 80295436Sandrew ARITH_PRECEDENCE(ARITH_BAND, 5), 81295436Sandrew ARITH_PRECEDENCE(ARITH_BXOR, 6), 82279377Simp ARITH_PRECEDENCE(ARITH_BOR, 7), 83279377Simp}; 84279377Simp 85279377Simp#define ARITH_MAX_PREC 8 86279377Simp 87279377Simpstatic __dead2 void yyerror(const char *s) 88279377Simp{ 89279377Simp error("arithmetic expression: %s: \"%s\"", s, arith_startbuf); 90279377Simp /* NOTREACHED */ 91279377Simp} 92279377Simp 93279377Simpstatic arith_t arith_lookupvarint(char *varname) 94279377Simp{ 95279377Simp const char *str; 96279377Simp char *p; 97279377Simp arith_t result; 98279377Simp 99279377Simp str = lookupvar(varname); 100279377Simp if (uflag && str == NULL) 101279377Simp yyerror("variable not set"); 102279377Simp if (str == NULL || *str == '\0') 103279377Simp str = "0"; 104279377Simp errno = 0; 105279377Simp result = strtoarith_t(str, &p, 0); 106279377Simp if (errno != 0 || *p != '\0') 107279377Simp yyerror("variable conversion error"); 108279377Simp return result; 109279377Simp} 110279377Simp 111279377Simpstatic inline int arith_prec(int op) 112279377Simp{ 113279377Simp return prec[op - ARITH_BINOP_MIN]; 114279377Simp} 115279377Simp 116279377Simpstatic inline int higher_prec(int op1, int op2) 117279377Simp{ 118279377Simp return arith_prec(op1) < arith_prec(op2); 119279377Simp} 120279377Simp 121279377Simpstatic arith_t do_binop(int op, arith_t a, arith_t b) 122279377Simp{ 123295436Sandrew 124279377Simp switch (op) { 125279377Simp default: 126279377Simp case ARITH_REM: 127279377Simp case ARITH_DIV: 128279377Simp if (!b) 129279377Simp yyerror("division by zero"); 130279377Simp if (a == ARITH_MIN && b == -1) 131279377Simp yyerror("divide error"); 132279377Simp return op == ARITH_REM ? a % b : a / b; 133279377Simp case ARITH_MUL: 134279377Simp return a * b; 135279377Simp case ARITH_ADD: 136279377Simp return a + b; 137279377Simp case ARITH_SUB: 138279377Simp return a - b; 139279377Simp case ARITH_LSHIFT: 140279377Simp return a << b; 141279377Simp case ARITH_RSHIFT: 142279377Simp return a >> b; 143279377Simp case ARITH_LT: 144279377Simp return a < b; 145279377Simp case ARITH_LE: 146279377Simp return a <= b; 147279377Simp case ARITH_GT: 148279377Simp return a > b; 149279377Simp case ARITH_GE: 150279377Simp return a >= b; 151279377Simp case ARITH_EQ: 152279377Simp return a == b; 153279377Simp case ARITH_NE: 154279377Simp return a != b; 155279377Simp case ARITH_BAND: 156279377Simp return a & b; 157279377Simp case ARITH_BXOR: 158279377Simp return a ^ b; 159279377Simp case ARITH_BOR: 160279377Simp return a | b; 161279377Simp } 162279377Simp} 163279377Simp 164279377Simpstatic arith_t assignment(int var, int noeval); 165279377Simp 166279377Simpstatic arith_t primary(int token, union yystype *val, int op, int noeval) 167279377Simp{ 168279377Simp arith_t result; 169279377Simp 170279377Simpagain: 171279377Simp switch (token) { 172279377Simp case ARITH_LPAREN: 173279377Simp result = assignment(op, noeval); 174279377Simp if (last_token != ARITH_RPAREN) 175279377Simp yyerror("expecting ')'"); 176279377Simp last_token = yylex(); 177279377Simp return result; 178279377Simp case ARITH_NUM: 179279377Simp last_token = op; 180279377Simp return val->val; 181279377Simp case ARITH_VAR: 182279377Simp last_token = op; 183279377Simp return noeval ? val->val : arith_lookupvarint(val->name); 184279377Simp case ARITH_ADD: 185279377Simp token = op; 186279377Simp *val = yylval; 187295436Sandrew op = yylex(); 188295436Sandrew goto again; 189295436Sandrew case ARITH_SUB: 190295436Sandrew *val = yylval; 191295436Sandrew return -primary(op, val, yylex(), noeval); 192295436Sandrew case ARITH_NOT: 193295436Sandrew *val = yylval; 194295436Sandrew return !primary(op, val, yylex(), noeval); 195295436Sandrew case ARITH_BNOT: 196295436Sandrew *val = yylval; 197295436Sandrew return ~primary(op, val, yylex(), noeval); 198295436Sandrew default: 199295436Sandrew yyerror("expecting primary"); 200295436Sandrew } 201295436Sandrew} 202295436Sandrew 203295436Sandrewstatic arith_t binop2(arith_t a, int op, int precedence, int noeval) 204279377Simp{ 205279377Simp for (;;) { 206279377Simp union yystype val; 207279377Simp arith_t b; 208279377Simp int op2; 209279377Simp int token; 210279377Simp 211279377Simp token = yylex(); 212279377Simp val = yylval; 213279377Simp 214279377Simp b = primary(token, &val, yylex(), noeval); 215279377Simp 216279377Simp op2 = last_token; 217279377Simp if (op2 >= ARITH_BINOP_MIN && op2 < ARITH_BINOP_MAX && 218279377Simp higher_prec(op2, op)) { 219279377Simp b = binop2(b, op2, arith_prec(op), noeval); 220279377Simp op2 = last_token; 221279377Simp } 222279377Simp 223279377Simp a = noeval ? b : do_binop(op, a, b); 224295436Sandrew 225295436Sandrew if (op2 < ARITH_BINOP_MIN || op2 >= ARITH_BINOP_MAX || 226295436Sandrew arith_prec(op2) >= precedence) 227295436Sandrew return a; 228295436Sandrew 229295436Sandrew op = op2; 230295436Sandrew } 231295436Sandrew} 232295436Sandrew 233295436Sandrewstatic arith_t binop(int token, union yystype *val, int op, int noeval) 234295436Sandrew{ 235295436Sandrew arith_t a = primary(token, val, op, noeval); 236295436Sandrew 237295436Sandrew op = last_token; 238295436Sandrew if (op < ARITH_BINOP_MIN || op >= ARITH_BINOP_MAX) 239295436Sandrew return a; 240279377Simp 241279377Simp return binop2(a, op, ARITH_MAX_PREC, noeval); 242279377Simp} 243279377Simp 244279377Simpstatic arith_t and(int token, union yystype *val, int op, int noeval) 245279377Simp{ 246279377Simp arith_t a = binop(token, val, op, noeval); 247279377Simp arith_t b; 248279377Simp 249279377Simp op = last_token; 250279377Simp if (op != ARITH_AND) 251279377Simp return a; 252279377Simp 253279377Simp token = yylex(); 254279377Simp *val = yylval; 255279377Simp 256279377Simp b = and(token, val, yylex(), noeval | !a); 257279377Simp 258295436Sandrew return a && b; 259295436Sandrew} 260279377Simp 261279377Simpstatic arith_t or(int token, union yystype *val, int op, int noeval) 262279377Simp{ 263279377Simp arith_t a = and(token, val, op, noeval); 264279377Simp arith_t b; 265279377Simp 266279377Simp op = last_token; 267279377Simp if (op != ARITH_OR) 268279377Simp return a; 269279377Simp 270279377Simp token = yylex(); 271279377Simp *val = yylval; 272279377Simp 273279377Simp b = or(token, val, yylex(), noeval | !!a); 274279377Simp 275279377Simp return a || b; 276279377Simp} 277279377Simp 278279377Simpstatic arith_t cond(int token, union yystype *val, int op, int noeval) 279279377Simp{ 280279377Simp arith_t a = or(token, val, op, noeval); 281279377Simp arith_t b; 282279377Simp arith_t c; 283279377Simp 284279377Simp if (last_token != ARITH_QMARK) 285279377Simp return a; 286279377Simp 287279377Simp b = assignment(yylex(), noeval | !a); 288279377Simp 289279377Simp if (last_token != ARITH_COLON) 290279377Simp yyerror("expecting ':'"); 291279377Simp 292279377Simp token = yylex(); 293295436Sandrew *val = yylval; 294295436Sandrew 295295436Sandrew c = cond(token, val, yylex(), noeval | !!a); 296295436Sandrew 297295436Sandrew return a ? b : c; 298295436Sandrew} 299295436Sandrew 300295436Sandrewstatic arith_t assignment(int var, int noeval) 301279377Simp{ 302279377Simp union yystype val = yylval; 303279377Simp int op = yylex(); 304279377Simp arith_t result; 305279377Simp char sresult[DIGITS(result) + 1]; 306279377Simp 307279377Simp if (var != ARITH_VAR) 308279377Simp return cond(var, &val, op, noeval); 309279377Simp 310279377Simp if (op != ARITH_ASS && (op < ARITH_ASS_MIN || op >= ARITH_ASS_MAX)) 311279377Simp return cond(var, &val, op, noeval); 312279377Simp 313279377Simp result = assignment(yylex(), noeval); 314279377Simp if (noeval) 315279377Simp return result; 316279377Simp 317279377Simp if (op != ARITH_ASS) 318279377Simp result = do_binop(op - 11, arith_lookupvarint(val.name), result); 319279377Simp snprintf(sresult, sizeof(sresult), ARITH_FORMAT_STR, result); 320279377Simp setvar(val.name, sresult, 0); 321279377Simp return result; 322279377Simp} 323279377Simp 324279377Simparith_t arith(const char *s) 325279377Simp{ 326279377Simp struct stackmark smark; 327279377Simp arith_t result; 328279377Simp 329279377Simp setstackmark(&smark); 330279377Simp 331279377Simp arith_buf = arith_startbuf = s; 332279377Simp 333279377Simp result = assignment(yylex(), 0); 334279377Simp 335279377Simp if (last_token) 336279377Simp yyerror("expecting EOF"); 337279377Simp 338279377Simp popstackmark(&smark); 339279377Simp 340279377Simp return result; 341279377Simp} 342279377Simp 343279377Simp/* 344279377Simp * The exp(1) builtin. 345279377Simp */ 346279377Simpint 347279377Simpletcmd(int argc, char **argv) 348279377Simp{ 349279377Simp const char *p; 350279377Simp char *concat; 351279377Simp char **ap; 352279377Simp arith_t i; 353279377Simp 354279377Simp if (argc > 1) { 355279377Simp p = argv[1]; 356279377Simp if (argc > 2) { 357279377Simp /* 358279377Simp * Concatenate arguments. 359279377Simp */ 360279377Simp STARTSTACKSTR(concat); 361279377Simp ap = argv + 2; 362279377Simp for (;;) { 363279377Simp while (*p) 364279377Simp STPUTC(*p++, concat); 365279377Simp if ((p = *ap++) == NULL) 366279377Simp break; 367279377Simp STPUTC(' ', concat); 368279377Simp } 369295436Sandrew STPUTC('\0', concat); 370279377Simp p = grabstackstr(concat); 371279377Simp } 372279377Simp } else 373279377Simp p = ""; 374279377Simp 375279377Simp i = arith(p); 376279377Simp 377279377Simp out1fmt(ARITH_FORMAT_STR "\n", i); 378279377Simp return !i; 379279377Simp} 380279377Simp 381279377Simp