| 535 | } |
| 536 | |
| 537 | bool llama_grammar_parser::parse(const char * src) { |
| 538 | try { |
| 539 | const char * pos = parse_space(src, true); |
| 540 | while (*pos) { |
| 541 | pos = parse_rule(pos); |
| 542 | } |
| 543 | // Validate the state to ensure that all rules are defined |
| 544 | for (const auto & rule : rules) { |
| 545 | if (rule.empty()) { |
| 546 | throw std::runtime_error("Undefined rule"); |
| 547 | } |
| 548 | for (const auto & elem : rule) { |
| 549 | if (elem.type == LLAMA_GRETYPE_RULE_REF) { |
| 550 | // Ensure that the rule at that location exists |
| 551 | if (elem.value >= rules.size() || rules[elem.value].empty()) { |
| 552 | // Get the name of the rule that is missing |
| 553 | for (const auto & kv : symbol_ids) { |
| 554 | if (kv.second == elem.value) { |
| 555 | throw std::runtime_error("Undefined rule identifier '" + kv.first + "'"); |
| 556 | } |
| 557 | } |
| 558 | } |
| 559 | } |
| 560 | } |
| 561 | } |
| 562 | } catch (const std::exception & err) { |
| 563 | fprintf(stderr, "%s: error parsing grammar: %s\n\n%s\n", __func__, err.what(), src); |
| 564 | rules.clear(); |
| 565 | return false; |
| 566 | } |
| 567 | |
| 568 | return true; |
| 569 | } |
| 570 | |
| 571 | void llama_grammar_parser::print(FILE * file) { |
| 572 | try { |