/* * (C) Copyright 2016 Leo C. * * SPDX-License-Identifier: GPL-2.0 */ #include "eval_arg.h" #include "common.h" #include #include #include #include "print-utils.h" #include "command.h" /* jump_buf */ static jmp_buf eval_jbuf; static char ch; static char *start_p; static char *bp; static long expr(void); static void print_error_pos(void) { printf_P(PSTR("Arg: '%s'\n" " "), start_p); print_blanks(bp - start_p); my_puts_P(PSTR("^syntax error!\n")); } static void error (void) { --bp; longjmp (eval_jbuf, 1); } static void next(void) { do ch = *bp++; while (isspace(ch)); } static long number (void) { int base = 16; char *end_p; long n; if (ch == '$') { /* FIXME: should be '#' */ next(); base = 10; } if (!isdigit(ch) && !(base == 16 && isxdigit(ch))) error (); n = strtoul(bp - 1, &end_p, base); if (end_p == bp - 1) error(); bp = end_p; next(); return n; } static long factor (void) { long f; if (ch == '(') { next(); f = expr(); if (ch == ')') next(); else error (); } else { char sign = ch; if (sign == '+' || sign == '-') { next(); } f = number(); if (sign == '-') f = -f; } return f; } static long term (void) { long t = factor(); for (;;) switch (ch) { case '*': next(); t *= factor(); break; case '/': next(); t /= factor(); break; case '%': next(); t %= factor(); break; default: return t; } } static long expr(void) { long e = term (); while (ch == '+' || ch == '-') { char op = ch; next(); if (op == '-') e -= term (); else e += term (); } return e; } long eval_arg(char *arg, char **end_ptr) { long val; start_p = arg; bp = arg; next(); if (setjmp (eval_jbuf) != 0) { if (!end_ptr) { print_error_pos(); longjmp(cmd_jbuf, 1); } val = -1; } else { val = expr (); --bp; } if (!end_ptr) { if (*bp != '\0') { print_error_pos(); longjmp(cmd_jbuf, 1); } } else *end_ptr = bp; return val; }