dc: tweak parsing

https://bugs.debian.org/538685
dc requires whitespace between language elements.

We were requiring
1 2 + p
instead of the abbreviated
1 2+p
(for example).

function                                             old     new   delta
stack_machine                                         97     126     +29
dc_main                                              117      79     -38
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/1 up/down: 29/-38)             Total: -9 bytes

Signed-off-by: Bernhard Reutner-Fischer <rep.dot.nop@gmail.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Bernhard Reutner-Fischer 2015-02-16 17:12:04 +01:00 committed by Denys Vlasenko
parent 8e92df15b5
commit 70e30e8eec
2 changed files with 83 additions and 30 deletions

View File

@ -196,14 +196,6 @@ struct op {
}; };
static const struct op operators[] = { static const struct op operators[] = {
{"+", add},
{"add", add},
{"-", sub},
{"sub", sub},
{"*", mul},
{"mul", mul},
{"/", divide},
{"div", divide},
#if ENABLE_FEATURE_DC_LIBM #if ENABLE_FEATURE_DC_LIBM
{"**", power}, {"**", power},
{"exp", power}, {"exp", power},
@ -216,28 +208,47 @@ static const struct op operators[] = {
{"not", not}, {"not", not},
{"eor", eor}, {"eor", eor},
{"xor", eor}, {"xor", eor},
{"+", add},
{"add", add},
{"-", sub},
{"sub", sub},
{"*", mul},
{"mul", mul},
{"/", divide},
{"div", divide},
{"p", print_no_pop}, {"p", print_no_pop},
{"f", print_stack_no_pop}, {"f", print_stack_no_pop},
{"o", set_output_base}, {"o", set_output_base},
}; };
/* Feed the stack machine */
static void stack_machine(const char *argument) static void stack_machine(const char *argument)
{ {
char *end; char *end;
double d; double number;
const struct op *o; const struct op *o;
d = strtod(argument, &end); next:
if (end != argument && *end == '\0') { number = strtod(argument, &end);
push(d); if (end != argument) {
return; argument = end;
push(number);
goto next;
} }
/* We might have matched a digit, eventually advance the argument */
argument = skip_whitespace(argument);
if (*argument == '\0')
return;
o = operators; o = operators;
do { do {
if (strcmp(o->name, argument) == 0) { const size_t name_len = strlen(o->name);
if (strncmp(o->name, argument, name_len) == 0) {
argument += name_len;
o->function(); o->function();
return; goto next;
} }
o++; o++;
} while (o != operators + ARRAY_SIZE(operators)); } while (o != operators + ARRAY_SIZE(operators));
@ -254,25 +265,11 @@ int dc_main(int argc UNUSED_PARAM, char **argv)
if (!argv[0]) { if (!argv[0]) {
/* take stuff from stdin if no args are given */ /* take stuff from stdin if no args are given */
char *line; char *line;
char *cursor;
char *token;
while ((line = xmalloc_fgetline(stdin)) != NULL) { while ((line = xmalloc_fgetline(stdin)) != NULL) {
cursor = line; stack_machine(line);
while (1) {
token = skip_whitespace(cursor);
if (*token == '\0')
break;
cursor = skip_non_whitespace(token);
if (*cursor != '\0')
*cursor++ = '\0';
stack_machine(token);
}
free(line); free(line);
} }
} else { } else {
// why? it breaks "dc -2 2 + p"
//if (argv[0][0] == '-')
// bb_show_usage();
do { do {
stack_machine(*argv); stack_machine(*argv);
} while (*++argv); } while (*++argv);

56
testsuite/dc.tests Executable file
View File

@ -0,0 +1,56 @@
#!/bin/sh
# Copyright 2015 by Bernhard Reutner-Fischer
# Licensed under GPLv2 or later, see file LICENSE in this source tree.
. ./testing.sh
# testing "test name" "command" "expected result" "file input" "stdin"
testing "dc basic syntax (stdin, multiple args)" \
"dc" \
"30\n" \
"" "10 20+p"
testing "dc basic syntax (argv, single arg)" \
"dc '10 20+p'" \
"30\n" \
"" ""
testing "dc basic syntax (argv, multiple args)" \
"dc 10 20+p" \
"30\n" \
"" ""
testing "dc complex with spaces (single arg)" \
"dc '8 8 * 2 2 + / p'" \
"16\n" \
"" ""
testing "dc complex without spaces (single arg)" \
"dc '8 8*2 2+/p'" \
"16\n" \
"" ""
testing "dc complex with spaces (multiple args)" \
"dc 8 8 \* 2 2 + / p" \
"16\n" \
"" ""
testing "dc complex without spaces (multiple args)" \
"dc 8 8\*2 2+/p" \
"16\n" \
"" ""
exit $FAILCOUNT
# we do not support arguments
testing "dc -e <exprs>" \
"dc -e '10 2+f'" \
"12\n" \
"" ""
testing "dc -f <exprs-from-given-file>" \
"dc -f input" \
"12\n" \
"10 2+f" ""