Skip to content

Commit 6602b1d

Browse files
committed
Fix #304
1 parent 2b02299 commit 6602b1d

File tree

7 files changed

+142
-63
lines changed

7 files changed

+142
-63
lines changed

Diff for: README.md

+19
Original file line numberDiff line numberDiff line change
@@ -647,6 +647,25 @@ custom_message.txt:1:8: code format error...
647647

648648
NOTE: If there are more than one elements with error message instruction in a prioritized choice, this feature may not work as you expect.
649649

650+
Change the Start Definition Rule
651+
--------------------------------
652+
653+
We can change the start definition rule as below.
654+
655+
```cpp
656+
peg::parser parser(
657+
R"(
658+
Start <- A
659+
A <- B (',' B)*
660+
B <- '[one]' / '[two]'
661+
%whitespace <- [ \t\n]*
662+
)",
663+
"A" // Start Rule is "A"
664+
)";
665+
666+
parser.parse(" [one] , [two] "); // OK
667+
```
668+
650669
peglint - PEG syntax lint utility
651670
---------------------------------
652671

Diff for: docs/index.html

+1
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
<li><span>Source Code</span></li>
2121
<li class="editor-options">
2222
<ul class="editor-header-options">
23+
<li class="option"><label>Start Rule: </label><input id="start-rule" type="text"></li>
2324
<li class="option"><input id="packrat" type="checkbox"><label>Packrat</label></li>
2425
<li class="option"><input id="auto-refresh" type="checkbox"><label>Auto Refresh</label></li>
2526
<li class="option"><button id="parse" class="parse">Parse</button></li>

Diff for: docs/index.js

+5-1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ const codeAstOptimized = setupInfoArea("code-ast-optimized");
2727
const codeProfile = setupInfoArea("code-profile");
2828

2929
$('#opt-mode').val(localStorage.getItem('optimizationMode') || 'all');
30+
$('#start-rule').val(localStorage.getItem('startRule') || '');
3031
$('#packrat').prop('checked', localStorage.getItem('packrat') === 'true');
3132
$('#auto-refresh').prop('checked', localStorage.getItem('autoRefresh') === 'true');
3233
$('#parse').prop('disabled', $('#auto-refresh').prop('checked'));
@@ -61,6 +62,7 @@ function updateLocalStorage() {
6162
localStorage.setItem('grammarText', grammar.getValue());
6263
localStorage.setItem('codeText', code.getValue());
6364
localStorage.setItem('optimizationMode', $('#opt-mode').val());
65+
localStorage.setItem('startRule', $('#start-rule').val());
6466
localStorage.setItem('packrat', $('#packrat').prop('checked'));
6567
localStorage.setItem('autoRefresh', $('#auto-refresh').prop('checked'));
6668
}
@@ -75,6 +77,7 @@ function parse() {
7577
const codeText = code.getValue();
7678

7779
const optimizationMode = $('#opt-mode').val();
80+
const startRule = $('#start-rule').val();
7881
const packrat = $('#packrat').prop('checked');
7982

8083
$grammarInfo.html('');
@@ -97,7 +100,7 @@ function parse() {
97100
'background-color': 'rgba(0, 0, 0, 0.1)'
98101
});
99102
window.setTimeout(() => {
100-
const data = JSON.parse(Module.lint(grammarText, codeText, mode, packrat));
103+
const data = JSON.parse(Module.lint(grammarText, codeText, mode, packrat, startRule));
101104
$('#overlay').css({
102105
'z-index': '-1',
103106
'display': 'none',
@@ -165,6 +168,7 @@ $('#code-info').on('click', 'li', makeOnClickInInfo(code));
165168

166169
// Event handing in the AST optimization
167170
$('#opt-mode').on('change', setupTimer);
171+
$('#start-rule').on('keydown', setupTimer);
168172
$('#packrat').on('change', setupTimer);
169173
$('#auto-refresh').on('change', () => {
170174
updateLocalStorage();

Diff for: docs/native.cpp

+7-5
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@ std::string escape_json(const std::string &s) {
2121
std::function<void(size_t, size_t, const std::string &, const std::string &)>
2222
makeJSONFormatter(peg::parser &peg, std::string &json, bool &init) {
2323
init = true;
24-
return [&](size_t ln, size_t col, const std::string &msg, const std::string &rule) mutable {
24+
return [&](size_t ln, size_t col, const std::string &msg,
25+
const std::string &rule) mutable {
2526
if (!init) { json += ","; }
2627
json += "{";
2728
json += R"("ln":)" + std::to_string(ln) + ",";
@@ -43,11 +44,11 @@ makeJSONFormatter(peg::parser &peg, std::string &json, bool &init) {
4344
}
4445

4546
bool parse_grammar(const std::string &text, peg::parser &peg,
46-
std::string &json) {
47+
const std::string &startRule, std::string &json) {
4748
bool init;
4849
peg.set_logger(makeJSONFormatter(peg, json, init));
4950
json += "[";
50-
auto ret = peg.load_grammar(text.data(), text.size());
51+
auto ret = peg.load_grammar(text.data(), text.size(), startRule);
5152
json += "]";
5253
return ret;
5354
}
@@ -64,15 +65,16 @@ bool parse_code(const std::string &text, peg::parser &peg, std::string &json,
6465
}
6566

6667
std::string lint(const std::string &grammarText, const std::string &codeText,
67-
bool opt_mode, bool packrat) {
68+
bool opt_mode, bool packrat, const std::string &startRule) {
6869
std::string grammarResult;
6970
std::string codeResult;
7071
std::string astResult;
7172
std::string astResultOptimized;
7273
std::string profileResult;
7374

7475
peg::parser peg;
75-
auto is_grammar_valid = parse_grammar(grammarText, peg, grammarResult);
76+
auto is_grammar_valid =
77+
parse_grammar(grammarText, peg, startRule, grammarResult);
7678
auto is_source_valid = false;
7779

7880
if (is_grammar_valid && peg) {

Diff for: docs/native.wasm

1.1 KB
Binary file not shown.

Diff for: peglib.h

+67-50
Original file line numberDiff line numberDiff line change
@@ -3298,18 +3298,15 @@ using Rules = std::unordered_map<std::string, std::shared_ptr<Ope>>;
32983298

32993299
class ParserGenerator {
33003300
public:
3301-
static std::shared_ptr<Grammar> parse(const char *s, size_t n,
3302-
const Rules &rules, std::string &start,
3303-
bool &enablePackratParsing, Log log) {
3304-
return get_instance().perform_core(s, n, rules, start, enablePackratParsing,
3305-
log);
3306-
}
3301+
struct ParserContext {
3302+
std::shared_ptr<Grammar> grammar;
3303+
std::string start;
3304+
bool enablePackratParsing = false;
3305+
};
33073306

3308-
static std::shared_ptr<Grammar> parse(const char *s, size_t n,
3309-
std::string &start,
3310-
bool &enablePackratParsing, Log log) {
3311-
Rules dummy;
3312-
return parse(s, n, dummy, start, enablePackratParsing, log);
3307+
static ParserContext parse(const char *s, size_t n, const Rules &rules,
3308+
Log log, std::string_view start) {
3309+
return get_instance().perform_core(s, n, rules, log, std::string(start));
33133310
}
33143311

33153312
// For debugging purpose
@@ -3989,9 +3986,8 @@ class ParserGenerator {
39893986
return true;
39903987
}
39913988

3992-
std::shared_ptr<Grammar> perform_core(const char *s, size_t n,
3993-
const Rules &rules, std::string &start,
3994-
bool &enablePackratParsing, Log log) {
3989+
ParserContext perform_core(const char *s, size_t n, const Rules &rules,
3990+
Log log, std::string requested_start) {
39953991
Data data;
39963992
auto &grammar = *data.grammar;
39973993

@@ -4023,7 +4019,7 @@ class ParserGenerator {
40234019
log(line.first, line.second, "syntax error", r.error_info.label);
40244020
}
40254021
}
4026-
return nullptr;
4022+
return {};
40274023
}
40284024

40294025
// User provided rules
@@ -4081,7 +4077,25 @@ class ParserGenerator {
40814077
}
40824078

40834079
// Set root definition
4084-
auto &start_rule = grammar[data.start];
4080+
auto start = data.start;
4081+
4082+
if (!requested_start.empty()) {
4083+
if (grammar.count(requested_start)) {
4084+
start = requested_start;
4085+
} else {
4086+
if (log) {
4087+
auto line = line_info(s, s);
4088+
log(line.first, line.second,
4089+
"The specified start rule '" + requested_start + "' is undefined.",
4090+
"");
4091+
}
4092+
ret = false;
4093+
}
4094+
}
4095+
4096+
if (!ret) { return {}; }
4097+
4098+
auto &start_rule = grammar[start];
40854099

40864100
// Check if the start rule has ignore operator
40874101
{
@@ -4096,7 +4110,7 @@ class ParserGenerator {
40964110
}
40974111
}
40984112

4099-
if (!ret) { return nullptr; }
4113+
if (!ret) { return {}; }
41004114

41014115
// Check missing definitions
41024116
auto referenced = std::unordered_set<std::string>{
@@ -4129,7 +4143,7 @@ class ParserGenerator {
41294143
}
41304144
}
41314145

4132-
if (!ret) { return nullptr; }
4146+
if (!ret) { return {}; }
41334147

41344148
// Link references
41354149
for (auto &x : grammar) {
@@ -4153,10 +4167,10 @@ class ParserGenerator {
41534167
}
41544168
}
41554169

4156-
if (!ret) { return nullptr; }
4170+
if (!ret) { return {}; }
41574171

41584172
// Check infinite loop
4159-
if (detect_infiniteLoop(data, start_rule, log, s)) { return nullptr; }
4173+
if (detect_infiniteLoop(data, start_rule, log, s)) { return {}; }
41604174

41614175
// Automatic whitespace skipping
41624176
if (grammar.count(WHITESPACE_DEFINITION_NAME)) {
@@ -4169,15 +4183,15 @@ class ParserGenerator {
41694183
auto &rule = grammar[WHITESPACE_DEFINITION_NAME];
41704184
start_rule.whitespaceOpe = wsp(rule.get_core_operator());
41714185

4172-
if (detect_infiniteLoop(data, rule, log, s)) { return nullptr; }
4186+
if (detect_infiniteLoop(data, rule, log, s)) { return {}; }
41734187
}
41744188

41754189
// Word expression
41764190
if (grammar.count(WORD_DEFINITION_NAME)) {
41774191
auto &rule = grammar[WORD_DEFINITION_NAME];
41784192
start_rule.wordOpe = rule.get_core_operator();
41794193

4180-
if (detect_infiniteLoop(data, rule, log, s)) { return nullptr; }
4194+
if (detect_infiniteLoop(data, rule, log, s)) { return {}; }
41814195
}
41824196

41834197
// Apply instructions
@@ -4189,9 +4203,7 @@ class ParserGenerator {
41894203
const auto &info =
41904204
std::any_cast<PrecedenceClimbing::BinOpeInfo>(instruction.data);
41914205

4192-
if (!apply_precedence_instruction(rule, info, s, log)) {
4193-
return nullptr;
4194-
}
4206+
if (!apply_precedence_instruction(rule, info, s, log)) { return {}; }
41954207
} else if (instruction.type == "error_message") {
41964208
rule.error_message = std::any_cast<std::string>(instruction.data);
41974209
} else if (instruction.type == "no_ast_opt") {
@@ -4200,11 +4212,7 @@ class ParserGenerator {
42004212
}
42014213
}
42024214

4203-
// Set root definition
4204-
start = data.start;
4205-
enablePackratParsing = data.enablePackratParsing;
4206-
4207-
return data.grammar;
4215+
return {data.grammar, start, data.enablePackratParsing};
42084216
}
42094217

42104218
bool detect_infiniteLoop(const Data &data, Definition &rule, const Log &log,
@@ -4530,43 +4538,52 @@ class parser {
45304538
public:
45314539
parser() = default;
45324540

4533-
parser(const char *s, size_t n, const Rules &rules) {
4534-
load_grammar(s, n, rules);
4541+
parser(const char *s, size_t n, const Rules &rules,
4542+
std::string_view start = {}) {
4543+
load_grammar(s, n, rules, start);
45354544
}
45364545

4537-
parser(const char *s, size_t n) : parser(s, n, Rules()) {}
4546+
parser(const char *s, size_t n, std::string_view start = {})
4547+
: parser(s, n, Rules(), start) {}
45384548

4539-
parser(std::string_view sv, const Rules &rules)
4540-
: parser(sv.data(), sv.size(), rules) {}
4549+
parser(std::string_view sv, const Rules &rules, std::string_view start = {})
4550+
: parser(sv.data(), sv.size(), rules, start) {}
45414551

4542-
parser(std::string_view sv) : parser(sv.data(), sv.size(), Rules()) {}
4552+
parser(std::string_view sv, std::string_view start = {})
4553+
: parser(sv.data(), sv.size(), Rules(), start) {}
45434554

45444555
#if defined(__cpp_lib_char8_t)
4545-
parser(std::u8string_view sv, const Rules &rules)
4546-
: parser(reinterpret_cast<const char *>(sv.data()), sv.size(), rules) {}
4556+
parser(std::u8string_view sv, const Rules &rules, std::string_view start = {})
4557+
: parser(reinterpret_cast<const char *>(sv.data()), sv.size(), rules,
4558+
start) {}
45474559

4548-
parser(std::u8string_view sv)
4549-
: parser(reinterpret_cast<const char *>(sv.data()), sv.size(), Rules()) {}
4560+
parser(std::u8string_view sv, std::string_view start = {})
4561+
: parser(reinterpret_cast<const char *>(sv.data()), sv.size(), Rules(),
4562+
start) {}
45504563
#endif
45514564

45524565
operator bool() { return grammar_ != nullptr; }
45534566

4554-
bool load_grammar(const char *s, size_t n, const Rules &rules) {
4555-
grammar_ = ParserGenerator::parse(s, n, rules, start_,
4556-
enablePackratParsing_, log_);
4567+
bool load_grammar(const char *s, size_t n, const Rules &rules,
4568+
std::string_view start = {}) {
4569+
auto cxt = ParserGenerator::parse(s, n, rules, log_, start);
4570+
grammar_ = cxt.grammar;
4571+
start_ = cxt.start;
4572+
enablePackratParsing_ = cxt.enablePackratParsing;
45574573
return grammar_ != nullptr;
45584574
}
45594575

4560-
bool load_grammar(const char *s, size_t n) {
4561-
return load_grammar(s, n, Rules());
4576+
bool load_grammar(const char *s, size_t n, std::string_view start = {}) {
4577+
return load_grammar(s, n, Rules(), start);
45624578
}
45634579

4564-
bool load_grammar(std::string_view sv, const Rules &rules) {
4565-
return load_grammar(sv.data(), sv.size(), rules);
4580+
bool load_grammar(std::string_view sv, const Rules &rules,
4581+
std::string_view start = {}) {
4582+
return load_grammar(sv.data(), sv.size(), rules, start);
45664583
}
45674584

4568-
bool load_grammar(std::string_view sv) {
4569-
return load_grammar(sv.data(), sv.size());
4585+
bool load_grammar(std::string_view sv, std::string_view start = {}) {
4586+
return load_grammar(sv.data(), sv.size(), start);
45704587
}
45714588

45724589
bool parse_n(const char *s, size_t n, const char *path = nullptr) const {
@@ -4671,7 +4688,7 @@ class parser {
46714688
void enable_packrat_parsing() {
46724689
if (grammar_ != nullptr) {
46734690
auto &rule = (*grammar_)[start_];
4674-
rule.enablePackratParsing = enablePackratParsing_ && true;
4691+
rule.enablePackratParsing = enablePackratParsing_;
46754692
}
46764693
}
46774694

0 commit comments

Comments
 (0)