/* See LICENSE file for copyright and license details. */ #include #include #include #include #include #include #include #define LIST_RULES(X, D)\ X("comment", colourise, "31") D\ X("intrusive-identifier", colourise, "33") D\ X("discrete-identifier", colourise, "") D\ X("escape-payload", ignore, "") D\ X("ESCAPE", colourise, "2;34") D\ X("escape", colourise_and_descend, "34") D\ X("string", colourise_and_descend, "32") D\ X("character", descend, "") D\ X("integer", ignore, "") D\ X("boundary", descend, "") D\ X("low", descend, "") D\ X("high", descend, "") D\ X("NONDETERMINISTIC", colourise, "1;33") D\ X("COMMITTED", colourise, "1;33") D\ X("committed", descend, "") D\ X("REJECTION", colourise, "1;31") D\ X("rejection", descend, "") D\ X("EXCEPTION", colourise, "1;31") D\ X("exception", descend, "") D\ X("CONCATENATION", colourise, "2") D\ X("concatenation", descend, "") D\ X("ALTERNATION", colourise, "") D\ X("alternation", descend, "") D\ X("CHAR-RANGE-START", ignore, "") D\ X("CHAR-RANGE-COMMA", ignore, "") D\ X("CHAR-RANGE-END", ignore, "") D\ X("CHAR-RANGE-EDGE", ignore, "") D\ X("CHAR-RANGE", ignore, "") D\ X("char-range", colourise_and_descend, "35") D\ X("OPTIONAL-START", ignore, "") D\ X("OPTIONAL-END", ignore, "") D\ X("OPTIONAL", colourise, "1;34") D\ X("optional", descend, "") D\ X("REPEATED-START", ignore, "") D\ X("REPEATED-END", ignore, "") D\ X("REPEATED", colourise, "1;32") D\ X("repeated", descend, "") D\ X("GROUP-START", ignore, "") D\ X("GROUP-END", ignore, "") D\ X("GROUP", colourise, "1") D\ X("group", descend, "") D\ X("embedded-rule", descend, "") D\ X("operand", descend, "") D\ X("DEFINITION", ignore, "") D\ X("TERMINATION", ignore, "") D\ X("RULE", colourise, "1;36") D\ X("rule-name", descend, "") D\ X("rule", descend, "") D\ X("grammar", descend, "") static const char *argv0; static char *text = NULL; static size_t size = 0; static size_t len = 0; static size_t off = 0; static void descend(struct libparser_unit *tree, const char *colour); static void write_all(const char *s, size_t n) { ssize_t r; while (n) { r = write(STDOUT_FILENO, s, n); if (r < 0) { if (errno == EINTR) continue; fprintf(stderr, "%s: write %s: %s\n", argv0, "", strerror(errno)); exit(1); } s = &s[r]; n -= (size_t)r; } } static void write_str(const char *s) { write_all(s, strlen(s)); } static void output(size_t to) { if (to > off) { write_all(&text[off], to - off); off = to; } } static void ignore(struct libparser_unit *tree, const char *colour) { (void) tree; (void) colour; } static void colourise(struct libparser_unit *tree, const char *colour) { output(tree->start); write_str("\033[m"); write_str(colour); output(tree->end); write_str("\033[m"); } static void colourise_and_descend(struct libparser_unit *tree, const char *colour) { struct libparser_unit *node; output(tree->start); write_str("\033[m"); write_str(colour); #define X(RULE, ACTION, COLOUR)\ if (!strcmp(node->rule, RULE)) ACTION(node, "\033["COLOUR"m"); for (node = tree->in; node; node = node->next) { LIST_RULES(X, else) else descend(node, ""); } #undef X write_str("\033[m"); write_str(colour); output(tree->end); write_str("\033[m"); } static void descend(struct libparser_unit *tree, const char *colour) { struct libparser_unit *node; (void) colour; #define X(RULE, ACTION, COLOUR)\ if (!strcmp(node->rule, RULE)) ACTION(node, "\033["COLOUR"m"); for (node = tree->in; node; node = node->next) { LIST_RULES(X, else) else descend(node, ""); } #undef X } static void free_tree(struct libparser_unit *tree) { struct libparser_unit *node; struct libparser_unit *next; if (!tree) return; for (node = tree->in; node; node = next) { next = node->next; free_tree(node); } free(tree); } int main(int argc, char *argv[]) { struct libparser_unit *tree = NULL; ssize_t r; int fd = STDIN_FILENO; const char *path = ""; argv0 = *argv++; argc--; if (argc && !strcmp(*argv, "--")) { argv++; argc--; } else if (argc && argv[0][0] == '-' && argv[0][1]) { goto usage; } if (argc > 1) goto usage; if (argc && !strcmp(*argv, "-")) argc--; if (argc) { path = *argv; fd = open(path, O_RDONLY); if (fd < 0) { fprintf(stderr, "%s: open %s O_RDONLY: %s\n", argv[0], path, strerror(errno)); exit(1); } } for (;;) { if (len == size) { size += 8096u; text = realloc(text, size); if (!text) { fprintf(stderr, "%s: realloc %zu: %s\n", argv[0], size, strerror(errno)); exit(1); } } r = read(fd, &text[len], size - len); if (!r) break; if (r < 0) { if (errno == EINTR) continue; fprintf(stderr, "%s: read %s: %s\n", argv[0], path, strerror(errno)); exit(1); } len += (size_t)r; } if (argc) close(fd); r = libparser_parse_file(libparser_rule_table, text, len, &tree); if (r < 0) { fprintf(stderr, "%s: libparser_parse_file: %s\n", argv0, strerror(errno)); exit(1); } else if (!tree || tree->end != (size_t)len || !r) { fprintf(stderr, "%s: failed to parse input\n", argv0); exit(1); } descend(tree, ""); output(len); free(text); free_tree(tree); return 0; usage: fprintf(stderr, "usage: %s [file]\n", argv0); exit(1); }