[PATCH] dc: tweak parsing
Bernhard Reutner-Fischer
rep.dot.nop at gmail.com
Sun Feb 15 14:00:59 UTC 2015
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 101 138 +37
dc_main 131 102 -29
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/1 up/down: 37/-29) Total: 8 bytes
text data bss dec hex filename
Signed-off-by: Bernhard Reutner-Fischer <rep.dot.nop at gmail.com>
---
miscutils/dc.c | 62 ++++++++++++++++++++++++++++--------------------------
testsuite/dc.tests | 56 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 88 insertions(+), 30 deletions(-)
create mode 100755 testsuite/dc.tests
diff --git a/miscutils/dc.c b/miscutils/dc.c
index 6bcfbe2..c40d1ef 100644
--- a/miscutils/dc.c
+++ b/miscutils/dc.c
@@ -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,45 @@ 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},
};
-static void stack_machine(const char *argument)
+/* Feed the stack machine.
+ * Returns a pointer to the first character not yet matched or NULL when
+ * done.
+ */
+static char* 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;
+ number = strtod(argument, &end);
+ if (end != argument) {
+ push(number);
+ return end;
}
+ if (*end == '\0')
+ return NULL;
+ /* We might have matched a digit, eventually advance the argument */
+ argument = skip_whitespace(end);
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) {
o->function();
- return;
+ return ((char *)argument) + name_len;
}
o++;
} while (o != operators + ARRAY_SIZE(operators));
@@ -248,33 +257,26 @@ static void stack_machine(const char *argument)
int dc_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int dc_main(int argc UNUSED_PARAM, char **argv)
{
+ char *cursor;
INIT_G();
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);
+ while (*cursor != '\0') {
+ cursor = stack_machine(cursor);
}
free(line);
}
} else {
- // why? it breaks "dc -2 2 + p"
- //if (argv[0][0] == '-')
- // bb_show_usage();
do {
- stack_machine(*argv);
+ cursor = *argv;
+ while (*cursor != '\0') {
+ cursor = stack_machine(cursor);
+ }
} while (*++argv);
}
return EXIT_SUCCESS;
diff --git a/testsuite/dc.tests b/testsuite/dc.tests
new file mode 100755
index 0000000..a5da537
--- /dev/null
+++ b/testsuite/dc.tests
@@ -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" ""
+
--
2.1.4
More information about the busybox
mailing list