/bin/sh/arith_yacc.c

https://bitbucket.org/freebsd/freebsd-head/ · C · 381 lines · 278 code · 63 blank · 40 comment · 59 complexity · 96fa67814a480b7a44c4f106f6c4b467 MD5 · raw file

  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. #include <sys/cdefs.h>
  35. __FBSDID("$FreeBSD$");
  36. #include <limits.h>
  37. #include <errno.h>
  38. #include <inttypes.h>
  39. #include <stdlib.h>
  40. #include <stdio.h>
  41. #include "arith.h"
  42. #include "arith_yacc.h"
  43. #include "expand.h"
  44. #include "shell.h"
  45. #include "error.h"
  46. #include "memalloc.h"
  47. #include "output.h"
  48. #include "options.h"
  49. #include "var.h"
  50. #if ARITH_BOR + 11 != ARITH_BORASS || ARITH_ASS + 11 != ARITH_EQ
  51. #error Arithmetic tokens are out of order.
  52. #endif
  53. static const char *arith_startbuf;
  54. const char *arith_buf;
  55. union yystype yylval;
  56. static int last_token;
  57. #define ARITH_PRECEDENCE(op, prec) [op - ARITH_BINOP_MIN] = prec
  58. static const char prec[ARITH_BINOP_MAX - ARITH_BINOP_MIN] = {
  59. ARITH_PRECEDENCE(ARITH_MUL, 0),
  60. ARITH_PRECEDENCE(ARITH_DIV, 0),
  61. ARITH_PRECEDENCE(ARITH_REM, 0),
  62. ARITH_PRECEDENCE(ARITH_ADD, 1),
  63. ARITH_PRECEDENCE(ARITH_SUB, 1),
  64. ARITH_PRECEDENCE(ARITH_LSHIFT, 2),
  65. ARITH_PRECEDENCE(ARITH_RSHIFT, 2),
  66. ARITH_PRECEDENCE(ARITH_LT, 3),
  67. ARITH_PRECEDENCE(ARITH_LE, 3),
  68. ARITH_PRECEDENCE(ARITH_GT, 3),
  69. ARITH_PRECEDENCE(ARITH_GE, 3),
  70. ARITH_PRECEDENCE(ARITH_EQ, 4),
  71. ARITH_PRECEDENCE(ARITH_NE, 4),
  72. ARITH_PRECEDENCE(ARITH_BAND, 5),
  73. ARITH_PRECEDENCE(ARITH_BXOR, 6),
  74. ARITH_PRECEDENCE(ARITH_BOR, 7),
  75. };
  76. #define ARITH_MAX_PREC 8
  77. int letcmd(int, char **);
  78. static __dead2 void yyerror(const char *s)
  79. {
  80. error("arithmetic expression: %s: \"%s\"", s, arith_startbuf);
  81. /* NOTREACHED */
  82. }
  83. static arith_t arith_lookupvarint(char *varname)
  84. {
  85. const char *str;
  86. char *p;
  87. arith_t result;
  88. str = lookupvar(varname);
  89. if (uflag && str == NULL)
  90. yyerror("variable not set");
  91. if (str == NULL || *str == '\0')
  92. str = "0";
  93. errno = 0;
  94. result = strtoarith_t(str, &p, 0);
  95. if (errno != 0 || *p != '\0')
  96. yyerror("variable conversion error");
  97. return result;
  98. }
  99. static inline int arith_prec(int op)
  100. {
  101. return prec[op - ARITH_BINOP_MIN];
  102. }
  103. static inline int higher_prec(int op1, int op2)
  104. {
  105. return arith_prec(op1) < arith_prec(op2);
  106. }
  107. static arith_t do_binop(int op, arith_t a, arith_t b)
  108. {
  109. switch (op) {
  110. default:
  111. case ARITH_REM:
  112. case ARITH_DIV:
  113. if (!b)
  114. yyerror("division by zero");
  115. if (a == ARITH_MIN && b == -1)
  116. yyerror("divide error");
  117. return op == ARITH_REM ? a % b : a / b;
  118. case ARITH_MUL:
  119. return (uintmax_t)a * (uintmax_t)b;
  120. case ARITH_ADD:
  121. return (uintmax_t)a + (uintmax_t)b;
  122. case ARITH_SUB:
  123. return (uintmax_t)a - (uintmax_t)b;
  124. case ARITH_LSHIFT:
  125. return a << b;
  126. case ARITH_RSHIFT:
  127. return a >> b;
  128. case ARITH_LT:
  129. return a < b;
  130. case ARITH_LE:
  131. return a <= b;
  132. case ARITH_GT:
  133. return a > b;
  134. case ARITH_GE:
  135. return a >= b;
  136. case ARITH_EQ:
  137. return a == b;
  138. case ARITH_NE:
  139. return a != b;
  140. case ARITH_BAND:
  141. return a & b;
  142. case ARITH_BXOR:
  143. return a ^ b;
  144. case ARITH_BOR:
  145. return a | b;
  146. }
  147. }
  148. static arith_t assignment(int var, int noeval);
  149. static arith_t primary(int token, union yystype *val, int op, int noeval)
  150. {
  151. arith_t result;
  152. again:
  153. switch (token) {
  154. case ARITH_LPAREN:
  155. result = assignment(op, noeval);
  156. if (last_token != ARITH_RPAREN)
  157. yyerror("expecting ')'");
  158. last_token = yylex();
  159. return result;
  160. case ARITH_NUM:
  161. last_token = op;
  162. return val->val;
  163. case ARITH_VAR:
  164. last_token = op;
  165. return noeval ? val->val : arith_lookupvarint(val->name);
  166. case ARITH_ADD:
  167. token = op;
  168. *val = yylval;
  169. op = yylex();
  170. goto again;
  171. case ARITH_SUB:
  172. *val = yylval;
  173. return -primary(op, val, yylex(), noeval);
  174. case ARITH_NOT:
  175. *val = yylval;
  176. return !primary(op, val, yylex(), noeval);
  177. case ARITH_BNOT:
  178. *val = yylval;
  179. return ~primary(op, val, yylex(), noeval);
  180. default:
  181. yyerror("expecting primary");
  182. }
  183. }
  184. static arith_t binop2(arith_t a, int op, int precedence, int noeval)
  185. {
  186. for (;;) {
  187. union yystype val;
  188. arith_t b;
  189. int op2;
  190. int token;
  191. token = yylex();
  192. val = yylval;
  193. b = primary(token, &val, yylex(), noeval);
  194. op2 = last_token;
  195. if (op2 >= ARITH_BINOP_MIN && op2 < ARITH_BINOP_MAX &&
  196. higher_prec(op2, op)) {
  197. b = binop2(b, op2, arith_prec(op), noeval);
  198. op2 = last_token;
  199. }
  200. a = noeval ? b : do_binop(op, a, b);
  201. if (op2 < ARITH_BINOP_MIN || op2 >= ARITH_BINOP_MAX ||
  202. arith_prec(op2) >= precedence)
  203. return a;
  204. op = op2;
  205. }
  206. }
  207. static arith_t binop(int token, union yystype *val, int op, int noeval)
  208. {
  209. arith_t a = primary(token, val, op, noeval);
  210. op = last_token;
  211. if (op < ARITH_BINOP_MIN || op >= ARITH_BINOP_MAX)
  212. return a;
  213. return binop2(a, op, ARITH_MAX_PREC, noeval);
  214. }
  215. static arith_t and(int token, union yystype *val, int op, int noeval)
  216. {
  217. arith_t a = binop(token, val, op, noeval);
  218. arith_t b;
  219. op = last_token;
  220. if (op != ARITH_AND)
  221. return a;
  222. token = yylex();
  223. *val = yylval;
  224. b = and(token, val, yylex(), noeval | !a);
  225. return a && b;
  226. }
  227. static arith_t or(int token, union yystype *val, int op, int noeval)
  228. {
  229. arith_t a = and(token, val, op, noeval);
  230. arith_t b;
  231. op = last_token;
  232. if (op != ARITH_OR)
  233. return a;
  234. token = yylex();
  235. *val = yylval;
  236. b = or(token, val, yylex(), noeval | !!a);
  237. return a || b;
  238. }
  239. static arith_t cond(int token, union yystype *val, int op, int noeval)
  240. {
  241. arith_t a = or(token, val, op, noeval);
  242. arith_t b;
  243. arith_t c;
  244. if (last_token != ARITH_QMARK)
  245. return a;
  246. b = assignment(yylex(), noeval | !a);
  247. if (last_token != ARITH_COLON)
  248. yyerror("expecting ':'");
  249. token = yylex();
  250. *val = yylval;
  251. c = cond(token, val, yylex(), noeval | !!a);
  252. return a ? b : c;
  253. }
  254. static arith_t assignment(int var, int noeval)
  255. {
  256. union yystype val = yylval;
  257. int op = yylex();
  258. arith_t result;
  259. char sresult[DIGITS(result) + 1];
  260. if (var != ARITH_VAR)
  261. return cond(var, &val, op, noeval);
  262. if (op != ARITH_ASS && (op < ARITH_ASS_MIN || op >= ARITH_ASS_MAX))
  263. return cond(var, &val, op, noeval);
  264. result = assignment(yylex(), noeval);
  265. if (noeval)
  266. return result;
  267. if (op != ARITH_ASS)
  268. result = do_binop(op - 11, arith_lookupvarint(val.name), result);
  269. snprintf(sresult, sizeof(sresult), ARITH_FORMAT_STR, result);
  270. setvar(val.name, sresult, 0);
  271. return result;
  272. }
  273. arith_t arith(const char *s)
  274. {
  275. struct stackmark smark;
  276. arith_t result;
  277. setstackmark(&smark);
  278. arith_buf = arith_startbuf = s;
  279. result = assignment(yylex(), 0);
  280. if (last_token)
  281. yyerror("expecting EOF");
  282. popstackmark(&smark);
  283. return result;
  284. }
  285. /*
  286. * The exp(1) builtin.
  287. */
  288. int
  289. letcmd(int argc, char **argv)
  290. {
  291. const char *p;
  292. char *concat;
  293. char **ap;
  294. arith_t i;
  295. if (argc > 1) {
  296. p = argv[1];
  297. if (argc > 2) {
  298. /*
  299. * Concatenate arguments.
  300. */
  301. STARTSTACKSTR(concat);
  302. ap = argv + 2;
  303. for (;;) {
  304. while (*p)
  305. STPUTC(*p++, concat);
  306. if ((p = *ap++) == NULL)
  307. break;
  308. STPUTC(' ', concat);
  309. }
  310. STPUTC('\0', concat);
  311. p = grabstackstr(concat);
  312. }
  313. } else
  314. p = "";
  315. i = arith(p);
  316. out1fmt(ARITH_FORMAT_STR "\n", i);
  317. return !i;
  318. }