Skip to content

Commit 8f8d71e

Browse files
committed
Generate non-overlapping YYFILL labels for reuse blocks.
Since all reuse blocks have their own enumeration of YYFILL states starting from zero and their own state dispatch (not shared with other blocks, as in the case of non-reuse blocks), YYFILL labels in reuse blocks have identical indices. This patch adds block ID infix to such labels in order to prevent label collision if blocks are located in the same function. This partially fixes #282 "Options -f, -c and -r do not combine well".
1 parent a7542f2 commit 8f8d71e

File tree

7 files changed

+148
-134
lines changed

7 files changed

+148
-134
lines changed

src/codegen/code.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -678,7 +678,7 @@ struct CodegenContext {
678678
const bool used_yyaccept;
679679
const bool warn_cond_ord;
680680
const uint32_t fill_index;
681-
const std::vector<CodeList*> &fill_fallback;
681+
const std::vector<CodeList*> &fill_goto;
682682
};
683683

684684
struct RenderContext {
@@ -707,8 +707,8 @@ struct OutputBlock {
707707
const opt_t *opts;
708708

709709
// used in state dispatch
710-
uint32_t fill_index; // maximal YYFILL label for this block
711-
std::vector<CodeList*> fill_fallback; // fallback transitions on YYFILL failure
710+
uint32_t fill_index; // upper bound of YYFILL state index
711+
std::vector<CodeList*> fill_goto; // transitions to YYFILL states
712712

713713
OutputBlock(const loc_t &loc, bool reuse);
714714
~OutputBlock();
@@ -738,8 +738,8 @@ class Output {
738738
Scratchbuf scratchbuf;
739739

740740
// used in state dispatch (accumulated for all non-reuse blocks)
741-
uint32_t total_fill_index; // maximal YYFILL label
742-
std::vector<CodeList*> total_fill_fallback; // fallback transitions on YYFILL failure
741+
uint32_t total_fill_index; // upper bound of YYFILL state index
742+
std::vector<CodeList*> total_fill_goto; // transitions to YYFILL states
743743

744744
// "final" options accumulated for all non-reuse blocks
745745
const opt_t *total_opts;

src/codegen/gen_delayed.cc

Lines changed: 7 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -79,45 +79,29 @@ static void gen_state_goto(CodegenContext &ctx, Code *code)
7979
text = o.cstr("goto ").str(opts->labelPrefix).u32(0).flush();
8080
append(goto_start, code_stmt(alc, text));
8181

82-
CodeCases *ccases = code_cases(alc);
82+
CodeCases *cases = code_cases(alc);
8383
if (opts->bUseStateAbort) {
8484
// default: abort();
8585
CodeList *abort = code_list(alc);
8686
append(abort, code_stmt(alc, "abort()"));
87-
append(ccases, code_case_default(alc, abort));
87+
append(cases, code_case_default(alc, abort));
8888

8989
// case -1: goto <start label>;
90-
append(ccases, code_case_number(alc, goto_start, -1));
90+
append(cases, code_case_number(alc, goto_start, -1));
9191
}
9292
else {
9393
// default: goto <start label>;
94-
append(ccases, code_case_default(alc, goto_start));
94+
append(cases, code_case_default(alc, goto_start));
9595
}
9696

97-
DASSERT(opts->eof == NOEOF || ctx.fill_index == ctx.fill_fallback.size());
97+
DASSERT(ctx.fill_index == ctx.fill_goto.size());
9898
for (uint32_t i = 0; i < ctx.fill_index; ++i) {
99-
CodeList *stmts = code_list(alc);
100-
101-
// If EOF rule is used, handle possible YYFILL failure: if there is still
102-
// not enough input, follow the default/final transition for i-th state.
103-
// Inline the code for transition here rather than jumping to the
104-
// corresponding condition branch in DFA, since not all language backends
105-
// support jumping in the middle of a nested block (Golang doesn't).
106-
if (opts->eof != NOEOF) {
107-
text = gen_lessthan(o, opts, 1);
108-
append(stmts, code_if_then_else(alc, text, ctx.fill_fallback[i], NULL));
109-
}
110-
111-
// goto yyFillLabel<i>;
112-
text = o.cstr("goto ").str(opts->yyfilllabel).u32(i).flush();
113-
append(stmts, code_stmt(alc, text));
114-
115-
append(ccases, code_case_number(alc, stmts, static_cast<int32_t>(i)));
99+
append(cases, code_case_number(alc, ctx.fill_goto[i], static_cast<int32_t>(i)));
116100
}
117101

118102
CodeList *stmts = code_list(alc);
119103
text = o.str(opts->state_get).cstr(opts->state_get_naked ? "" : "()").flush();
120-
append(stmts, code_switch(alc, text, ccases));
104+
append(stmts, code_switch(alc, text, cases));
121105

122106
if (opts->bUseStateNext) {
123107
text = o.str(opts->yynext).cstr(":").flush();

src/codegen/gen_program.cc

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,7 @@ OutputBlock::OutputBlock(const loc_t &loc, bool reuse)
5353
, mtags()
5454
, opts(NULL)
5555
, fill_index(0)
56-
, fill_fallback()
56+
, fill_goto()
5757
{}
5858

5959
OutputBlock::~OutputBlock ()
@@ -78,7 +78,7 @@ Output::Output(Msg &msg)
7878
, allocator()
7979
, scratchbuf(allocator)
8080
, total_fill_index(0)
81-
, total_fill_fallback()
81+
, total_fill_goto()
8282
, total_opts(NULL)
8383
{}
8484

@@ -151,8 +151,8 @@ void Output::gather_info_from_block()
151151
const OutputBlock *b = pblocks->back();
152152
if (!b->is_reuse_block) {
153153
total_fill_index = b->fill_index;
154-
total_fill_fallback.insert(total_fill_fallback.end(),
155-
b->fill_fallback.begin(), b->fill_fallback.end());
154+
total_fill_goto.insert(total_fill_goto.end(),
155+
b->fill_goto.begin(), b->fill_goto.end());
156156
}
157157
}
158158

@@ -211,7 +211,7 @@ bool Output::emit_blocks(const std::string &fname, blocks_t &blocks,
211211
, b.used_yyaccept
212212
, warn_condition_order
213213
, b.is_reuse_block ? b.fill_index : total_fill_index
214-
, b.is_reuse_block ? b.fill_fallback : total_fill_fallback
214+
, b.is_reuse_block ? b.fill_goto : total_fill_goto
215215
};
216216

217217
const size_t n = b.fragments.size();

src/codegen/gen_state.cc

Lines changed: 45 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,19 @@ static void gen_fintags(Output &output, CodeList *stmts, const DFA &dfa, const R
3131
static Code *gen_on_eof(Output &output, const DFA &dfa, const State *from, const State *to);
3232
static bool endstate(const State *s);
3333

34+
static const char *gen_yyfill_label(Output &output, uint32_t index)
35+
{
36+
const opt_t *opts = output.block().opts;
37+
Scratchbuf &o = output.scratchbuf;
38+
DASSERT(o.empty());
39+
40+
o.str(opts->yyfilllabel);
41+
if (output.block().is_reuse_block) o.u64(output.blockid()).cstr("_");
42+
o.u32(index);
43+
44+
return o.flush();
45+
}
46+
3447
void emit_action(Output &output, const DFA &dfa, const State *s, CodeList *stmts)
3548
{
3649
const opt_t *opts = output.block().opts;
@@ -305,25 +318,26 @@ void gen_fill_noeof(Output &output, CodeList *stmts, size_t some)
305318
}
306319

307320
if (opts->fFlag) {
308-
text = o.str(opts->yyfilllabel).u32(fill_index).flush();
309-
append(stmts, code_slabel(alc, text));
321+
const char *flabel = gen_yyfill_label(output, fill_index);
322+
323+
// YYFILL label
324+
append(stmts, code_slabel(alc, flabel));
325+
326+
// Save transition to YYFILL label from the initial state dispatch.
327+
CodeList *goto_flabel = code_list(alc);
328+
text = o.cstr("goto ").cstr(flabel).flush();
329+
append(goto_flabel, code_stmt(alc, text));
330+
output.block().fill_goto.push_back(goto_flabel);
310331
}
311332
}
312333

313334
void gen_rescan_label(Output &output, CodeList *stmts, const State *s)
314335
{
315336
const opt_t *opts = output.block().opts;
316-
317-
if (opts->eof == NOEOF || !opts->fill_use || endstate(s)) {
318-
return; // no rescan label
337+
if (opts->eof != NOEOF && opts->fill_use && !endstate(s)) {
338+
const uint32_t fillidx = output.block().fill_index++;
339+
append(stmts, code_slabel(output.allocator, gen_yyfill_label(output, fillidx)));
319340
}
320-
321-
code_alc_t &alc = output.allocator;
322-
Scratchbuf &o = output.scratchbuf;
323-
const uint32_t fill_index = output.block().fill_index++;
324-
325-
const char *text = o.str(opts->yyfilllabel).u32(fill_index).flush();
326-
append(stmts, code_slabel(alc, text));
327341
}
328342

329343
void gen_goto(Output &output, const DFA &dfa, CodeList *stmts, const State *from,
@@ -423,7 +437,8 @@ Code *gen_on_eof(Output &output, const DFA &dfa, const State *from, const State
423437

424438
// go to retry label (on YYFILL success)
425439
CodeList *rescan = code_list(alc);
426-
text = o.cstr("goto ").str(opts->yyfilllabel).u32(fillidx).flush();
440+
const char *flabel = gen_yyfill_label(output, fillidx);
441+
text = o.cstr("goto ").cstr(flabel).flush();
427442
append(rescan, code_stmt(alc, text));
428443

429444
append(refill, code_if_then_else(alc, if_yyfill, rescan, NULL));
@@ -462,8 +477,23 @@ Code *gen_on_eof(Output &output, const DFA &dfa, const State *from, const State
462477
append(refill, fallback_trans);
463478
}
464479
else {
465-
// Save fallback transition for the initial state dispatch.
466-
output.block().fill_fallback.push_back(fallback_trans);
480+
CodeList *fill_goto = code_list(alc);
481+
482+
// With storable state and EOF rule the initial state dispatch needs to
483+
// handle YYFILL failure: if there is still not enough input, it must
484+
// follow the fallback transition for the state that triggered YYFILL.
485+
// Fallback transition is inlined in the state dispatch (as opposed to
486+
// jumping to the corresponding DFA transition) because Go backend does
487+
// not support jumping in the middle of a nested block.
488+
text = gen_lessthan(o, opts, 1);
489+
append(fill_goto, code_if_then_else(alc, text, fallback_trans, NULL));
490+
491+
// Transition to YYFILL label from the initial state dispatch.
492+
const char *flabel = gen_yyfill_label(output, fillidx);
493+
text = o.cstr("goto ").cstr(flabel).flush();
494+
append(fill_goto, code_stmt(alc, text));
495+
496+
output.block().fill_goto.push_back(fill_goto);
467497
}
468498

469499
return code_if_then_else(alc, if_refill, refill, NULL);

0 commit comments

Comments
 (0)