aboutsummaryrefslogtreecommitdiffstats
path: root/calc-example
diff options
context:
space:
mode:
Diffstat (limited to 'calc-example')
-rw-r--r--calc-example/calc.c142
-rw-r--r--calc-example/calc.syntax27
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 | -)}, _;