From: Ulya Trofimovich Date: Wed, 11 May 2016 10:17:49 +0000 (+0100) Subject: Allow to override output and header filenames with configurations. X-Git-Tag: 1.0~39^2~309 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=2cac33a7d1d0f20f3217a42048643f007d4c8b2f;p=re2c Allow to override output and header filenames with configurations. --- diff --git a/re2c/bootstrap/src/conf/parse_opts.cc b/re2c/bootstrap/src/conf/parse_opts.cc index 8134fe5b..d891b503 100644 --- a/re2c/bootstrap/src/conf/parse_opts.cc +++ b/re2c/bootstrap/src/conf/parse_opts.cc @@ -1,4 +1,4 @@ -/* Generated by re2c 0.16 on Tue May 10 13:30:37 2016 */ +/* Generated by re2c 0.16 on Wed May 11 11:08:20 2016 */ #line 1 "../src/conf/parse_opts.re" #include "src/codegen/input_api.h" #include "src/conf/msg.h" @@ -2458,7 +2458,7 @@ yy604: yy605: ++YYCURSOR; #line 173 "../src/conf/parse_opts.re" - { if (!opts.output (*argv)) return EXIT_FAIL; goto opt; } + { opts.set_output_file(*argv); goto opt; } #line 2463 "src/conf/parse_opts.cc" yy607: ++YYCURSOR; diff --git a/re2c/bootstrap/src/parse/lex_conf.cc b/re2c/bootstrap/src/parse/lex_conf.cc index 1656edd3..5908b28e 100644 --- a/re2c/bootstrap/src/parse/lex_conf.cc +++ b/re2c/bootstrap/src/parse/lex_conf.cc @@ -1,4 +1,4 @@ -/* Generated by re2c 0.16 on Tue May 10 16:46:34 2016 */ +/* Generated by re2c 0.16 on Wed May 11 11:08:20 2016 */ #line 1 "../src/parse/lex_conf.re" #include "src/util/c99_stdint.h" #include @@ -651,7 +651,7 @@ yy114: if (yych == 'u') goto yy159; yy115: #line 68 "../src/parse/lex_conf.re" - { if (!opts.output(lex_conf_string())) exit(1); return; } + { opts.set_output_file(lex_conf_string()); return; } #line 656 "src/parse/lex_conf.cc" yy116: yyaccept = 8; diff --git a/re2c/src/codegen/emit_dfa.cc b/re2c/src/codegen/emit_dfa.cc index 8d50dd47..84ef2af2 100644 --- a/re2c/src/codegen/emit_dfa.cc +++ b/re2c/src/codegen/emit_dfa.cc @@ -180,7 +180,7 @@ void DFA::emit(Output & output, uint32_t& ind, bool isLastCond, bool& bPrologBra if (opts->target == opt_t::SKELETON) { if (output.skeletons.insert (name).second) { - emit_data(*skeleton, o.file_name); + emit_data(*skeleton); emit_start(*skeleton, o, max_fill, need_backup, need_backupctx, need_accept, basetag, tagnames); uint32_t i = 2; diff --git a/re2c/src/codegen/output.cc b/re2c/src/codegen/output.cc index b1cfbd7f..b48e1d03 100644 --- a/re2c/src/codegen/output.cc +++ b/re2c/src/codegen/output.cc @@ -5,6 +5,7 @@ #include "src/codegen/indent.h" #include "src/codegen/output.h" #include "src/codegen/print.h" +#include "src/conf/msg.h" #include "src/conf/opt.h" #include "src/conf/warn.h" #include "src/util/strrreplace.h" @@ -61,10 +62,8 @@ OutputBlock::~OutputBlock () } } -OutputFile::OutputFile(const std::string &fn) - : file_name (fn) - , file (NULL) - , blocks () +OutputFile::OutputFile() + : blocks () , label_counter () , warn_condition_order (!opts->tFlag) // see note [condition order] , default_tags (true) @@ -72,28 +71,9 @@ OutputFile::OutputFile(const std::string &fn) new_block (); } -bool OutputFile::open () -{ - if (file_name.empty()) - { - file_name = ""; - file = stdout; - } - else - { - file = fopen (file_name.c_str(), "wb"); - } - return file != NULL; -} - OutputFile::~OutputFile () { - if (file != NULL && file != stdout) - { - fclose (file); - } - for (unsigned int i = 0; i < blocks.size (); ++i) - { + for (unsigned int i = 0; i < blocks.size(); ++i) { delete blocks[i]; } } @@ -289,116 +269,118 @@ void OutputFile::global_lists( } } -void OutputFile::emit( - const uniq_vector_t &global_types, +bool OutputFile::emit(const uniq_vector_t &global_types, const std::set &global_tags, size_t max_fill) { - if (file != NULL) - { - unsigned int line_count = 1; - for (unsigned int j = 0; j < blocks.size (); ++j) - { - OutputBlock & b = * blocks[j]; - for (unsigned int i = 0; i < b.fragments.size (); ++i) - { - OutputFragment & f = * b.fragments[i]; - switch (f.type) - { - case OutputFragment::CODE: - break; - case OutputFragment::LINE_INFO: - output_line_info (f.stream, line_count + 1, file_name); - break; - case OutputFragment::STATE_GOTO: - output_state_goto (f.stream, f.indent, 0); - break; - case OutputFragment::TAGS: - if (f.tags) { - output_tags(f.stream, *f.tags, global_tags); - } else if (default_tags) { - output_tags_default(f.stream, f.indent, b.tags); - } - break; - case OutputFragment::TYPES: - output_types (f.stream, f.indent, global_types); - break; - case OutputFragment::WARN_CONDITION_ORDER: - if (warn_condition_order) // see note [condition order] - { - warn.condition_order (b.line); - } - break; - case OutputFragment::YYACCEPT_INIT: - output_yyaccept_init (f.stream, f.indent, b.used_yyaccept); - break; - case OutputFragment::YYMAXFILL: - output_yymaxfill (f.stream, max_fill); - break; - } - std::string content = f.stream.str (); - fwrite (content.c_str (), 1, content.size (), file); - line_count += f.count_lines (); + FILE *file = NULL; + std::string filename = opts->output_file; + if (filename.empty()) { + filename = ""; + file = stdout; + } else { + file = fopen(filename.c_str(), "wb"); + if (!file) { + error("cannot open output file: %s", filename.c_str()); + return false; + } + } + + unsigned int line_count = 1; + for (unsigned int j = 0; j < blocks.size(); ++j) { + OutputBlock & b = * blocks[j]; + for (unsigned int i = 0; i < b.fragments.size(); ++i) { + OutputFragment & f = * b.fragments[i]; + switch (f.type) { + case OutputFragment::CODE: break; + case OutputFragment::LINE_INFO: + output_line_info(f.stream, line_count + 1, filename); + break; + case OutputFragment::STATE_GOTO: + output_state_goto(f.stream, f.indent, 0); + break; + case OutputFragment::TAGS: + if (f.tags) { + output_tags(f.stream, *f.tags, global_tags); + } else if (default_tags) { + output_tags_default(f.stream, f.indent, b.tags); + } + break; + case OutputFragment::TYPES: + output_types(f.stream, f.indent, global_types); + break; + case OutputFragment::WARN_CONDITION_ORDER: + if (warn_condition_order) {// see note [condition order] + warn.condition_order (b.line); + } + break; + case OutputFragment::YYACCEPT_INIT: + output_yyaccept_init(f.stream, f.indent, b.used_yyaccept); + break; + case OutputFragment::YYMAXFILL: + output_yymaxfill(f.stream, max_fill); + break; } + std::string content = f.stream.str(); + fwrite(content.c_str(), 1, content.size(), file); + line_count += f.count_lines(); } } + + fclose(file); + return true; } -HeaderFile::HeaderFile(const std::string &fn) - : stream () - // header is always generated, but not always dumped to file - // NULL filename crashes 'operator <<' on some platforms - // TODO: generate header only if necessary - , file_name (fn) - , file (NULL) +bool HeaderFile::emit(const uniq_vector_t &types) { - if (file_name.empty()) { - file_name = ".h"; + if (!opts->tFlag) { + return true; } -} -bool HeaderFile::open () -{ - file = fopen (file_name.c_str(), "wb"); - return file != NULL; -} + FILE *file = NULL; + std::string filename = opts->header_file; + if (filename.empty()) { + filename = ".h"; + file = stdout; + } else { + file = fopen(filename.c_str(), "wb"); + if (!file) { + error("cannot open header file: %s", filename.c_str()); + return false; + } + } -void HeaderFile::emit(const uniq_vector_t &types) -{ - output_version_time (stream); - output_line_info (stream, 3, file_name); + output_version_time(stream); + output_line_info(stream, 3, filename); stream << "\n"; output_types(stream, 0, types); -} -HeaderFile::~HeaderFile () -{ - if (file != NULL) - { - std::string content = stream.str (); - fwrite (content.c_str (), 1, content.size (), file); - fclose (file); - } + std::string content = stream.str(); + fwrite(content.c_str(), 1, content.size(), file); + + fclose(file); + return true; } -Output::Output(const std::string &source_name, const std::string &header_name) - : source(source_name) - , header(header_name) +Output::Output() + : source() + , header() , skeletons() , max_fill(1) {} -Output::~Output () +bool Output::emit() { - if (!warn.error ()) - { - uniq_vector_t types; - std::set tags; - source.global_lists(types, tags); - - source.emit(types, tags, max_fill); - header.emit(types); + if (warn.error()) { + return false; } + + uniq_vector_t types; + std::set tags; + source.global_lists(types, tags); + + return source.emit(types, tags, max_fill) + && header.emit(types); } void output_tags(std::ostream &o, const ConfTags &conf, diff --git a/re2c/src/codegen/output.h b/re2c/src/codegen/output.h index 1a2fba0a..497f6313 100644 --- a/re2c/src/codegen/output.h +++ b/re2c/src/codegen/output.h @@ -66,13 +66,8 @@ struct OutputBlock ~OutputBlock (); }; -struct OutputFile +class OutputFile { -public: - std::string file_name; - -private: - FILE * file; std::vector blocks; public: @@ -80,8 +75,8 @@ public: bool warn_condition_order; bool default_tags; - OutputFile(const std::string &fn); - ~OutputFile (); + OutputFile(); + ~OutputFile(); std::ostream & stream (); OutputBlock &block(); @@ -118,24 +113,19 @@ public: void global_lists(uniq_vector_t &types, std::set &tags) const; - void emit(const uniq_vector_t &global_types, + bool emit(const uniq_vector_t &global_types, const std::set &global_tags, size_t max_fill); FORBID_COPY (OutputFile); }; -struct HeaderFile +class HeaderFile { - HeaderFile(const std::string &fn); - ~HeaderFile (); - bool open (); - void emit(const uniq_vector_t &types); - -private: std::ostringstream stream; - std::string file_name; - FILE * file; +public: + HeaderFile(): stream() {} + bool emit(const uniq_vector_t &types); FORBID_COPY (HeaderFile); }; @@ -146,8 +136,8 @@ struct Output std::set skeletons; size_t max_fill; - Output(const std::string &source_name, const std::string &header_name); - ~Output (); + Output(); + bool emit(); }; void output_tags(std::ostream &o, const ConfTags &conf, diff --git a/re2c/src/conf/opt.cc b/re2c/src/conf/opt.cc index 946d3497..ed8e6246 100644 --- a/re2c/src/conf/opt.cc +++ b/re2c/src/conf/opt.cc @@ -292,20 +292,6 @@ bool Opt::source (const char *s) } } -bool Opt::output (const std::string &s) -{ - if (!output_file.empty()) - { - error ("multiple output files: %s, %s", output_file.c_str(), s.c_str()); - return false; - } - else - { - output_file = s; - return true; - } -} - void Opt::reset_encoding (const Enc & enc) { useropt->encoding = enc; diff --git a/re2c/src/conf/opt.h b/re2c/src/conf/opt.h index 66780835..b4518b01 100644 --- a/re2c/src/conf/opt.h +++ b/re2c/src/conf/opt.h @@ -17,6 +17,8 @@ namespace re2c #define RE2C_OPTS \ /* target */ \ OPT1 (opt_t::target_t, target, CODE) \ + /* output file */ \ + OPT (std::string, output_file, "") \ /* fingerprint */ \ OPT (bool, bNoGenerationDate, false) \ OPT (bool, version, true) \ @@ -28,7 +30,7 @@ namespace re2c /* conditions */ \ OPT (bool, cFlag, false) \ OPT (bool, tFlag, false) \ - OPT (std::string, header_file, "") \ + OPT (std::string, header_file, "") \ OPT (std::string, yycondtype, "YYCONDTYPE") \ OPT (std::string, cond_get, "YYGETCONDITION") \ OPT (bool, cond_get_naked, false) \ @@ -157,7 +159,6 @@ struct Opt static const opt_t baseopt; const char *source_file; - std::string output_file; private: useropt_t useropt; @@ -166,7 +167,6 @@ private: public: Opt () : source_file (NULL) - , output_file () , useropt () , realopt (useropt) {} @@ -178,7 +178,6 @@ public: } bool source (const char *s); - bool output (const std::string &s); // Inplace configurations are applied immediately when parsed. // This is very bad: first, re2c behaviour is changed in the middle diff --git a/re2c/src/conf/parse_opts.re b/re2c/src/conf/parse_opts.re index ebc6f214..a8b2536e 100644 --- a/re2c/src/conf/parse_opts.re +++ b/re2c/src/conf/parse_opts.re @@ -170,7 +170,7 @@ opt_output: error ("bad argument to option -o, --output: %s", *argv); return EXIT_FAIL; } - filename end { if (!opts.output (*argv)) return EXIT_FAIL; goto opt; } + filename end { opts.set_output_file(*argv); goto opt; } */ opt_header: diff --git a/re2c/src/ir/skeleton/generate_code.cc b/re2c/src/ir/skeleton/generate_code.cc index b956b61b..3e4d87d6 100644 --- a/re2c/src/ir/skeleton/generate_code.cc +++ b/re2c/src/ir/skeleton/generate_code.cc @@ -101,6 +101,10 @@ void emit_start(const Skeleton &skel, OutputFile &o, size_t maxfill, sizeof_key = skel.sizeof_key; const size_t norule = skel.rule2key(Rule::NONE); const std::string &name = skel.name; + std::string filename = opts->output_file; + if (filename.empty()) { + filename = ""; + } o.ws("\n#define YYCTYPE "); exact_uint (o, sizeof_cunit); @@ -181,7 +185,7 @@ void emit_start(const Skeleton &skel, OutputFile &o, size_t maxfill, o.ws("\n").wind(1).ws("unsigned int i = 0;"); o.ws("\n"); o.ws("\n").wind(1).ws("input = (YYCTYPE *) read_file"); - o.ws("\n").wind(2).ws("(\"").wstring(o.file_name).ws(".").wstring(name).ws(".input\""); + o.ws("\n").wind(2).ws("(\"").wstring(filename).ws(".").wstring(name).ws(".input\""); o.ws("\n").wind(2).ws(", sizeof (YYCTYPE)"); o.ws("\n").wind(2).ws(", padding"); o.ws("\n").wind(2).ws(", &input_len"); @@ -198,7 +202,7 @@ void emit_start(const Skeleton &skel, OutputFile &o, size_t maxfill, o.ws("\n"); } o.ws("\n").wind(1).ws("keys = (YYKEYTYPE *) read_file"); - o.ws("\n").wind(2).ws("(\"").wstring(o.file_name).ws(".").wstring(name).ws(".keys\""); + o.ws("\n").wind(2).ws("(\"").wstring(filename).ws(".").wstring(name).ws(".keys\""); o.ws("\n").wind(2).ws(", 3 * sizeof (YYKEYTYPE)"); o.ws("\n").wind(2).ws(", 0"); o.ws("\n").wind(2).ws(", &keys_count"); diff --git a/re2c/src/ir/skeleton/generate_data.cc b/re2c/src/ir/skeleton/generate_data.cc index b73f34d8..b417b0e6 100644 --- a/re2c/src/ir/skeleton/generate_data.cc +++ b/re2c/src/ir/skeleton/generate_data.cc @@ -228,8 +228,13 @@ static void generate_paths(const Skeleton &skel, cover_t &cover) } } -void emit_data(const Skeleton &skel, const std::string &fname) +void emit_data(const Skeleton &skel) { + std::string fname = opts->output_file; + if (fname.empty()) { + fname = ""; + } + const std::string input_name = fname + "." + skel.name + ".input"; FILE *input = fopen(input_name.c_str(), "wb"); if (!input) { diff --git a/re2c/src/ir/skeleton/skeleton.h b/re2c/src/ir/skeleton/skeleton.h index ab51c282..1161011f 100644 --- a/re2c/src/ir/skeleton/skeleton.h +++ b/re2c/src/ir/skeleton/skeleton.h @@ -87,7 +87,7 @@ uint32_t maxpath(const Skeleton &skel); void warn_undefined_control_flow(const Skeleton &skel); void fprint_default_path(FILE *f, const Skeleton &skel, const path_t &p); void warn_unreachable_nullable_rules(const Skeleton &skel); -void emit_data(const Skeleton &skel, const std::string &fname); +void emit_data(const Skeleton &skel); void emit_prolog(OutputFile & o); void emit_start(const Skeleton &skel, OutputFile &o, size_t maxfill, bool backup, bool backupctx, bool accept, bool basetag, diff --git a/re2c/src/main.cc b/re2c/src/main.cc index 6d1288b4..d69e708a 100644 --- a/re2c/src/main.cc +++ b/re2c/src/main.cc @@ -41,20 +41,13 @@ int main(int, char *argv[]) } // set up the output streams - re2c::Output output (opts.output_file, opts->header_file); - if (!output.source.open ()) - { - error ("cannot open output file: %s", opts.output_file.c_str()); - return 1; - } - if (opts->tFlag && !output.header.open ()) - { - error ("cannot open header file: %s", opts->header_file.c_str()); - return 1; - } + re2c::Output output; Scanner scanner (input, output.source); parse (scanner, output); + if (!output.emit()) { + return 1; + } return warn.error () ? 1 : 0; } diff --git a/re2c/src/parse/lex_conf.re b/re2c/src/parse/lex_conf.re index 093e3e3a..cffd556c 100644 --- a/re2c/src/parse/lex_conf.re +++ b/re2c/src/parse/lex_conf.re @@ -65,7 +65,7 @@ void Scanner::lex_conf () "flags:" ("x" | "utf-16") { lex_conf_enc(Enc::UTF16); return; } "flags:" ("8" | "utf-8") { lex_conf_enc(Enc::UTF8); return; } - "flags:" ("o" | "output") { if (!opts.output(lex_conf_string())) exit(1); return; } + "flags:" ("o" | "output") { opts.set_output_file(lex_conf_string()); return; } "flags:" ("t" | "type-header") { opts.set_header_file(lex_conf_string()); return; } "flags:encoding-policy" { lex_conf_encoding_policy(); return; } diff --git a/re2c/test/config/flags.c b/re2c/test/config/flags.c index b0d0e9d5..c7248d92 100644 --- a/re2c/test/config/flags.c +++ b/re2c/test/config/flags.c @@ -1,5 +1,5 @@ /* Generated by re2c */ -#line 1 "flags.re" +#line 1 "config/flags.re" int main() { diff --git a/re2c/test/config/flags.re b/re2c/test/config/flags.re index 67aec08a..b8fdc5d0 100644 --- a/re2c/test/config/flags.re +++ b/re2c/test/config/flags.re @@ -40,6 +40,11 @@ re2c:flags:8 = 1; re2c:flags:utf-8 = 0; + re2c:flags:o = "flags_x.c"; + re2c:flags:output = "flags.c"; + re2c:flags:t = "flags_x.h"; + re2c:flags:type-header = "flags.h"; + re2c:flags:encoding-policy = ignore; re2c:flags:encoding-policy = substitute; re2c:flags:encoding-policy = fail; diff --git a/re2c/test/config/flags_output.c b/re2c/test/config/flags_output.c new file mode 100644 index 00000000..14a7c3c0 --- /dev/null +++ b/re2c/test/config/flags_output.c @@ -0,0 +1,4 @@ +/* Generated by re2c */ +#line 1 "config/flags_output.re" +#line 5 "config/flags_output.re" + diff --git a/re2c/test/config/flags_output.re b/re2c/test/config/flags_output.re new file mode 100644 index 00000000..1e8f2c75 --- /dev/null +++ b/re2c/test/config/flags_output.re @@ -0,0 +1,5 @@ +/*!re2c + // 2nd configuration overrides 1st + re2c:flags:o = "flags_output_x.c"; + re2c:flags:output = "flags_output.c"; +*/ diff --git a/re2c/test/config/flags_type-header.c b/re2c/test/config/flags_type-header.c new file mode 100644 index 00000000..6e4b9b24 --- /dev/null +++ b/re2c/test/config/flags_type-header.c @@ -0,0 +1,9 @@ +/* Generated by re2c */ +#line 1 "config/flags_type-header.re" +#line 6 "config/flags_type-header.re" + +/* Generated by re2c */ +#line 3 "flags_type-header.h" + +enum YYCONDTYPE { +}; diff --git a/re2c/test/config/flags_type-header.re b/re2c/test/config/flags_type-header.re new file mode 100644 index 00000000..a0956e8f --- /dev/null +++ b/re2c/test/config/flags_type-header.re @@ -0,0 +1,6 @@ +/*!re2c + // 2nd configuration overrides 1st + re2c:flags:t = "flags_type-header_x.h"; + re2c:flags:type-header = "flags_type-header.h"; + re2c:flags:c = 1; +*/