From a698ea6145a200890f222ce7545ff34d7c5aeede Mon Sep 17 00:00:00 2001 From: Ulya Trofimovich Date: Thu, 29 Dec 2016 17:07:52 +0000 Subject: [PATCH] Memorize options for each block and use them for delayed code generation. Option scope is very poorly defined in re2c. Most options should have block scope, but some have global scope (because they belong to global directives like '/*!types:re2c ... */', '/*!tags:re2c ... */' or other global things like generation date, etc.). For now, options are applied immediately as they are parsed. Code generation just reads the most recent state of options, so the output depends not only on the location in source code when the option is defined, but also on program points in which re2c generates and outputs code. Generation and output may happen at different times, so they may use different options. This is all very bad. This commit is the first attempt to introduce scoped options: re2c now makes a snapshot of options at the end of each block and uses this snapshot for delayed code generation for this block (unless the given option must be global). This is not perfect (immediate code generation still uses 'seen-so-far' options instead of block options), but at least it allows to delay code generation for non-global things without loosing options. --- re2c/bootstrap/src/parse/lex.cc | 2 +- re2c/bootstrap/src/parse/parser.cc | 6 +++- re2c/src/codegen/output.cc | 56 ++++++++++++++---------------- re2c/src/codegen/output.h | 15 ++++---- re2c/src/conf/opt.h | 3 ++ re2c/src/parse/parser.ypp | 6 +++- 6 files changed, 48 insertions(+), 40 deletions(-) diff --git a/re2c/bootstrap/src/parse/lex.cc b/re2c/bootstrap/src/parse/lex.cc index 79a043a8..3dc2caac 100644 --- a/re2c/bootstrap/src/parse/lex.cc +++ b/re2c/bootstrap/src/parse/lex.cc @@ -1,4 +1,4 @@ -/* Generated by re2c 0.16 on Tue Dec 27 20:54:24 2016 */ +/* Generated by re2c 0.16 on Thu Dec 29 16:34:43 2016 */ #line 1 "../src/parse/lex.re" #include "src/util/c99_stdint.h" #include diff --git a/re2c/bootstrap/src/parse/parser.cc b/re2c/bootstrap/src/parse/parser.cc index 45e1cb94..397897ec 100644 --- a/re2c/bootstrap/src/parse/parser.cc +++ b/re2c/bootstrap/src/parse/parser.cc @@ -2056,6 +2056,7 @@ void parse(Scanner &input, Output & o) ScannerState rules_state, curr_state; Opt &opts = input.opts; + o.source.new_block(); o.source.wversion_time () .wline_info (input.get_cline (), input.get_fname ().c_str ()); if (opts->target == opt_t::SKELETON) @@ -2065,7 +2066,9 @@ void parse(Scanner &input, Output & o) Enc encodingOld = opts->encoding; for (Scanner::ParseMode mode; (mode = input.echo()) != Scanner::Stop;) { - o.source.new_block (); + + o.source.block().opts = opts.snapshot(); + o.source.new_block(); input.save_state(curr_state); if (opts->rFlag && mode == Scanner::Rules && !dfas.empty()) @@ -2139,6 +2142,7 @@ void parse(Scanner &input, Output & o) { emit_epilog (o.source, o.skeletons); } + o.source.block().opts = opts.snapshot(); RegExp::flist.clear(); Code::flist.clear(); diff --git a/re2c/src/codegen/output.cc b/re2c/src/codegen/output.cc index eebbebfa..224300ca 100644 --- a/re2c/src/codegen/output.cc +++ b/re2c/src/codegen/output.cc @@ -47,6 +47,7 @@ OutputBlock::OutputBlock () , line (0) , types () , tags () + , opts(NULL) { fragments.push_back (new OutputFragment (OutputFragment::CODE, 0)); } @@ -57,6 +58,7 @@ OutputBlock::~OutputBlock () { delete fragments[i]; } + delete opts; } OutputFile::OutputFile(Opt &o, Warn &w) @@ -68,9 +70,7 @@ OutputFile::OutputFile(Opt &o, Warn &w) , warn_condition_order (!o->tFlag) // see note [condition order] , opts(o) , warn(w) -{ - new_block (); -} +{} OutputFile::~OutputFile () { @@ -124,7 +124,7 @@ OutputFile & OutputFile::wu32_width (uint32_t n, int w) OutputFile & OutputFile::wline_info (uint32_t l, const char * fn) { - output_line_info (stream (), l, fn, opts); + output_line_info (stream (), l, fn, opts->iFlag); return *this; } @@ -305,17 +305,17 @@ bool OutputFile::emit(const uniq_vector_t &global_types, switch (f.type) { case OutputFragment::CODE: break; case OutputFragment::LINE_INFO: - output_line_info(f.stream, line_count + 1, filename, opts); + output_line_info(f.stream, line_count + 1, filename, b.opts->iFlag); break; case OutputFragment::COND_GOTO: output_cond_goto(f.stream, f.indent, b.types, - opts, warn, warn_condition_order, b.line); + b.opts, warn, warn_condition_order, b.line); break; case OutputFragment::COND_TABLE: - output_cond_table(f.stream, f.indent, b.types, opts); + output_cond_table(f.stream, f.indent, b.types, b.opts); break; case OutputFragment::STATE_GOTO: - output_state_goto(f.stream, f.indent, 0, fill_index, opts); + output_state_goto(f.stream, f.indent, 0, fill_index, b.opts); break; case OutputFragment::TAGS: output_tags(f.stream, *f.tags, global_tags); @@ -324,7 +324,7 @@ bool OutputFile::emit(const uniq_vector_t &global_types, output_types(f.stream, f.indent, global_types, opts); break; case OutputFragment::YYACCEPT_INIT: - output_yyaccept_init(f.stream, f.indent, b.used_yyaccept, opts); + output_yyaccept_init(f.stream, f.indent, b.used_yyaccept, b.opts); break; case OutputFragment::YYMAXFILL: output_yymaxfill(f.stream, max_fill); @@ -360,7 +360,7 @@ bool HeaderFile::emit(const uniq_vector_t &types, Opt &opts) } output_version_time(stream, opts); - output_line_info(stream, 3, filename, opts); + output_line_info(stream, 3, filename, opts->iFlag); stream << "\n"; output_types(stream, 0, types, opts); @@ -410,10 +410,15 @@ void output_tags(std::ostream &o, const ConfTags &conf, } void output_state_goto(std::ostream & o, uint32_t ind, - uint32_t start_label, uint32_t fill_index, Opt &opts) + uint32_t start_label, uint32_t fill_index, const opt_t *opts) { - const std::string indstr = indent(ind, opts->indString); - o << indstr << "switch (" << output_get_state(opts) << ") {\n"; + const std::string + indstr = indent(ind, opts->indString), + getstate = opts->state_get_naked + ? opts->state_get + : opts->state_get + "()"; + + o << indstr << "switch (" << getstate << ") {\n"; if (opts->bUseStateAbort) { o << indstr << "default: abort();\n"; @@ -434,7 +439,7 @@ void output_state_goto(std::ostream & o, uint32_t ind, } } -void output_yyaccept_init (std::ostream & o, uint32_t ind, bool used_yyaccept, Opt &opts) +void output_yyaccept_init (std::ostream & o, uint32_t ind, bool used_yyaccept, const opt_t *opts) { if (used_yyaccept) { @@ -447,11 +452,11 @@ void output_yymaxfill (std::ostream & o, size_t max_fill) o << "#define YYMAXFILL " << max_fill << "\n"; } -void output_line_info (std::ostream & o, uint32_t line_number, const std::string &file_name, Opt &opts) +void output_line_info(std::ostream &o, uint32_t line, + const std::string &fname, bool iflag) { - if (!opts->iFlag) - { - o << "#line " << line_number << " \"" << file_name << "\"\n"; + if (!iflag) { + o << "#line " << line << " \"" << fname << "\"\n"; } } @@ -484,13 +489,6 @@ void output_version_time (std::ostream & o, Opt &opts) o << " */" << "\n"; } -std::string output_get_state (Opt &opts) -{ - return opts->state_get_naked - ? opts->state_get - : opts->state_get + "()"; -} - /* * note [condition order] * @@ -515,13 +513,13 @@ std::string output_get_state (Opt &opts) * dispatch shrinks to unconditional jump */ -static std::string output_cond_get(Opt &opts) +static std::string output_cond_get(const opt_t *opts) { return opts->cond_get + (opts->cond_get_naked ? "" : "()"); } static void output_cond_goto_binary(std::ostream &o, uint32_t ind, - const std::vector &conds, Opt &opts, + const std::vector &conds, const opt_t *opts, size_t lower, size_t upper) { const std::string indstr = indent(ind, opts->indString); @@ -539,7 +537,7 @@ static void output_cond_goto_binary(std::ostream &o, uint32_t ind, } void output_cond_goto(std::ostream &o, uint32_t ind, - const std::vector &conds, Opt &opts, + const std::vector &conds, const opt_t *opts, Warn &warn, bool warn_cond_order, uint32_t line) { const size_t ncond = conds.size(); @@ -575,7 +573,7 @@ void output_cond_goto(std::ostream &o, uint32_t ind, } void output_cond_table(std::ostream &o, uint32_t ind, - const std::vector &conds, Opt &opts) + const std::vector &conds, const opt_t *opts) { const size_t ncond = conds.size(); const std::string indstr = opts->indString; diff --git a/re2c/src/codegen/output.h b/re2c/src/codegen/output.h index 364c12b0..5c2b7c8a 100644 --- a/re2c/src/codegen/output.h +++ b/re2c/src/codegen/output.h @@ -66,9 +66,11 @@ struct OutputBlock uint32_t line; std::vector types; std::set tags; + const opt_t *opts; OutputBlock (); ~OutputBlock (); + FORBID_COPY(OutputBlock); }; class OutputFile @@ -151,18 +153,15 @@ struct Output }; void output_tags (std::ostream &o, const ConfTags &conf, const std::set &tags); -void output_line_info (std::ostream &o, uint32_t ind, const std::string &file_name, Opt &opts); -void output_cond_goto (std::ostream &o, uint32_t ind, const std::vector &conds, Opt &opts, Warn &warn, bool warn_cond_order, uint32_t line); -void output_cond_table (std::ostream &o, uint32_t ind, const std::vector &conds, Opt &opts); -void output_state_goto (std::ostream &o, uint32_t ind, uint32_t start_label, uint32_t fill_index, Opt &opts); +void output_line_info (std::ostream &o, uint32_t line, const std::string &fname, bool iflag); +void output_cond_goto (std::ostream &o, uint32_t ind, const std::vector &conds, const opt_t *opts, Warn &warn, bool warn_cond_order, uint32_t line); +void output_cond_table (std::ostream &o, uint32_t ind, const std::vector &conds, const opt_t *opts); +void output_state_goto (std::ostream &o, uint32_t ind, uint32_t start_label, uint32_t fill_index, const opt_t *opts); void output_types (std::ostream &o, uint32_t ind, const uniq_vector_t &types, Opt &opts); void output_version_time (std::ostream &o, Opt &opts); -void output_yyaccept_init (std::ostream &o, uint32_t ind, bool, Opt &opts); +void output_yyaccept_init (std::ostream &o, uint32_t ind, bool, const opt_t *opts); void output_yymaxfill (std::ostream &o, size_t max_fill); -// helpers -std::string output_get_state (Opt &opts); - } // namespace re2c #endif // _RE2C_CODEGEN_OUTPUT_ diff --git a/re2c/src/conf/opt.h b/re2c/src/conf/opt.h index 17e85348..61ea95c6 100644 --- a/re2c/src/conf/opt.h +++ b/re2c/src/conf/opt.h @@ -152,6 +152,7 @@ public: realopt_t (useropt_t & opt); const opt_t * operator -> (); void sync (); + const opt_t *snapshot() const { return new opt_t(real); } }; class useropt_t @@ -181,6 +182,8 @@ public: , realopt (useropt) {} + const opt_t *snapshot() const { return realopt.snapshot(); } + // read-only access, forces options syncronization const opt_t * operator -> () { diff --git a/re2c/src/parse/parser.ypp b/re2c/src/parse/parser.ypp index 8e1b990c..c42b7c2b 100644 --- a/re2c/src/parse/parser.ypp +++ b/re2c/src/parse/parser.ypp @@ -431,6 +431,7 @@ void parse(Scanner &input, Output & o) ScannerState rules_state, curr_state; Opt &opts = input.opts; + o.source.new_block(); o.source.wversion_time () .wline_info (input.get_cline (), input.get_fname ().c_str ()); if (opts->target == opt_t::SKELETON) @@ -440,7 +441,9 @@ void parse(Scanner &input, Output & o) Enc encodingOld = opts->encoding; for (Scanner::ParseMode mode; (mode = input.echo()) != Scanner::Stop;) { - o.source.new_block (); + + o.source.block().opts = opts.snapshot(); + o.source.new_block(); input.save_state(curr_state); if (opts->rFlag && mode == Scanner::Rules && !dfas.empty()) @@ -514,6 +517,7 @@ void parse(Scanner &input, Output & o) { emit_epilog (o.source, o.skeletons); } + o.source.block().opts = opts.snapshot(); RegExp::flist.clear(); Code::flist.clear(); -- 2.40.0