logo

utils-std

Collection of commonly available Unix tools git clone https://anongit.hacktivis.me/git/utils-std.git/

expr.y (11919B)


  1. %{
  2. // SPDX-License-Identifier: 0BSD
  3. // Copyright Pace Willisson (pace@blitz.com), J.T. Conklin (jtc@wimsey.com)
  4. /*-
  5. * Written by Pace Willisson (pace@blitz.com)
  6. * and placed in the public domain.
  7. *
  8. * Largely rewritten by J.T. Conklin (jtc@wimsey.com)
  9. */
  10. /*
  11. * Warning: OpenBSD yacc prints the following at the very beginning:
  12. * #include <string.h>
  13. * #include <stdlib.h>
  14. */
  15. #include "../libutils/err.h"
  16. #include <assert.h>
  17. #include <ctype.h>
  18. #include <errno.h>
  19. #include <inttypes.h>
  20. #include <limits.h>
  21. #include <locale.h>
  22. #include <regex.h>
  23. #include <stdio.h>
  24. #include <stdlib.h>
  25. #include <string.h>
  26. #include <sys/types.h>
  27. /*
  28. * POSIX specifies a specific error code for syntax errors. We exit
  29. * with this code for all errors.
  30. */
  31. #define ERR_EXIT 2
  32. enum valtype {
  33. integer, numeric_string, string
  34. } ;
  35. struct val {
  36. enum valtype type;
  37. union {
  38. char *s;
  39. intmax_t i;
  40. } u;
  41. } ;
  42. char **av;
  43. struct val *result;
  44. static void assert_to_integer(struct val *);
  45. static void assert_div(intmax_t, intmax_t);
  46. static void assert_minus(intmax_t, intmax_t, intmax_t);
  47. static void assert_plus(intmax_t, intmax_t, intmax_t);
  48. static void assert_times(intmax_t, intmax_t, intmax_t);
  49. static int compare_vals(struct val *, struct val *);
  50. static void free_value(struct val *);
  51. static int is_integer(const char *);
  52. static int is_string(struct val *);
  53. static int is_zero_or_null(struct val *);
  54. static struct val *make_integer(intmax_t);
  55. static struct val *make_str(const char *);
  56. static struct val *op_and(struct val *, struct val *);
  57. static struct val *op_colon(struct val *, struct val *);
  58. static struct val *op_div(struct val *, struct val *);
  59. static struct val *op_eq(struct val *, struct val *);
  60. static struct val *op_ge(struct val *, struct val *);
  61. static struct val *op_gt(struct val *, struct val *);
  62. static struct val *op_le(struct val *, struct val *);
  63. static struct val *op_lt(struct val *, struct val *);
  64. static struct val *op_minus(struct val *, struct val *);
  65. static struct val *op_ne(struct val *, struct val *);
  66. static struct val *op_or(struct val *, struct val *);
  67. static struct val *op_plus(struct val *, struct val *);
  68. static struct val *op_rem(struct val *, struct val *);
  69. static struct val *op_times(struct val *, struct val *);
  70. static int to_integer(struct val *);
  71. static void to_string(struct val *);
  72. #define YYERROR_IS_DECLARED
  73. static int yyerror(const char *);
  74. static int yylex(void);
  75. const char *argv0 = "expr";
  76. %}
  77. %union
  78. {
  79. struct val *val;
  80. }
  81. %left <val> '|'
  82. %left <val> '&'
  83. %left <val> '=' '>' '<' GE LE NE
  84. %left <val> '+' '-'
  85. %left <val> '*' '/' '%'
  86. %left <val> ':'
  87. %token <val> TOKEN
  88. %type <val> start expr
  89. %%
  90. start: expr { result = $$; }
  91. expr: TOKEN
  92. | '(' expr ')' { $$ = $2; }
  93. | expr '|' expr { $$ = op_or($1, $3); }
  94. | expr '&' expr { $$ = op_and($1, $3); }
  95. | expr '=' expr { $$ = op_eq($1, $3); }
  96. | expr '>' expr { $$ = op_gt($1, $3); }
  97. | expr '<' expr { $$ = op_lt($1, $3); }
  98. | expr GE expr { $$ = op_ge($1, $3); }
  99. | expr LE expr { $$ = op_le($1, $3); }
  100. | expr NE expr { $$ = op_ne($1, $3); }
  101. | expr '+' expr { $$ = op_plus($1, $3); }
  102. | expr '-' expr { $$ = op_minus($1, $3); }
  103. | expr '*' expr { $$ = op_times($1, $3); }
  104. | expr '/' expr { $$ = op_div($1, $3); }
  105. | expr '%' expr { $$ = op_rem($1, $3); }
  106. | expr ':' expr { $$ = op_colon($1, $3); }
  107. ;
  108. %%
  109. static struct val *
  110. make_integer(intmax_t i)
  111. {
  112. struct val *vp;
  113. vp = (struct val *)malloc(sizeof(*vp));
  114. if (vp == NULL)
  115. utils_errx(ERR_EXIT, "malloc(vp) failed");
  116. vp->type = integer;
  117. vp->u.i = i;
  118. return (vp);
  119. }
  120. static struct val *
  121. make_str(const char *s)
  122. {
  123. struct val *vp;
  124. vp = (struct val *)malloc(sizeof(*vp));
  125. if (vp == NULL)
  126. utils_errx(ERR_EXIT, "malloc(vp) failed");
  127. if ((vp->u.s = strdup(s)) == NULL)
  128. utils_errx(ERR_EXIT, "strdup(s) failed");
  129. if (is_integer(s))
  130. vp->type = numeric_string;
  131. else
  132. vp->type = string;
  133. return (vp);
  134. }
  135. static void
  136. free_value(struct val *vp)
  137. {
  138. if (vp->type == string || vp->type == numeric_string)
  139. free(vp->u.s);
  140. if (vp->type == string || vp->type == numeric_string || vp->type == integer)
  141. free(vp);
  142. }
  143. static int
  144. to_integer(struct val *vp)
  145. {
  146. intmax_t i;
  147. /* we can only convert numeric_string to integer, here */
  148. if (vp->type == numeric_string) {
  149. errno = 0;
  150. i = strtoimax(vp->u.s, (char **)NULL, 10);
  151. /* just keep as numeric_string, if the conversion fails */
  152. if (errno != ERANGE) {
  153. free(vp->u.s);
  154. vp->u.i = i;
  155. vp->type = integer;
  156. }
  157. }
  158. return (vp->type == integer);
  159. }
  160. static void
  161. assert_to_integer(struct val *vp)
  162. {
  163. if (vp->type == string)
  164. utils_errx(ERR_EXIT, "not a decimal number: '%s'", vp->u.s);
  165. if (!to_integer(vp))
  166. utils_errx(ERR_EXIT, "operand too large: '%s'", vp->u.s);
  167. }
  168. static void
  169. to_string(struct val *vp)
  170. {
  171. if (vp->type == string || vp->type == numeric_string)
  172. return;
  173. int ndigits = snprintf(NULL, 0, "%jd", vp->u.i);
  174. if(ndigits <= 0)
  175. utils_errx(ERR_EXIT, "failed to pre-format integer %jd as a string", vp->u.i);
  176. ndigits++; // NULL terminator
  177. if(ndigits <= 0)
  178. utils_errx(ERR_EXIT, "pre-format length overflow", ndigits);
  179. char *tmp = malloc(ndigits);
  180. if (tmp == NULL)
  181. utils_errx(ERR_EXIT, "malloc(%zd) for to_string() failed", ndigits);
  182. int ret = snprintf(tmp, ndigits, "%jd", vp->u.i);
  183. if(ret < 0)
  184. utils_errx(ERR_EXIT, "failed to format integer %jd as a string", vp->u.i);
  185. vp->type = string;
  186. vp->u.s = tmp;
  187. }
  188. static int
  189. is_integer(const char *s)
  190. {
  191. if (*s == '-')
  192. s++;
  193. if (*s == '\0')
  194. return (0);
  195. while (isdigit((unsigned char)*s))
  196. s++;
  197. return (*s == '\0');
  198. }
  199. static int
  200. is_string(struct val *vp)
  201. {
  202. /* only TRUE if this string is not a valid integer */
  203. return (vp->type == string);
  204. }
  205. static int
  206. yylex(void)
  207. {
  208. char *p;
  209. if (*av == NULL)
  210. return (0);
  211. p = *av++;
  212. if (strlen(p) == 1) {
  213. if (strchr("|&=<>+-*/%:()", *p))
  214. return (*p);
  215. } else if (strlen(p) == 2 && p[1] == '=') {
  216. switch (*p) {
  217. case '>': return (GE);
  218. case '<': return (LE);
  219. case '!': return (NE);
  220. }
  221. }
  222. yylval.val = make_str(p);
  223. return (TOKEN);
  224. }
  225. static int
  226. is_zero_or_null(struct val *vp)
  227. {
  228. if (vp->type == integer)
  229. return (vp->u.i == 0);
  230. return (*vp->u.s == 0 || (to_integer(vp) && vp->u.i == 0));
  231. }
  232. int
  233. main(int argc, char *argv[])
  234. {
  235. char *lc_all = setlocale(LC_ALL, "");
  236. if(lc_all == NULL)
  237. {
  238. fprintf(stderr, "%s: warning: Failed loading locales. setlocale(LC_ALL, \"\"): %s\n", argv0, strerror(errno));
  239. }
  240. errno = 0;
  241. av = argv + 1;
  242. yyparse();
  243. assert(result);
  244. if (result->type == integer)
  245. printf("%jd\n", result->u.i);
  246. else
  247. printf("%s\n", result->u.s);
  248. int err = is_zero_or_null(result);
  249. free_value(result);
  250. return err;
  251. }
  252. static int
  253. yyerror(const char *s)
  254. {
  255. utils_errx(ERR_EXIT, "syntax error: %s", s);
  256. }
  257. static struct val *
  258. op_or(struct val *a, struct val *b)
  259. {
  260. if (!is_zero_or_null(a)) {
  261. free_value(b);
  262. return (a);
  263. }
  264. free_value(a);
  265. if (!is_zero_or_null(b))
  266. return (b);
  267. free_value(b);
  268. return (make_integer((intmax_t)0));
  269. }
  270. static struct val *
  271. op_and(struct val *a, struct val *b)
  272. {
  273. if (is_zero_or_null(a) || is_zero_or_null(b)) {
  274. free_value(a);
  275. free_value(b);
  276. return (make_integer((intmax_t)0));
  277. } else {
  278. free_value(b);
  279. return (a);
  280. }
  281. }
  282. static int
  283. compare_vals(struct val *a, struct val *b)
  284. {
  285. int r;
  286. if (is_string(a) || is_string(b)) {
  287. to_string(a);
  288. to_string(b);
  289. r = strcoll(a->u.s, b->u.s);
  290. } else {
  291. assert_to_integer(a);
  292. assert_to_integer(b);
  293. if (a->u.i > b->u.i)
  294. r = 1;
  295. else if (a->u.i < b->u.i)
  296. r = -1;
  297. else
  298. r = 0;
  299. }
  300. free_value(a);
  301. free_value(b);
  302. return (r);
  303. }
  304. static struct val *
  305. op_eq(struct val *a, struct val *b)
  306. {
  307. return (make_integer((intmax_t)(compare_vals(a, b) == 0)));
  308. }
  309. static struct val *
  310. op_gt(struct val *a, struct val *b)
  311. {
  312. return (make_integer((intmax_t)(compare_vals(a, b) > 0)));
  313. }
  314. static struct val *
  315. op_lt(struct val *a, struct val *b)
  316. {
  317. return (make_integer((intmax_t)(compare_vals(a, b) < 0)));
  318. }
  319. static struct val *
  320. op_ge(struct val *a, struct val *b)
  321. {
  322. return (make_integer((intmax_t)(compare_vals(a, b) >= 0)));
  323. }
  324. static struct val *
  325. op_le(struct val *a, struct val *b)
  326. {
  327. return (make_integer((intmax_t)(compare_vals(a, b) <= 0)));
  328. }
  329. static struct val *
  330. op_ne(struct val *a, struct val *b)
  331. {
  332. return (make_integer((intmax_t)(compare_vals(a, b) != 0)));
  333. }
  334. static void
  335. assert_plus(intmax_t a, intmax_t b, intmax_t r)
  336. {
  337. /*
  338. * sum of two positive numbers must be positive,
  339. * sum of two negative numbers must be negative
  340. */
  341. if ((a > 0 && b > 0 && r <= 0) ||
  342. (a < 0 && b < 0 && r >= 0))
  343. utils_errx(ERR_EXIT, "overflow");
  344. }
  345. static struct val *
  346. op_plus(struct val *a, struct val *b)
  347. {
  348. struct val *r;
  349. assert_to_integer(a);
  350. assert_to_integer(b);
  351. r = make_integer(a->u.i + b->u.i);
  352. assert_plus(a->u.i, b->u.i, r->u.i);
  353. free_value(a);
  354. free_value(b);
  355. return (r);
  356. }
  357. static void
  358. assert_minus(intmax_t a, intmax_t b, intmax_t r)
  359. {
  360. if ((a >= 0 && b < 0 && r <= 0) ||
  361. (a < 0 && b > 0 && r >= 0))
  362. utils_errx(ERR_EXIT, "overflow");
  363. }
  364. static struct val *
  365. op_minus(struct val *a, struct val *b)
  366. {
  367. struct val *r;
  368. assert_to_integer(a);
  369. assert_to_integer(b);
  370. r = make_integer(a->u.i - b->u.i);
  371. assert_minus(a->u.i, b->u.i, r->u.i);
  372. free_value(a);
  373. free_value(b);
  374. return (r);
  375. }
  376. /*
  377. * We depend on undefined behaviour giving a result (in r).
  378. * To test this result, pass it as volatile. This prevents
  379. * optimizing away of the test based on the undefined behaviour.
  380. */
  381. static void
  382. assert_times(intmax_t a, intmax_t b, volatile intmax_t r)
  383. {
  384. /*
  385. * If the first operand is 0, no overflow is possible,
  386. * else the result of the division test must match the
  387. * second operand.
  388. *
  389. * Be careful to avoid overflow in the overflow test, as
  390. * in assert_div(). Overflow in division would kill us
  391. * with a SIGFPE before getting the test wrong. In old
  392. * buggy versions, optimization used to give a null test
  393. * instead of a SIGFPE.
  394. */
  395. if ((a == -1 && b == INTMAX_MIN) || (a != 0 && r / a != b))
  396. utils_errx(ERR_EXIT, "overflow");
  397. }
  398. static struct val *
  399. op_times(struct val *a, struct val *b)
  400. {
  401. struct val *r;
  402. assert_to_integer(a);
  403. assert_to_integer(b);
  404. r = make_integer(a->u.i * b->u.i);
  405. assert_times(a->u.i, b->u.i, r->u.i);
  406. free_value(a);
  407. free_value(b);
  408. return (r);
  409. }
  410. static void
  411. assert_div(intmax_t a, intmax_t b)
  412. {
  413. if (b == 0)
  414. utils_errx(ERR_EXIT, "division by zero");
  415. /* only INTMAX_MIN / -1 causes overflow */
  416. if (a == INTMAX_MIN && b == -1)
  417. utils_errx(ERR_EXIT, "overflow");
  418. }
  419. static struct val *
  420. op_div(struct val *a, struct val *b)
  421. {
  422. struct val *r;
  423. assert_to_integer(a);
  424. assert_to_integer(b);
  425. /* assert based on operands only, not on result */
  426. assert_div(a->u.i, b->u.i);
  427. r = make_integer(a->u.i / b->u.i);
  428. free_value(a);
  429. free_value(b);
  430. return (r);
  431. }
  432. static struct val *
  433. op_rem(struct val *a, struct val *b)
  434. {
  435. struct val *r;
  436. assert_to_integer(a);
  437. assert_to_integer(b);
  438. /* pass a=1 to only check for div by zero */
  439. assert_div(1, b->u.i);
  440. r = make_integer(a->u.i % b->u.i);
  441. free_value(a);
  442. free_value(b);
  443. return (r);
  444. }
  445. static struct val *
  446. op_colon(struct val *a, struct val *b)
  447. {
  448. regex_t rp;
  449. regmatch_t rm[2];
  450. char errbuf[256];
  451. int eval;
  452. struct val *v;
  453. /* coerce both arguments to strings */
  454. to_string(a);
  455. to_string(b);
  456. /* compile regular expression */
  457. if ((eval = regcomp(&rp, b->u.s, 0)) != 0) {
  458. regerror(eval, &rp, errbuf, sizeof(errbuf));
  459. utils_errx(ERR_EXIT, "%s", errbuf);
  460. }
  461. /* compare string against pattern */
  462. /* remember that patterns are anchored to the beginning of the line */
  463. if (regexec(&rp, a->u.s, (size_t)2, rm, 0) == 0 && rm[0].rm_so == 0)
  464. if (rm[1].rm_so >= 0) {
  465. *(a->u.s + rm[1].rm_eo) = '\0';
  466. v = make_str(a->u.s + rm[1].rm_so);
  467. } else
  468. v = make_integer((intmax_t)(rm[0].rm_eo));
  469. else
  470. if (rp.re_nsub == 0)
  471. v = make_integer((intmax_t)0);
  472. else
  473. v = make_str("");
  474. /* free arguments and pattern buffer */
  475. free_value(a);
  476. free_value(b);
  477. regfree(&rp);
  478. return (v);
  479. }