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