/* See LICENSE file for copyright and license details. */ #include #include #include #include #include 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 r; if (argc == 2 ? strcmp(argv[1], "--") : argc > 2) { fprintf(stderr, "usage: %s\n", argv[0]); return 1; } while ((len = getline(&line, &size, stdin)) >= 0) { if (len && line[len - 1] == '\n') line[--len] = '\0'; r = libparser_parse_file(libparser_rule_table, line, (size_t)len, &input); if (r < 0) { perror("libparser_parse_file"); continue; } else if (!input) { fprintf(stderr, "didn't find anything to parse\n"); continue; } else if (input->end != (size_t)len) { fprintf(stderr, "line could not be parsed, stopped at column %zu\n", input->end); free_input(input); continue; } else if (!r) { fprintf(stderr, "premature end of line\n"); free_input(input); continue; } res = calculate(input, line); printf("%ji\n", res); } free(line); return 0; }