static int run_grammar(VALUE self, char *filename, VALUE rb_input, char *input, bool run_callbacks) { reset_terminal_error(); struct bc_read_stream *s = bc_rs_open_file(filename); if (!s) return 1; // should raise an invalid file format error in ruby instead struct gzl_grammar *g = gzl_load_grammar(s); bc_rs_close_stream(s); ParseState *state = gzl_alloc_parse_state(); mk_user_data(state, self, input, rb_input); BoundGrammar bg = { .grammar = g, .error_char_cb = error_char_callback, .error_terminal_cb = error_terminal_callback }; if (run_callbacks) { bg.end_rule_cb = end_rule_callback; bg.terminal_cb = terminal_callback; } rb_gzl_parse(input, state, &bg); return 0; }
int main(int argc, char *argv[]) { if(argc > 1 && strcmp(argv[1], "--help") == 0) { usage(); exit(0); } if(argc < 3) { fprintf(stderr, "Not enough arguments.\n"); usage(); return 1; } int arg_offset = 1; bool dump_json = false; bool dump_total = false; while(arg_offset < argc && argv[arg_offset][0] == '-') { if(strcmp(argv[arg_offset], "--dump-json") == 0) dump_json = true; else if(strcmp(argv[arg_offset], "--dump-total") == 0) dump_total = true; else { fprintf(stderr, "Unrecognized option '%s'.\n", argv[arg_offset]); usage(); exit(1); } arg_offset++; } /* Load the grammar file. */ if(arg_offset+1 >= argc) { fprintf(stderr, "Must specify grammar file and input file.\n"); usage(); return 1; } struct bc_read_stream *s = bc_rs_open_file(argv[arg_offset++]); if(!s) { printf("Couldn't open bitcode file '%s'!\n\n", argv[1]); usage(); return 1; } struct gzl_grammar *g = gzl_load_grammar(s); bc_rs_close_stream(s); /* Open the input file. */ FILE *file; if(strcmp(argv[arg_offset], "-") == 0) { file = stdin; } else { file = fopen(argv[arg_offset], "r"); if(!file) { printf("Couldn't open file '%s' for reading: %s\n\n", argv[2], strerror(errno)); usage(); return 1; } } struct gzlparse_state user_state; INIT_DYNARRAY(user_state.first_child, 1, 16); user_state.first_child[0] = true; struct gzl_parse_state *state = gzl_alloc_parse_state(); struct gzl_bound_grammar bg = { .grammar = g, .error_char_cb = error_char_callback, .error_terminal_cb = error_terminal_callback, }; if(dump_json) { bg.terminal_cb = terminal_callback; bg.did_start_rule_cb = start_rule_callback; bg.will_end_rule_cb = end_rule_callback; fputs("{\"parse_tree\":", stdout); } gzl_init_parse_state(state, &bg); enum gzl_status status = gzl_parse_file(state, file, &user_state, 50 * 1024); switch(status) { case GZL_STATUS_OK: case GZL_STATUS_HARD_EOF: { if(dump_json) fputs("\n}\n", stdout); if(dump_total) { fprintf(stderr, "gzlparse: %zu bytes parsed", state->offset.byte); if(status == GZL_STATUS_HARD_EOF) fprintf(stderr, "(hit grammar EOF before file EOF)"); fprintf(stderr, ".\n"); } break; } case GZL_STATUS_ERROR: fprintf(stderr, "gzlparse: parse error, aborting.\n"); case GZL_STATUS_CANCELLED: /* TODO: when we support length caps. */ break; case GZL_STATUS_RESOURCE_LIMIT_EXCEEDED: /* TODO: more informative message about what limit was exceeded. */ fprintf(stderr, "gzlparse: resource limit exceeded.\n"); break; case GZL_STATUS_IO_ERROR: perror("gzlparse"); break; case GZL_STATUS_PREMATURE_EOF_ERROR: fprintf(stderr, "gzlparse: premature eof.\n"); break; } gzl_free_parse_state(state); gzl_free_grammar(g); FREE_DYNARRAY(user_state.first_child); fclose(file); }