diff options
Diffstat (limited to 'calc-example')
-rw-r--r-- | calc-example/calc.c | 142 | ||||
-rw-r--r-- | calc-example/calc.syntax | 27 |
2 files changed, 169 insertions, 0 deletions
diff --git a/calc-example/calc.c b/calc-example/calc.c new file mode 100644 index 0000000..adda2ba --- /dev/null +++ b/calc-example/calc.c @@ -0,0 +1,142 @@ +/* See LICENSE file for copyright and license details. */ +#include <libparser.h> +#include <libsimple.h> +#include <libsimple-arg.h> + +USAGE(""); + + +static void +free_input(struct libparser_unit *node) +{ + struct libparser_unit *next; + for (; node; next = node->next, free(node), node = next) + free_input(node->in); +} + + +static intmax_t +calculate(struct libparser_unit *node, const char *line) +{ + struct libparser_unit *next; + intmax_t value = 0; + int op; + if (!node->rule) { + next = node->in->next; + value = calculate(node->in, line); + free_input(next); + } else if (!strcmp(node->rule, "DIGIT")) { + value = (intmax_t)(line[node->start] - '0'); + } else if (!strcmp(node->rule, "sign")) { + value = !strcmp(node->in->rule, "SUB") ? -1 : +1; + free(node->in); + } else if (!strcmp(node->rule, "unsigned")) { + value = 0; + next = node->in; + free(node); + for (node = next; node; node = next) { + next = node->next; + value *= 10; + value += calculate(node, line); + } + } else if (!strcmp(node->rule, "number")) { + next = node->in->next; + value = calculate(node->in, line); + free(node); + for (node = next; node; node = next) { + next = node->next; + value *= calculate(node, line); + } + } else if (!strcmp(node->rule, "value")) { + next = node->in->next; + value = calculate(node->in, line); + if (next) + value *= calculate(next, line); + } else if (!strcmp(node->rule, "hyper1")) { + next = node->in->next; + value = calculate(node->in, line); + free(node); + node = next; + while (node) { + next = node->next; + op = !strcmp(node->rule, "SUB") ? -1 : +1; + free(node); + node = next; + next = node->next; + if (op < 0) + value -= calculate(node, line); + else + value += calculate(node, line); + node = next; + } + } else if (!strcmp(node->rule, "hyper2")) { + next = node->in->next; + value = calculate(node->in, line); + free(node); + node = next; + while (node) { + next = node->next; + op = !strcmp(node->rule, "DIV") ? -1 : +1; + free(node); + node = next; + next = node->next; + if (op < 0) + value /= calculate(node, line); + else + value *= calculate(node, line); + node = next; + } + } else if (node->rule[0] != '@') { + abort(); + } else if (node->in) { + next = node->in->next; + value = calculate(node->in, line); + if (next) + free_input(next); + } + free(node); + return value; +} + + +int +main(int argc, char *argv[]) +{ + struct libparser_unit *input; + char *line = NULL; + size_t size = 0; + ssize_t len; + intmax_t res; + int exception; + + ARGBEGIN { + default: + usage(); + } ARGEND; + if (argc) + usage(); + + while ((len = getline(&line, &size, stdin)) >= 0) { + if (len && line[len - 1] == '\n') + line[--len] = '\0'; + input = libparser_parse_file(libparser_rule_table, line, (size_t)len, &exception); + if (!input) { + weprintf("didn't find anything to parse\n"); + free_input(input); + continue; + } else if (input->end != (size_t)len) { + weprintf("line could not be parsed, stopped at column %zu\n", input->end); + free_input(input); + continue; + } else if (exception) { + weprintf("premature end of line\n"); + free_input(input); + continue; + } + res = calculate(input, line); + printf("%ji\n", res); + } + + free(line); + return 0; +} diff --git a/calc-example/calc.syntax b/calc-example/calc.syntax new file mode 100644 index 0000000..ef7a9f4 --- /dev/null +++ b/calc-example/calc.syntax @@ -0,0 +1,27 @@ +_WHITESPACE = " " | "\t" | " "; +_ = {_WHITESPACE}; + + +DIGIT = "0" | "1" | "2" | "3" | "4" | "5" | "6" | "7" | "8" | "9"; + +ADD = _, ("+"), _; +SUB = _, ("-" | "−"), _; +MUL = _, ("*" | "⋅" | "×"), _; +DIV = _, ("/" | "∕" | "÷"), _; + + +sign = ADD | SUB; + +unsigned = DIGIT, {DIGIT | _WHITESPACE | "_" | "'"}; + +_number = unsigned | "(", _expr, (")" | -); + +number = _number, {_, _number}; (* optionally with implicit multiplication *) + +value = [sign], number; + +_expr = hyper1; + + +hyper1 = _, hyper2, {(ADD | SUB), (hyper2 | -)}, _; +hyper2 = _, value, {(MUL | DIV), (value | -)}, _; |