From: Ulya Trofimovich Date: Wed, 25 Feb 2015 23:13:55 +0000 (+0000) Subject: One pass. X-Git-Tag: 0.15~382 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=57c14cfbe94f71b1c70b56fd4cf1df38f126f04d;p=re2c One pass. Second pass was used because some information (which influences early parts of the generated code, e.g enum with condition names or YYMAXFILL definition) becomes available only at the end of first pass. I isolate all (I hope so) these things and generate stubs for them, which are filled later. I restructured output as follows: the whole output consists of source and header, each of them is a list of blocks (corresponding to re2c blocks in source file), each block is a list of code fragments (which can be either regular strings with code or stubs that will be filled later). --- diff --git a/re2c/Makefile.am b/re2c/Makefile.am index 1e7f8cf2..d6990400 100755 --- a/re2c/Makefile.am +++ b/re2c/Makefile.am @@ -3,11 +3,11 @@ bin_PROGRAMS = re2c win_BINARIES = $(WINBUILDDIR)/re2c.exe re2c_SOURCES = code.cc dfa.cc main.cc parser.cc actions.cc scanner.re substr.cc range.cc \ - translate.cc scanner.cc mbo_getopt.cc print.cc input_api.cc \ + translate.cc scanner.cc mbo_getopt.cc print.cc input_api.cc output.cc \ enc.cc utf8.cc utf8_range.cc utf8_regexp.cc utf16.cc utf16_range.cc utf16_regexp.cc range_suffix.cc \ basics.h code.h code_names.h dfa.h enc.h indent.h input_api.h free_list.h globals.h ins.h \ mbo_getopt.h parser.h print.h range.h range_suffix.h re.h \ - scanner.h smart_ptr.h substr.h stream_lc.h token.h \ + scanner.h smart_ptr.h substr.h stream_lc.h token.h output.h \ utf16.h utf16_range.h utf16_regexp.h utf8.h utf8_range.h utf8_regexp.h BUILT_SOURCES = parser.cc scanner.cc @@ -101,7 +101,6 @@ $(DOCS): re2c.ad a2x -f manpage re2c.ad mkdir -p htdocs asciidoc -o htdocs/manual.html re2c.ad - cp re2c.1 $(top_srcdir)/bootstrap/re2c.1 else docs: $(DOCS) $(DOCS): $(top_srcdir)/bootstrap/re2c.1 diff --git a/re2c/bootstrap/parser.cc b/re2c/bootstrap/parser.cc index 051e3ae8..2a7be601 100644 --- a/re2c/bootstrap/parser.cc +++ b/re2c/bootstrap/parser.cc @@ -184,16 +184,13 @@ void setup_rule(CondList *clist, Token *code) assert(clist); assert(code); context_check(clist); - if (bFirstPass) + for(CondList::const_iterator it = clist->begin(); it != clist->end(); ++it) { - for(CondList::const_iterator it = clist->begin(); it != clist->end(); ++it) + if (ruleSetupMap.find(*it) != ruleSetupMap.end()) { - if (ruleSetupMap.find(*it) != ruleSetupMap.end()) - { - in->fatalf_at(code->line, "code to setup rule '%s' is already defined", it->c_str()); - } - ruleSetupMap[*it] = std::make_pair(code->line, code->text.to_string()); + in->fatalf_at(code->line, "code to setup rule '%s' is already defined", it->c_str()); } + ruleSetupMap[*it] = std::make_pair(code->line, code->text.to_string()); } delete clist; delete code; @@ -204,16 +201,13 @@ void default_rule(CondList *clist, Token *code) assert(clist); assert(code); context_check(clist); - if (bFirstPass) + for(CondList::const_iterator it = clist->begin(); it != clist->end(); ++it) { - for(CondList::const_iterator it = clist->begin(); it != clist->end(); ++it) + if (ruleDefaultMap.find(*it) != ruleDefaultMap.end()) { - if (ruleDefaultMap.find(*it) != ruleDefaultMap.end()) - { - in->fatalf_at(code->line, "code to default rule '%s' is already defined", it->c_str()); - } - ruleDefaultMap[*it] = code; + in->fatalf_at(code->line, "code to default rule '%s' is already defined", it->c_str()); } + ruleDefaultMap[*it] = code; } delete clist; } @@ -611,12 +605,12 @@ static const yytype_int8 yyrhs[] = /* YYRLINE[YYN] -- source line where rule number YYN was defined. */ static const yytype_uint16 yyrline[] = { - 0, 186, 186, 188, 192, 196, 205, 214, 218, 222, - 228, 236, 245, 254, 258, 263, 268, 274, 278, 286, - 294, 299, 305, 311, 323, 335, 341, 349, 352, 359, - 364, 373, 376, 384, 387, 394, 398, 405, 409, 420, - 424, 431, 435, 450, 457, 461, 465, 469, 476, 484, - 488, 492 + 0, 180, 180, 182, 186, 190, 199, 208, 212, 216, + 222, 230, 239, 248, 252, 257, 262, 268, 272, 280, + 288, 293, 299, 305, 317, 329, 335, 343, 346, 353, + 358, 367, 370, 378, 381, 388, 392, 399, 403, 414, + 418, 425, 429, 444, 451, 455, 459, 463, 470, 478, + 482, 486 }; #endif @@ -2231,27 +2225,22 @@ int yylex(){ namespace re2c { -void parse(Scanner& i, std::ostream& o, std::ostream* h) +void parse(Scanner& i, Output & o) { std::map > dfa_map; ScannerState rules_state; in = &i; - o << "/* Generated by re2c " PACKAGE_VERSION; - if (!bNoGenerationDate) - { - o << " on "; - time_t now = time(&now); - o.write(ctime(&now), 24); - } - o << " */\n"; - o << sourceFileInfo; - + output_version_time (o.source); + o.source << sourceFileInfo; + output_version_time (o.header); + Enc encodingOld = encoding; while ((parseMode = i.echo()) != Scanner::Stop) { + o.source.new_block (); bool bPrologBrace = false; ScannerState curr_state; @@ -2388,16 +2377,20 @@ void parse(Scanner& i, std::ostream& o, std::ostream* h) } } dfa_map[it->first] = genCode(it->second.second); - dfa_map[it->first]->prepare(); + dfa_map[it->first]->prepare(o.max_fill); } if (parseMode != Scanner::Rules && dfa_map.find(it->first) != dfa_map.end()) { dfa_map[it->first]->emit(o, topIndent, &specMap, it->first, !--nCount, bPrologBrace); } } - if (!h && !bTypesDone) + + genTypes (o, specMap); + if (o.header.status != OutputFile::NO_FILE) { - genTypes(typesInline, 0, specMap); + o.header.insert_line_info (); + o.header << "\n"; + o.header.insert_types (); } } else @@ -2412,7 +2405,7 @@ void parse(Scanner& i, std::ostream& o, std::ostream* h) if (parseMode != Scanner::Reuse) { dfa_map[""] = genCode(spec); - dfa_map[""]->prepare(); + dfa_map[""]->prepare(o.max_fill); } if (parseMode != Scanner::Rules && dfa_map.find("") != dfa_map.end()) { @@ -2420,7 +2413,7 @@ void parse(Scanner& i, std::ostream& o, std::ostream* h) } } } - o << sourceFileInfo; + o.source << sourceFileInfo; /* restore original char handling mode*/ encoding = encodingOld; } @@ -2447,11 +2440,6 @@ void parse(Scanner& i, std::ostream& o, std::ostream* h) } } - if (h) - { - genHeader(*h, 0, specMap); - } - parse_cleanup(); in = NULL; } diff --git a/re2c/bootstrap/scanner.cc b/re2c/bootstrap/scanner.cc index 85b9278d..47205749 100644 --- a/re2c/bootstrap/scanner.cc +++ b/re2c/bootstrap/scanner.cc @@ -1,5 +1,4 @@ -/* Generated by re2c 0.13.7.dev on Thu Apr 10 00:33:47 2014 */ -/* $Id$ */ +/* Generated by re2c 0.14.1.dev on Tue Feb 24 15:15:39 2015 */ #include #include #include @@ -233,10 +232,6 @@ yy21: { fatal("found 'rules:re2c' block without -r flag"); } - if (bUsedYYMaxFill && bSinglePass) - { - fatal("found scanner block after YYMAXFILL declaration"); - } tok = cursor; RETURN(Rules); } @@ -250,10 +245,6 @@ yy32: { fatal("found standard 're2c' block while using -r flag"); } - if (bUsedYYMaxFill && bSinglePass) - { - fatal("found scanner block after YYMAXFILL declaration"); - } if (!DFlag) { out.write((const char*)(tok), (const char*)(&cursor[-7]) - (const char*)(tok)); @@ -281,10 +272,6 @@ yy34: fatal("found 'use:re2c' block without -r flag"); } reuse(); - if (bUsedYYMaxFill && bSinglePass) - { - fatal("found scanner block after YYMAXFILL declaration"); - } if (!DFlag) { out.write((const char*)(tok), (const char*)(&cursor[-11]) - (const char*)(tok)); @@ -307,17 +294,12 @@ yy42: if (yych != 'c') goto yy12; ++YYCURSOR; { - if (bUsedYYMaxFill) - { - fatal("cannot generate YYMAXFILL twice"); - } if (!DFlag) { - out << "#define YYMAXFILL " << maxFill << std::endl; + out.insert_yymaxfill (); } tok = pos = cursor; ignore_eoc = true; - bUsedYYMaxFill = true; goto echo; } yy50: @@ -346,7 +328,7 @@ yy50: ++YYCURSOR; { tok = pos = cursor; - genGetStateGoto(out, topIndent, 0); + out.insert_state_goto (topIndent, 0); ignore_eoc = true; goto echo; } @@ -394,17 +376,13 @@ yy74: if (yych != 'c') goto yy12; ++YYCURSOR; { - if (bSinglePass) - { - fatal("cannot generate types inline in single pass mode"); - } tok = pos = cursor; ignore_eoc = true; - if (bLastPass && !DFlag) + if (!DFlag) { - out << outputFileInfo; + out.insert_line_info (); out << "\n"; - out << typesInline; + out.insert_types (); out << "\n"; out << sourceFileInfo; } diff --git a/re2c/code.cc b/re2c/code.cc index bc05fd6d..b398a8b5 100644 --- a/re2c/code.cc +++ b/re2c/code.cc @@ -2,11 +2,12 @@ #include #include #include +#include #include #include #include #include -#include + #include "code.h" #include "globals.h" #include "dfa.h" @@ -39,7 +40,7 @@ std::string replaceParam(std::string str, const std::string& param, const _Ty& v return str; } -static void genYYFill(std::ostream &o, uint, uint need) +static void genYYFill(OutputFile & o, uint, uint need) { if (bUseYYFillParam) { @@ -85,7 +86,7 @@ static std::string genGetCondition() } } -static void genSetCondition(std::ostream& o, uint ind, const std::string& newcond) +static void genSetCondition(OutputFile & o, uint ind, const std::string& newcond) { if (bUseYYSetConditionParam) { @@ -171,22 +172,6 @@ static void doGen(const Go *g, const State *s, uint *bm, uint f, uint m) } } -static void prt(std::ostream& o, const Go *g, const State *s) -{ - Span *b = g->span, *e = &b[g->nSpans]; - uint lb = 0; - - for (; b < e; ++b) - { - if (b->to == s) - { - printSpan(o, lb, b->ub); - } - - lb = b->ub; - } -} - static bool matches(const Go *g1, const State *s1, const Go *g2, const State *s2) { Span *b1 = g1->span, *e1 = &b1[g1->nSpans]; @@ -269,9 +254,9 @@ const BitMap *BitMap::find(const State *x) return NULL; } -void BitMap::gen(std::ostream &o, uint ind, uint lb, uint ub) +void BitMap::gen(OutputFile & o, uint ind, uint lb, uint ub) { - if (first && bLastPass && bUsedYYBitmap) + if (first && bUsedYYBitmap) { o << indent(ind) << "static const unsigned char " << mapCodeName["yybm"] << "[] = {"; @@ -311,39 +296,23 @@ void BitMap::gen(std::ostream &o, uint ind, uint lb, uint ub) if (yybmHexTable) { - prtHex(o, bm[j]); + prtHex(o.fragment (), bm[j]); } else { - o << std::setw(3) << (uint)bm[j]; + o << Setw (3) << (uint)bm[j]; } o << ", "; } } o << "\n" << indent(ind) << "};\n"; - /* stats(); */ delete[] bm; } } -void BitMap::stats() -{ - uint n = 0; - - for (const BitMap *b = first; b; b = b->next) - { - prt(std::cerr, b->go, b->on); - std::cerr << std::endl; - ++n; - } - - std::cerr << n << " bitmaps\n"; - first = NULL; -} - -static void genGoTo(std::ostream &o, uint ind, const State *from, const State *to, bool & readCh) +static void genGoTo(OutputFile & o, uint ind, const State *from, const State *to, bool & readCh) { if (DFlag) { @@ -361,7 +330,7 @@ static void genGoTo(std::ostream &o, uint ind, const State *from, const State *t vUsedLabels.insert(to->label); } -static void genIf(std::ostream &o, uint ind, const char *cmp, uint v, bool &readCh) +static void genIf(OutputFile & o, uint ind, const char *cmp, uint v, bool &readCh) { o << indent(ind) << "if ("; if (readCh) @@ -375,11 +344,11 @@ static void genIf(std::ostream &o, uint ind, const char *cmp, uint v, bool &read } o << " " << cmp << " "; - prtChOrHex(o, v); + prtChOrHex(o.fragment (), v); o << ") "; } -static void need(std::ostream &o, uint ind, uint n, bool & readCh, bool bSetMarker) +static void need(OutputFile & o, uint ind, uint n, bool & readCh, bool bSetMarker) { if (DFlag) { @@ -441,8 +410,10 @@ static void need(std::ostream &o, uint ind, uint n, bool & readCh, bool bSetMark } } -void Match::emit(std::ostream &o, uint ind, bool &readCh, const std::string&) const +void Match::emit(Output & output, uint ind, bool &readCh, const std::string&) const { + OutputFile & o = output.source; + if (DFlag) { return; @@ -470,8 +441,10 @@ void Match::emit(std::ostream &o, uint ind, bool &readCh, const std::string&) co } } -void Enter::emit(std::ostream &o, uint ind, bool &readCh, const std::string&) const +void Enter::emit(Output & output, uint ind, bool &readCh, const std::string&) const { + OutputFile & o = output.source; + if (state->link) { o << input_api.stmt_skip (ind); @@ -493,8 +466,10 @@ void Enter::emit(std::ostream &o, uint ind, bool &readCh, const std::string&) co } } -void Initial::emit(std::ostream &o, uint ind, bool &readCh, const std::string&) const +void Initial::emit(Output & output, uint ind, bool &readCh, const std::string&) const { + OutputFile & o = output.source; + if (!cFlag && !startLabelName.empty()) { o << startLabelName << ":\n"; @@ -523,7 +498,7 @@ void Initial::emit(std::ostream &o, uint ind, bool &readCh, const std::string&) if (dFlag) { - o << indent(ind) << mapCodeName["YYDEBUG"] << "(" << label << ", " << input_api.expr_peek () << ");\n"; + o << indent(ind) << mapCodeName["YYDEBUG"] << "(" << label << ", *" << mapCodeName["YYCURSOR"] << ");" << "\n"; } if (state->link) @@ -540,17 +515,16 @@ void Initial::emit(std::ostream &o, uint ind, bool &readCh, const std::string&) } } -void Save::emit(std::ostream &o, uint ind, bool &readCh, const std::string&) const +void Save::emit(Output & output, uint ind, bool &readCh, const std::string&) const { + OutputFile & o = output.source; + if (DFlag) { return; } - if (bUsedYYAccept) - { - o << indent(ind) << mapCodeName["yyaccept"] << " = " << selector << ";\n"; - } + o.insert_yyaccept_selector (ind, selector); if (state->link) { @@ -579,7 +553,7 @@ Move::Move(State *s) : Action(s) ; } -void Move::emit(std::ostream &, uint, bool &, const std::string&) const +void Move::emit(Output &, uint, bool &, const std::string&) const { ; } @@ -601,13 +575,12 @@ void Accept::genRuleMap() } } -void Accept::emitBinary(std::ostream &o, uint ind, uint l, uint r, bool &readCh) const +void Accept::emitBinary(OutputFile & o, uint ind, uint l, uint r, bool &readCh) const { if (l < r) { uint m = (l + r) >> 1; - assert(bUsedYYAccept); o << indent(ind) << "if (" << mapCodeName["yyaccept"] << (r == l+1 ? " == " : " <= ") << m << ") {\n"; emitBinary(o, ++ind, l, m, readCh); o << indent(--ind) << "} else {\n"; @@ -620,8 +593,10 @@ void Accept::emitBinary(std::ostream &o, uint ind, uint l, uint r, bool &readCh) } } -void Accept::emit(std::ostream &o, uint ind, bool &readCh, const std::string&) const +void Accept::emit(Output & output, uint ind, bool &readCh, const std::string &) const { + OutputFile & o = output.source; + if (mapRules.size() > 0) { bUsedYYMarker = true; @@ -638,7 +613,7 @@ void Accept::emit(std::ostream &o, uint ind, bool &readCh, const std::string&) c if (mapRules.size() > 1) { - bUsedYYAccept = true; + o.set_used_yyaccept (); if (gFlag && mapRules.size() >= cGotoThreshold) { @@ -703,8 +678,10 @@ Rule::Rule(State *s, RuleOp *r) : Action(s), rule(r) ; } -void Rule::emit(std::ostream &o, uint ind, bool &, const std::string& condName) const +void Rule::emit(Output & output, uint ind, bool &, const std::string& condName) const { + OutputFile & o = output.source; + if (DFlag) { o << state->label << " [label=\"" << sourceFileInfo.fname << ":" << rule->code->line << "\"]\n"; @@ -741,10 +718,10 @@ void Rule::emit(std::ostream &o, uint ind, bool &, const std::string& condName) o << rule->code->text; } o << "\n"; - o << outputFileInfo; + o.insert_line_info (); } -static void doLinear(std::ostream &o, uint ind, Span *s, uint n, const State *from, const State *next, bool &readCh, uint mask) +static void doLinear(OutputFile & o, uint ind, Span *s, uint n, const State *from, const State *next, bool &readCh, uint mask) { for (;;) { @@ -819,12 +796,12 @@ static void doLinear(std::ostream &o, uint ind, Span *s, uint n, const State *fr } } -void Go::genLinear(std::ostream &o, uint ind, const State *from, const State *next, bool &readCh, uint mask) const +void Go::genLinear(OutputFile & o, uint ind, const State *from, const State *next, bool &readCh, uint mask) const { doLinear(o, ind, span, nSpans, from, next, readCh, mask); } -static void printDotCharInterval(std::ostream &o, uint lastPrintableChar, uint chr, const State *from, const State *to, bool multipleIntervals) +static void printDotCharInterval(OutputFile & o, uint lastPrintableChar, uint chr, const State *from, const State *to, bool multipleIntervals) { o << from->label << " -> " << to->label; o << " [label="; @@ -843,23 +820,23 @@ static void printDotCharInterval(std::ostream &o, uint lastPrintableChar, uint c o << "]\n"; o << from->label << " -> " << to->label; o << " [label="; - prtChOrHex(o, ++chr); + prtChOrHex(o.fragment (), ++chr); } } else { - prtChOrHex(o, chr); + prtChOrHex(o.fragment (), chr); } } else { - prtChOrHex(o, chr); + prtChOrHex(o.fragment (), chr); } o << "]"; } -static bool genCases(std::ostream &o, uint ind, uint lb, Span *s, bool &newLine, uint mask, const State *from, const State *to) +static bool genCases(OutputFile & o, uint ind, uint lb, Span *s, bool &newLine, uint mask, const State *from, const State *to) { bool used = false; uint lastPrintableChar = 0; @@ -897,7 +874,7 @@ static bool genCases(std::ostream &o, uint ind, uint lb, Span *s, bool &newLine, else { o << indent(ind) << "case "; - prtChOrHex(o, lb); + prtChOrHex(o.fragment (), lb); o << ":"; if (dFlag && encoding.is(Enc::EBCDIC)) { @@ -931,7 +908,7 @@ static bool genCases(std::ostream &o, uint ind, uint lb, Span *s, bool &newLine, return used; } -void Go::genSwitch(std::ostream &o, uint ind, const State *from, const State *next, bool &readCh, uint mask) const +void Go::genSwitch(OutputFile & o, uint ind, const State *from, const State *next, bool &readCh, uint mask) const { bool newLine = true; @@ -1031,7 +1008,7 @@ void Go::genSwitch(std::ostream &o, uint ind, const State *from, const State *ne } } -static void doBinary(std::ostream &o, uint ind, Span *s, uint n, const State *from, const State *next, bool &readCh, uint mask) +static void doBinary(OutputFile & o, uint ind, Span *s, uint n, const State *from, const State *next, bool &readCh, uint mask) { if (n <= 4) { @@ -1050,7 +1027,7 @@ static void doBinary(std::ostream &o, uint ind, Span *s, uint n, const State *fr } } -void Go::genBinary(std::ostream &o, uint ind, const State *from, const State *next, bool &readCh, uint mask) const +void Go::genBinary(OutputFile & o, uint ind, const State *from, const State *next, bool &readCh, uint mask) const { if (mask) { @@ -1074,7 +1051,7 @@ void Go::genBinary(std::ostream &o, uint ind, const State *from, const State *ne } } -void Go::genBase(std::ostream &o, uint ind, const State *from, const State *next, bool &readCh, uint mask) const +void Go::genBase(OutputFile & o, uint ind, const State *from, const State *next, bool &readCh, uint mask) const { if ((mask ? wSpans : nSpans) == 0) { @@ -1125,7 +1102,7 @@ void Go::genBase(std::ostream &o, uint ind, const State *from, const State *next } } -void Go::genCpGoto(std::ostream &o, uint ind, const State *from, const State *next, bool &readCh) const +void Go::genCpGoto(OutputFile & o, uint ind, const State *from, const State *next, bool &readCh) const { std::string sYych; @@ -1181,7 +1158,7 @@ void Go::genCpGoto(std::ostream &o, uint ind, const State *from, const State *ne o << indent(--ind) << "}\n"; } -void Go::genGoto(std::ostream &o, uint ind, const State *from, const State *next, bool &readCh) +void Go::genGoto(OutputFile & o, uint ind, const State *from, const State *next, bool &readCh) { if ((gFlag || (encoding.szCodeUnit() > 1)) && wSpans == ~0u) { @@ -1271,7 +1248,7 @@ void Go::genGoto(std::ostream &o, uint ind, const State *from, const State *next o << "if (" << mapCodeName["yybm"] << "[" << b->i << "+" << sYych << "] & "; if (yybmHexTable) { - prtHex(o, b->m); + prtHex(o.fragment (), b->m); } else { @@ -1291,8 +1268,10 @@ void Go::genGoto(std::ostream &o, uint ind, const State *from, const State *next genBase(o, ind, from, next, readCh, 0); } -void State::emit(std::ostream &o, uint ind, bool &readCh, const std::string& condName) const +void State::emit(Output & output, uint ind, bool &readCh, const std::string& condName) const { + OutputFile & o = output.source; + if (vUsedLabels.count(label)) { o << labelPrefix << label << ":\n"; @@ -1305,7 +1284,7 @@ void State::emit(std::ostream &o, uint ind, bool &readCh, const std::string& con { o << input_api.stmt_backupctx (ind); } - action->emit(o, ind, readCh, condName); + action->emit(output, ind, readCh, condName); } static uint merge(Span *x0, State *fg, State *bg) @@ -1619,7 +1598,7 @@ void DFA::findBaseState() delete [] span; } -void DFA::prepare() +void DFA::prepare(uint & max_fill) { State *s; uint i; @@ -1634,9 +1613,9 @@ void DFA::prepare() for (s = head; s; s = s->next) { s->depth = maxDist(s); - if (maxFill < s->depth) + if (max_fill < s->depth) { - maxFill = s->depth; + max_fill = s->depth; } if (s->rule && s->rule->accept >= nRules) { @@ -1758,15 +1737,11 @@ void DFA::prepare() } -void DFA::emit(std::ostream &o, uint& ind, const RegExpMap* specMap, const std::string& condName, bool isLastCond, bool& bPrologBrace) +void DFA::emit(Output & output, uint& ind, const RegExpMap* specMap, const std::string& condName, bool isLastCond, bool& bPrologBrace) { + OutputFile & o = output.source; bool bProlog = (!cFlag || !bWroteCondCheck); - if (!cFlag) - { - bUsedYYAccept = false; - } - // In -c mode, the prolog needs its own label separate from start_label. // prolog_label is before the condition branch (GenCondGoto). It is // equivalent to startLabelName. @@ -1801,13 +1776,13 @@ void DFA::emit(std::ostream &o, uint& ind, const RegExpMap* specMap, const std:: // Save 'next_fill_index' and compute information about code generation // while writing to null device. uint save_fill_index = next_fill_index; - null_stream null_dev; + Output null_dev (NULL, NULL); for (s = head; s; s = s->next) { bool readCh = false; s->emit(null_dev, ind, readCh, condName); - s->go.genGoto(null_dev, ind, s, s->next, readCh); + s->go.genGoto(null_dev.source, ind, s, s->next, readCh); } if (last_fill_index < next_fill_index) { @@ -1818,14 +1793,15 @@ void DFA::emit(std::ostream &o, uint& ind, const RegExpMap* specMap, const std:: // Generate prolog if (bProlog) { - o << "\n" << outputFileInfo; + o << "\n"; + o.insert_line_info (); if (DFlag) { bPrologBrace = true; o << "digraph re2c {\n"; } - else if ((!fFlag && bUsedYYAccept) + else if ((!fFlag && o.get_used_yyaccept ()) || (!fFlag && bEmitYYCh) || (bFlag && !cFlag && BitMap::first) || (cFlag && !bWroteCondCheck && gFlag && !specMap->empty()) @@ -1846,10 +1822,7 @@ void DFA::emit(std::ostream &o, uint& ind, const RegExpMap* specMap, const std:: { o << indent(ind) << mapCodeName["YYCTYPE"] << " " << mapCodeName["yych"] << ";\n"; } - if (bUsedYYAccept) - { - o << indent(ind) << "unsigned int " << mapCodeName["yyaccept"] << " = 0;\n"; - } + o.insert_yyaccept_init (ind); } else { @@ -1863,7 +1836,7 @@ void DFA::emit(std::ostream &o, uint& ind, const RegExpMap* specMap, const std:: if (bProlog) { genCondTable(o, ind, *specMap); - genGetStateGoto(o, ind, prolog_label); + o.insert_state_goto (ind, prolog_label); if (cFlag && !DFlag) { if (vUsedLabels.count(prolog_label)) @@ -1911,7 +1884,7 @@ void DFA::emit(std::ostream &o, uint& ind, const RegExpMap* specMap, const std:: for (s = head; s; s = s->next) { bool readCh = false; - s->emit(o, ind, readCh, condName); + s->emit(output, ind, readCh, condName); s->go.genGoto(o, ind, s, s->next, readCh); } @@ -1935,7 +1908,7 @@ void DFA::emit(std::ostream &o, uint& ind, const RegExpMap* specMap, const std:: bUseStartLabel = false; } -static void genGetStateGotoSub(std::ostream &o, uint ind, uint start_label, int cMin, int cMax) +static void output_state_goto_sub (OutputFragment & o, uint ind, uint start_label, int cMin, int cMax) { if (cMin == cMax) { @@ -1953,86 +1926,83 @@ static void genGetStateGotoSub(std::ostream &o, uint ind, uint start_label, int int cMid = cMin + ((cMax - cMin + 1) / 2); o << indent(ind) << "if (" << genGetState() << " < " << cMid << ") {\n"; - genGetStateGotoSub(o, ind + 1, start_label, cMin, cMid - 1); + output_state_goto_sub (o, ind + 1, start_label, cMin, cMid - 1); o << indent(ind) << "} else {\n"; - genGetStateGotoSub(o, ind + 1, start_label, cMid, cMax); + output_state_goto_sub (o, ind + 1, start_label, cMid, cMax); o << indent(ind) << "}\n"; } } -void genGetStateGoto(std::ostream &o, uint& ind, uint start_label) +void output_state_goto (OutputFragment & o, uint start_label) { - if (fFlag && !bWroteGetState) + uint ind = o.indent; + if (gFlag) { - vUsedLabels.insert(start_label); - if (gFlag) + o << indent(ind++) << "static void *" << mapCodeName["yystable"] << "[" << "] = {\n"; + + for (size_t i=0; isecond.first >= 0); - vCondList[itSpecMap->second.first] = itSpecMap->first; + output.types[itSpecMap->second.first] = itSpecMap->first; } +} - for(RegExpIndices::const_iterator itCondType = vCondList.begin(); itCondType != vCondList.end(); ++itCondType) +void output_yyaccept_init (OutputFragment & o, bool used_yyaccept) +{ + if (used_yyaccept) { - o += indent(ind) + condEnumPrefix + *itCondType + ",\n"; + o << indent (o.indent) << "unsigned int " << mapCodeName["yyaccept"] << " = 0;\n"; } +} + +void output_yyaccept_selector (OutputFragment & o, bool used_yyaccept) +{ + if (used_yyaccept) + { + o << indent (o.indent) << mapCodeName["yyaccept"] << " = " << o.info.yyaccept_selector << ";\n"; + } +} - o += indent(--ind) + "};\n"; +void output_yymaxfill (OutputFragment & o, uint max_fill) +{ + o << "#define YYMAXFILL " << max_fill << "\n"; +} + +void output_line_info (OutputFragment & o, uint line_number, const char * filename) +{ + if (!iFlag) + { + o << "#line " << line_number << " \"" << filename << "\"\n"; + } +} + +void output_types (OutputFragment & o, const std::vector & types) +{ + uint ind = o.indent; + o << indent (ind++) << "enum " << mapCodeName["YYCONDTYPE"] << " {\n"; + for (unsigned int i = 0; i < types.size (); ++i) + { + o << indent (ind) << condEnumPrefix << types[i] << ",\n"; + } + o << indent (--ind) << "};\n"; } -void genHeader(std::ostream &o, uint ind, const RegExpMap& specMap) +void output_version_time (OutputFile & o) { o << "/* Generated by re2c " PACKAGE_VERSION; if (!bNoGenerationDate) { o << " on "; - time_t now = time(&now); - o.write(ctime(&now), 24); + time_t now = time (NULL); + o.write (ctime (&now), 24); } - o << " */\n"; - o << headerFileInfo; - o << "\n"; - // now the type(s) - genTypes(typesInline, ind, specMap); - o << typesInline; + o << "*/" << "\n"; } -std::ostream& operator << (std::ostream& o, const file_info& li) +OutputFragment & operator << (OutputFragment & o, const file_info& li) { if (li.ln && !iFlag) { @@ -2397,32 +2390,26 @@ void Scanner::config(const Str& cfg, const Str& val) bUseYYSetStateParam = false; } else if (mapVariableKeys.find(cfg.to_string()) != mapVariableKeys.end()) - { - if ((bFirstPass || rFlag) && !mapCodeName.insert( - std::make_pair(cfg.to_string().substr(sizeof("variable:") - 1), strVal) - ).second) - { + { + if (!mapCodeName.insert(std::make_pair(cfg.to_string().substr(sizeof("variable:") - 1), strVal)).second) + { fatalf("variable '%s' already being used and cannot be changed", cfg.to_string().c_str()); - } - } + } + } else if (mapDefineKeys.find(cfg.to_string()) != mapDefineKeys.end()) - { - if ((bFirstPass || rFlag) && !mapCodeName.insert( - std::make_pair(cfg.to_string().substr(sizeof("define:") - 1), strVal) - ).second) - { - fatalf("define '%s' already being used and cannot be changed", cfg.to_string().c_str()); - } - } + { + if (!mapCodeName.insert(std::make_pair(cfg.to_string().substr(sizeof("define:") - 1), strVal)).second) + { + fatalf("define '%s' already being used and cannot be changed", cfg.to_string().c_str()); + } + } else if (mapLabelKeys.find(cfg.to_string()) != mapLabelKeys.end()) - { - if ((bFirstPass || rFlag) && !mapCodeName.insert( - std::make_pair(cfg.to_string().substr(sizeof("label:") - 1), strVal) - ).second) - { + { + if (!mapCodeName.insert(std::make_pair(cfg.to_string().substr(sizeof("label:") - 1), strVal)).second) + { fatalf("label '%s' already being used and cannot be changed", cfg.to_string().c_str()); - } - } + } + } else { std::string msg = "unrecognized configuration name '"; @@ -2440,7 +2427,7 @@ ScannerState::ScannerState() { } -Scanner::Scanner(std::istream& i, std::ostream& o) +Scanner::Scanner(std::istream& i, OutputFile & o) : ScannerState(), in(i), out(o) { } @@ -2510,7 +2497,6 @@ void Scanner::set_in_parse(bool new_in_parse) void Scanner::fatal_at(uint line, uint ofs, const char *msg) const { - out.flush(); std::cerr << "re2c: error: " << "line " << line << ", column " << (tchar + ofs + 1) << ": " << msg << std::endl; diff --git a/re2c/code.h b/re2c/code.h index 12b735e5..1227fb22 100755 --- a/re2c/code.h +++ b/re2c/code.h @@ -22,8 +22,7 @@ public: public: static const BitMap *find(const Go*, const State*); static const BitMap *find(const State*); - static void gen(std::ostream&, uint ind, uint, uint); - static void stats(); + static void gen(OutputFile &, uint ind, uint, uint); BitMap(const Go*, const State*); ~BitMap(); diff --git a/re2c/dfa.h b/re2c/dfa.h index 66c391a4..0f4499bb 100644 --- a/re2c/dfa.h +++ b/re2c/dfa.h @@ -23,7 +23,7 @@ public: Action(State*); virtual ~Action(); - virtual void emit(std::ostream&, uint, bool&, const std::string&) const = 0; + virtual void emit(Output &, uint, bool&, const std::string&) const = 0; virtual bool isRule() const; virtual bool isMatch() const; virtual bool isInitial() const; @@ -47,7 +47,7 @@ class Match: public Action { public: Match(State*); - void emit(std::ostream&, uint, bool&, const std::string&) const; + void emit(Output &, uint, bool&, const std::string&) const; bool isMatch() const; }; @@ -58,7 +58,7 @@ public: public: Enter(State*, uint); - void emit(std::ostream&, uint, bool&, const std::string&) const; + void emit(Output &, uint, bool&, const std::string&) const; }; class Initial: public Enter @@ -68,7 +68,7 @@ public: public: Initial(State*, uint, bool); - void emit(std::ostream&, uint, bool&, const std::string&) const; + void emit(Output &, uint, bool&, const std::string&) const; bool isInitial() const; }; @@ -80,7 +80,7 @@ public: public: Save(State*, uint); - void emit(std::ostream&, uint, bool&, const std::string&) const; + void emit(Output &, uint, bool&, const std::string&) const; bool isMatch() const; }; @@ -89,7 +89,7 @@ class Move: public Action public: Move(State*); - void emit(std::ostream&, uint, bool&, const std::string&) const; + void emit(Output &, uint, bool&, const std::string&) const; }; class Accept: public Action @@ -105,8 +105,8 @@ public: public: Accept(State*, uint, uint*, State**); - void emit(std::ostream&, uint, bool&, const std::string&) const; - void emitBinary(std::ostream &o, uint ind, uint l, uint r, bool &readCh) const; + void emit(Output &, uint, bool&, const std::string&) const; + void emitBinary(OutputFile & o, uint ind, uint l, uint r, bool &readCh) const; void genRuleMap(); #ifdef PEDANTIC @@ -134,7 +134,7 @@ public: public: Rule(State*, RuleOp*); - void emit(std::ostream&, uint, bool&, const std::string&) const; + void emit(Output &, uint, bool&, const std::string&) const; bool isRule() const; #ifdef PEDANTIC @@ -185,12 +185,12 @@ public: Span *span; public: - void genGoto( std::ostream&, uint ind, const State *from, const State *next, bool &readCh); - void genBase( std::ostream&, uint ind, const State *from, const State *next, bool &readCh, uint mask) const; - void genLinear(std::ostream&, uint ind, const State *from, const State *next, bool &readCh, uint mask) const; - void genBinary(std::ostream&, uint ind, const State *from, const State *next, bool &readCh, uint mask) const; - void genSwitch(std::ostream&, uint ind, const State *from, const State *next, bool &readCh, uint mask) const; - void genCpGoto(std::ostream&, uint ind, const State *from, const State *next, bool &readCh) const; + void genGoto(OutputFile &, uint ind, const State *from, const State *next, bool &readCh); + void genBase(OutputFile &, uint ind, const State *from, const State *next, bool &readCh, uint mask) const; + void genLinear(OutputFile &, uint ind, const State *from, const State *next, bool &readCh, uint mask) const; + void genBinary(OutputFile &, uint ind, const State *from, const State *next, bool &readCh, uint mask) const; + void genSwitch(OutputFile &, uint ind, const State *from, const State *next, bool &readCh, uint mask) const; + void genCpGoto(OutputFile &, uint ind, const State *from, const State *next, bool &readCh) const; void compact(); void unmap(Go*, const State*); }; @@ -215,7 +215,7 @@ public: public: State(); ~State(); - void emit(std::ostream&, uint, bool&, const std::string&) const; + void emit(Output &, uint, bool&, const std::string&) const; friend std::ostream& operator<<(std::ostream&, const State&); friend std::ostream& operator<<(std::ostream&, const State*); @@ -268,8 +268,8 @@ public: void findSCCs(); void findBaseState(); - void prepare(); - void emit(std::ostream&, uint&, const RegExpMap*, const std::string&, bool, bool&); + void prepare(uint &); + void emit(Output &, uint&, const RegExpMap*, const std::string&, bool, bool&); friend std::ostream& operator<<(std::ostream&, const DFA&); friend std::ostream& operator<<(std::ostream&, const DFA*); diff --git a/re2c/globals.h b/re2c/globals.h index 5a78315c..92c86031 100644 --- a/re2c/globals.h +++ b/re2c/globals.h @@ -17,8 +17,6 @@ namespace re2c enum BUFFERSIZE { BSIZE = 8192}; extern file_info sourceFileInfo; -extern file_info outputFileInfo; -extern file_info headerFileInfo; extern bool bFlag; extern bool cFlag; @@ -33,13 +31,6 @@ extern bool sFlag; extern bool tFlag; extern bool bNoGenerationDate; - -extern bool bSinglePass; -extern bool bFirstPass; -extern bool bLastPass; - -extern bool bUsedYYAccept; -extern bool bUsedYYMaxFill; extern bool bUsedYYMarker; extern bool bUsedYYBitmap; @@ -57,7 +48,6 @@ extern std::string yyFillLength; extern std::string yySetConditionParam; extern std::string yySetStateParam; extern std::string yySetupRule; -extern uint maxFill; extern uint next_label; extern uint cGotoThreshold; @@ -81,7 +71,6 @@ extern bool bWroteGetState; extern bool bWroteCondCheck; extern bool bCaseInsensitive; extern bool bCaseInverted; -extern bool bTypesDone; extern const uint asc2asc[256]; extern const uint asc2ebc[256]; @@ -91,7 +80,6 @@ extern uint next_fill_index; extern uint last_fill_index; extern std::set vUsedLabels; extern CodeNames mapCodeName; -extern std::string typesInline; extern Enc encoding; extern InputAPI input_api; diff --git a/re2c/main.cc b/re2c/main.cc index cb07d15e..8d0e6650 100644 --- a/re2c/main.cc +++ b/re2c/main.cc @@ -13,14 +13,13 @@ #include "globals.h" #include "parser.h" #include "dfa.h" +#include "enc.h" #include "mbo_getopt.h" namespace re2c { file_info sourceFileInfo; -file_info outputFileInfo; -file_info headerFileInfo; bool bFlag = false; bool cFlag = false; @@ -35,16 +34,8 @@ bool sFlag = false; bool tFlag = false; bool bNoGenerationDate = false; - -bool bSinglePass = false; -bool bFirstPass = true; -bool bLastPass = false; bool bUsedYYBitmap = false; - -bool bUsedYYAccept = false; -bool bUsedYYMaxFill = false; bool bUsedYYMarker = true; - bool bEmitYYCh = true; bool bUseStartLabel = false; bool bUseStateNext = false; @@ -71,7 +62,6 @@ std::string yyFillLength("@@"); std::string yySetConditionParam("@@"); std::string yySetStateParam("@@"); std::string yySetupRule(""); -uint maxFill = 1; uint next_label = 0; uint cGotoThreshold = 9; @@ -83,7 +73,6 @@ bool bWroteGetState = false; bool bWroteCondCheck = false; bool bCaseInsensitive = false; bool bCaseInverted = false; -bool bTypesDone = false; Enc encoding; InputAPI input_api; @@ -92,7 +81,6 @@ uint next_fill_index = 0; uint last_fill_index = 0; std::set vUsedLabels; CodeNames mapCodeName; -std::string typesInline; free_list RegExp::vFreeList; free_list Range::vFreeList; @@ -125,7 +113,7 @@ static const mbo_opt_struct OPTIONS[] = mbo_opt_struct('w', 0, "wide-chars"), mbo_opt_struct('x', 0, "utf-16"), mbo_opt_struct('8', 0, "utf-8"), - mbo_opt_struct('1', 0, "single-pass"), + mbo_opt_struct('1', 0, "deprecated, single-pass"), mbo_opt_struct(10, 0, "no-generation-date"), mbo_opt_struct(11, 0, "case-insensitive"), mbo_opt_struct(12, 0, "case-inverted"), @@ -200,7 +188,8 @@ static void usage() " re2c assumes that input character size is 1 byte. This switch is\n" " incompatible with -e, -w, -x and -u." "\n" - "-1 --single-pass Force single pass generation, this cannot be combined\n" + "-1 --single-pass Deprecated.\n" + " Force single pass generation, this cannot be combined\n" " with -f and disables YYMAXFILL generation prior to last\n" " re2c block.\n" "\n" @@ -306,7 +295,6 @@ int main(int argc, char *argv[]) break; case '1': - bSinglePass = true; break; case 'v': @@ -416,10 +404,6 @@ int main(int argc, char *argv[]) } } - if ((bFlag || fFlag) && bSinglePass) { - std::cerr << "re2c: error: Cannot combine -1 and -b or -f switch\n"; - return 1; - } if (!cFlag && headerFileName) { std::cerr << "re2c: error: Can only output a header file when using -c switch\n"; @@ -462,58 +446,29 @@ int main(int argc, char *argv[]) return 1; } - // set up the output stream - re2c::ofstream_lc output; - re2c::ofstream_lc header; - - if (outputFileName == 0 || (sourceFileName[0] == '-' && sourceFileName[1] == '\0')) + // set up the output streams + if (outputFileName == NULL || (sourceFileName[0] == '-' && sourceFileName[1] == '\0')) { outputFileName = ""; - output.open(stdout); } - else if (!output.open(outputFileName).is_open()) + re2c::Output output (outputFileName, headerFileName); + if (output.source.status == OutputFile::FAIL_OPEN) { cerr << "re2c: error: cannot open " << outputFileName << "\n"; return 1; } - if (headerFileName) + if (output.header.status == OutputFile::FAIL_OPEN) { - if (!header.open(headerFileName).is_open()) - { - cerr << "re2c: error: cannot open " << headerFileName << "\n"; - return 1; - } - headerFileInfo = file_info(headerFileName, &header); + cerr << "re2c: error: cannot open " << headerFileName << "\n"; + return 1; } - Scanner scanner(source, output); - sourceFileInfo = file_info(sourceFileName, &scanner); - outputFileInfo = file_info(outputFileName, &output); - - if (!bSinglePass) - { - bUsedYYMarker = false; - re2c::ifstream_lc null_source; - - if (!null_source.open(sourceFileName).is_open()) - { - cerr << "re2c: error: cannot re-open " << sourceFileName << "\n"; - return 1; - } + Scanner scanner (source, output.source); + sourceFileInfo = file_info (sourceFileName, &scanner); + parse (scanner, output); - null_stream null_dev; - Scanner null_scanner(null_source, null_dev); - parse(null_scanner, null_dev, NULL); - next_label = 0; - next_fill_index = 0; - bWroteGetState = false; - bWroteCondCheck = false; - bUsedYYMaxFill = false; - bFirstPass = false; - sourceFileInfo.set_fname(sourceFileName); - } + // output generated code + output.emit (); - bLastPass = true; - parse(scanner, output, header.is_open() ? &header : NULL); return 0; } diff --git a/re2c/output.cc b/re2c/output.cc new file mode 100644 index 00000000..51fb006f --- /dev/null +++ b/re2c/output.cc @@ -0,0 +1,239 @@ +#include +#include + +#include "output.h" +#include "re.h" + +namespace re2c +{ + +uint OutputFragment::count_lines () +{ + uint lines = 0; + const std::string content = str (); + const char * p = content.c_str (); + for (uint i = 0; i < content.size (); ++i) + { + if (p[i] == '\n') + { + ++lines; + } + } + return lines; +} + +OutputBlock::OutputBlock () + : fragments () + , used_yyaccept (false) +{ + fragments.push_back (new OutputFragment (OutputFragment::CODE, 0)); +} + +OutputBlock::~OutputBlock () +{ + for (unsigned int i = 0; i < fragments.size (); ++i) + { + delete fragments[i]; + } +} + +OutputFile::OutputFile (const char * fn) + : status (NO_FILE) + , filename (fn) + , file (NULL) + , blocks () + , prolog_label (0) +{ + if (filename != NULL) + { + if (strcmp (filename, "") == 0) + { + file = stdout; + status = OK; + } + else + { + file = fopen (filename, "wb"); + status = file == NULL + ? FAIL_OPEN + : OK; + } + } + new_block (); +} + +OutputFile::~OutputFile () +{ + if (file != NULL && file != stdout) + { + fclose (file); + } + for (unsigned int i = 0; i < blocks.size (); ++i) + { + delete blocks[i]; + } +} + +OutputFragment & OutputFile::fragment () +{ + return * blocks.back ()->fragments.back (); +} + +void OutputFile::write (const char * s, std::streamsize n) +{ + fragment ().write (s, n); +} + +OutputFile & operator << (OutputFile & u, uint n) +{ + u.fragment () << n; + return u; +} + +OutputFile & operator << (OutputFile & u, const std::string & s) +{ + u.fragment () << s; + return u; +} + +OutputFile & operator << (OutputFile & u, const char * s) +{ + u.fragment () << s; + return u; +} + +OutputFile & operator << (OutputFile & u, const file_info & i) +{ + u.fragment () << i; + return u; +} + +OutputFile & operator << (OutputFile & u, const Str & s) +{ + u.fragment () << s; + return u; +} + +OutputFile & operator << (OutputFile & u, const Setw & s) +{ + u.fragment () << std::setw (s.width); + return u; +} + +void OutputFile::insert_code () +{ + blocks.back ()->fragments.push_back (new OutputFragment (OutputFragment::CODE, 0)); +} + +void OutputFile::insert_line_info () +{ + blocks.back ()->fragments.push_back (new OutputFragment (OutputFragment::LINE_INFO, 0)); + insert_code (); +} + +void OutputFile::insert_state_goto (uint ind, uint start_label) +{ + if (fFlag && !bWroteGetState) + { + prolog_label = start_label; + vUsedLabels.insert (start_label); + blocks.back ()->fragments.push_back (new OutputFragment (OutputFragment::STATE_GOTO, ind)); + insert_code (); + bWroteGetState = true; + } +} + +void OutputFile::insert_types () +{ + blocks.back ()->fragments.push_back (new OutputFragment (OutputFragment::TYPES, 0)); + insert_code (); +} + +void OutputFile::insert_yyaccept_init (uint ind) +{ + blocks.back ()->fragments.push_back (new OutputFragment (OutputFragment::YYACCEPT_INIT, ind)); + insert_code (); +} + +void OutputFile::insert_yyaccept_selector (uint ind, uint selector) +{ + OutputFragment * p = new OutputFragment (OutputFragment::YYACCEPT_SELECTOR, ind); + p->info.yyaccept_selector = selector; + blocks.back ()->fragments.push_back (p); + insert_code (); +} + +void OutputFile::insert_yymaxfill () +{ + blocks.back ()->fragments.push_back (new OutputFragment (OutputFragment::YYMAXFILL, 0)); + insert_code (); +} + +void OutputFile::set_used_yyaccept () +{ + blocks.back ()->used_yyaccept = true; +} + +bool OutputFile::get_used_yyaccept () const +{ + return blocks.back ()->used_yyaccept; +} + +void OutputFile::new_block () +{ + blocks.push_back (new OutputBlock ()); + insert_code (); +} + +void OutputFile::emit + ( const std::vector & types + , uint 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, line_count + 1, filename); + break; + case OutputFragment::STATE_GOTO: + output_state_goto (f, prolog_label); + break; + case OutputFragment::TYPES: + output_types (f, types); + break; + case OutputFragment::YYACCEPT_INIT: + output_yyaccept_init (f, b.used_yyaccept); + break; + case OutputFragment::YYACCEPT_SELECTOR: + output_yyaccept_selector (f, b.used_yyaccept); + break; + case OutputFragment::YYMAXFILL: + output_yymaxfill (f, max_fill); + break; + } + std::string content = f.str (); + fwrite (content.c_str (), 1, content.size (), file); + line_count += f.count_lines (); + } + } + } +} + +void Output::emit () +{ + source.emit (types, max_fill); + header.emit (types, max_fill); +} + +} // namespace re2c diff --git a/re2c/output.h b/re2c/output.h new file mode 100644 index 00000000..e24a3e2e --- /dev/null +++ b/re2c/output.h @@ -0,0 +1,127 @@ +#ifndef _output_h +#define _output_h + +#include +#include +#include + +#include "basics.h" + +namespace re2c +{ + +struct file_info; +struct Str; + +struct Setw +{ + uint width; + + Setw (uint n) + : width (n) + {} +}; + +struct OutputFragment : public std::ostringstream +{ + enum type_t + { CODE +// , COND_GOTO + , COND_TABLE +// , CONFIG + , LINE_INFO + , STATE_GOTO + , TYPES + , YYACCEPT_INIT + , YYACCEPT_SELECTOR + , YYMAXFILL + }; + + union info_t + { + uint yyaccept_selector; + }; + + type_t type; + info_t info; + uint indent; + + OutputFragment (type_t t, uint i) + : std::ostringstream () + , type (t) + , info () + , indent (i) + {} + + uint count_lines (); +}; + +OutputFragment & operator << (OutputFragment & f, const file_info & info); + +struct OutputBlock +{ + std::vector fragments; + bool used_yyaccept; + + OutputBlock (); + ~OutputBlock (); +}; + +struct OutputFile +{ + enum status_t + { NO_FILE + , OK + , FAIL_OPEN + } status; + + OutputFile (const char * filename); + ~OutputFile (); + OutputFragment & fragment (); + void write (const char * s, std::streamsize n); + void insert_line_info (); + void insert_state_goto (uint ind, uint start_label); + void insert_types (); + void insert_yyaccept_init (uint ind); + void insert_yyaccept_selector (uint ind, uint selector); + void insert_yymaxfill (); + void new_block (); + void set_used_yyaccept (); + bool get_used_yyaccept () const; + void emit (const std::vector & types, uint max_fill); + friend OutputFile & operator << (OutputFile & o, uint n); + friend OutputFile & operator << (OutputFile & o, const std::string & s); + friend OutputFile & operator << (OutputFile & o, const char * s); + friend OutputFile & operator << (OutputFile & o, const file_info & i); + friend OutputFile & operator << (OutputFile & o, const Str & s); + friend OutputFile & operator << (OutputFile & o, const Setw & s); + +private: + const char * filename; + FILE * file; + std::vector blocks; + uint prolog_label; + + void insert_code (); +}; + +struct Output +{ + OutputFile source; + OutputFile header; + std::vector types; + uint max_fill; + + Output (const char * source_name, const char * header_name) + : source (source_name) + , header (header_name) + , types () + , max_fill (1) + {} + + void emit (); +}; + +} // namespace re2c + +#endif // _output_h diff --git a/re2c/parser.h b/re2c/parser.h index c6d3ffc1..b067d8ff 100644 --- a/re2c/parser.h +++ b/re2c/parser.h @@ -2,9 +2,9 @@ #ifndef _parser_h #define _parser_h -#include "scanner.h" +#include "output.h" #include "re.h" -#include +#include "scanner.h" namespace re2c { @@ -53,7 +53,7 @@ private: #endif }; -extern void parse(Scanner&, std::ostream&, std::ostream*); +extern void parse(Scanner &, Output &); extern void parse_cleanup(); } // end namespace re2c diff --git a/re2c/parser.y b/re2c/parser.y index f0e7375e..530785a2 100644 --- a/re2c/parser.y +++ b/re2c/parser.y @@ -116,16 +116,13 @@ void setup_rule(CondList *clist, Token *code) assert(clist); assert(code); context_check(clist); - if (bFirstPass) + for(CondList::const_iterator it = clist->begin(); it != clist->end(); ++it) { - for(CondList::const_iterator it = clist->begin(); it != clist->end(); ++it) + if (ruleSetupMap.find(*it) != ruleSetupMap.end()) { - if (ruleSetupMap.find(*it) != ruleSetupMap.end()) - { - in->fatalf_at(code->line, "code to setup rule '%s' is already defined", it->c_str()); - } - ruleSetupMap[*it] = std::make_pair(code->line, code->text.to_string()); + in->fatalf_at(code->line, "code to setup rule '%s' is already defined", it->c_str()); } + ruleSetupMap[*it] = std::make_pair(code->line, code->text.to_string()); } delete clist; delete code; @@ -136,16 +133,13 @@ void default_rule(CondList *clist, Token *code) assert(clist); assert(code); context_check(clist); - if (bFirstPass) + for(CondList::const_iterator it = clist->begin(); it != clist->end(); ++it) { - for(CondList::const_iterator it = clist->begin(); it != clist->end(); ++it) + if (ruleDefaultMap.find(*it) != ruleDefaultMap.end()) { - if (ruleDefaultMap.find(*it) != ruleDefaultMap.end()) - { - in->fatalf_at(code->line, "code to default rule '%s' is already defined", it->c_str()); - } - ruleDefaultMap[*it] = code; + in->fatalf_at(code->line, "code to default rule '%s' is already defined", it->c_str()); } + ruleDefaultMap[*it] = code; } delete clist; } @@ -511,27 +505,22 @@ int yylex(){ namespace re2c { -void parse(Scanner& i, std::ostream& o, std::ostream* h) +void parse(Scanner& i, Output & o) { std::map > dfa_map; ScannerState rules_state; in = &i; - o << "/* Generated by re2c " PACKAGE_VERSION; - if (!bNoGenerationDate) - { - o << " on "; - time_t now = time(&now); - o.write(ctime(&now), 24); - } - o << " */\n"; - o << sourceFileInfo; - + output_version_time (o.source); + o.source << sourceFileInfo; + output_version_time (o.header); + Enc encodingOld = encoding; while ((parseMode = i.echo()) != Scanner::Stop) { + o.source.new_block (); bool bPrologBrace = false; ScannerState curr_state; @@ -668,16 +657,20 @@ void parse(Scanner& i, std::ostream& o, std::ostream* h) } } dfa_map[it->first] = genCode(it->second.second); - dfa_map[it->first]->prepare(); + dfa_map[it->first]->prepare(o.max_fill); } if (parseMode != Scanner::Rules && dfa_map.find(it->first) != dfa_map.end()) { dfa_map[it->first]->emit(o, topIndent, &specMap, it->first, !--nCount, bPrologBrace); } } - if (!h && !bTypesDone) + + genTypes (o, specMap); + if (o.header.status != OutputFile::NO_FILE) { - genTypes(typesInline, 0, specMap); + o.header.insert_line_info (); + o.header << "\n"; + o.header.insert_types (); } } else @@ -692,7 +685,7 @@ void parse(Scanner& i, std::ostream& o, std::ostream* h) if (parseMode != Scanner::Reuse) { dfa_map[""] = genCode(spec); - dfa_map[""]->prepare(); + dfa_map[""]->prepare(o.max_fill); } if (parseMode != Scanner::Rules && dfa_map.find("") != dfa_map.end()) { @@ -700,7 +693,7 @@ void parse(Scanner& i, std::ostream& o, std::ostream* h) } } } - o << sourceFileInfo; + o.source << sourceFileInfo; /* restore original char handling mode*/ encoding = encodingOld; } @@ -727,11 +720,6 @@ void parse(Scanner& i, std::ostream& o, std::ostream* h) } } - if (h) - { - genHeader(*h, 0, specMap); - } - parse_cleanup(); in = NULL; } diff --git a/re2c/re.h b/re2c/re.h index 11431c5d..068ff69e 100644 --- a/re2c/re.h +++ b/re2c/re.h @@ -8,12 +8,14 @@ #include #include #include -#include "token.h" -#include "ins.h" + #include "free_list.h" #include "globals.h" +#include "ins.h" +#include "output.h" #include "range.h" #include "smart_ptr.h" +#include "token.h" namespace re2c { @@ -407,11 +409,17 @@ typedef std::map DefaultMap; class DFA; extern smart_ptr genCode(RegExp*); -extern void genGetStateGoto(std::ostream&, uint&, uint); -extern void genCondTable(std::ostream&, uint, const RegExpMap&); -extern void genCondGoto(std::ostream&, uint, const RegExpMap&); -extern void genTypes(std::string&, uint, const RegExpMap&); -extern void genHeader(std::ostream&, uint, const RegExpMap&); +extern void genCondTable(OutputFile &, uint, const RegExpMap&); +extern void genCondGoto(OutputFile &, uint, const RegExpMap&); +extern void genTypes(Output &, const RegExpMap&); + +extern void output_state_goto (OutputFragment &, uint); +extern void output_types (OutputFragment &, const std::vector &); +extern void output_version_time (OutputFile &); +extern void output_yyaccept_init (OutputFragment &, bool); +extern void output_yyaccept_selector (OutputFragment &, bool); +extern void output_yymaxfill (OutputFragment &, uint); +extern void output_line_info (OutputFragment &, uint, const char *); extern RegExp *mkDiff(RegExp*, RegExp*); extern RegExp *mkAlt(RegExp*, RegExp*); diff --git a/re2c/scanner.h b/re2c/scanner.h index 8df3e5a6..5c1674bb 100644 --- a/re2c/scanner.h +++ b/re2c/scanner.h @@ -4,9 +4,11 @@ #include #include -#include "token.h" -#include "re.h" + #include "globals.h" +#include "output.h" +#include "re.h" +#include "token.h" namespace re2c { @@ -26,7 +28,7 @@ class Scanner: { private: std::istream& in; - std::ostream& out; + OutputFile & out; private: char *fill(char*, uint); @@ -35,7 +37,7 @@ private: void set_sourceline(char *& cursor); public: - Scanner(std::istream&, std::ostream&); + Scanner(std::istream&, OutputFile &); ~Scanner(); enum ParseMode { diff --git a/re2c/scanner.re b/re2c/scanner.re index 3bcf10ab..805292d0 100644 --- a/re2c/scanner.re +++ b/re2c/scanner.re @@ -1,4 +1,3 @@ -/* $Id$ */ #include #include #include @@ -70,10 +69,6 @@ echo: { fatal("found standard 're2c' block while using -r flag"); } - if (bUsedYYMaxFill && bSinglePass) - { - fatal("found scanner block after YYMAXFILL declaration"); - } if (!DFlag) { out.write((const char*)(tok), (const char*)(&cursor[-7]) - (const char*)(tok)); @@ -90,10 +85,6 @@ echo: { fatal("found 'rules:re2c' block without -r flag"); } - if (bUsedYYMaxFill && bSinglePass) - { - fatal("found scanner block after YYMAXFILL declaration"); - } tok = cursor; RETURN(Rules); } @@ -103,10 +94,6 @@ echo: fatal("found 'use:re2c' block without -r flag"); } reuse(); - if (bUsedYYMaxFill && bSinglePass) - { - fatal("found scanner block after YYMAXFILL declaration"); - } if (!DFlag) { out.write((const char*)(tok), (const char*)(&cursor[-11]) - (const char*)(tok)); @@ -115,22 +102,17 @@ echo: RETURN(Reuse); } "/*!max:re2c" { - if (bUsedYYMaxFill) - { - fatal("cannot generate YYMAXFILL twice"); - } if (!DFlag) { - out << "#define YYMAXFILL " << maxFill << std::endl; + out.insert_yymaxfill (); } tok = pos = cursor; ignore_eoc = true; - bUsedYYMaxFill = true; goto echo; } "/*!getstate:re2c" { tok = pos = cursor; - genGetStateGoto(out, topIndent, 0); + out.insert_state_goto (topIndent, 0); ignore_eoc = true; goto echo; } @@ -140,17 +122,13 @@ echo: goto echo; } "/*!types:re2c" { - if (bSinglePass) - { - fatal("cannot generate types inline in single pass mode"); - } tok = pos = cursor; ignore_eoc = true; - if (bLastPass && !DFlag) + if (!DFlag) { - out << outputFileInfo; + out.insert_line_info (); out << "\n"; - out << typesInline; + out.insert_types (); out << "\n"; out << sourceFileInfo; } diff --git a/re2c/test/error13.1.c b/re2c/test/error13.1.c index e44533a1..0ab654c4 100755 --- a/re2c/test/error13.1.c +++ b/re2c/test/error13.1.c @@ -1,5 +1,51 @@ /* Generated by re2c */ #line 1 "error13.1.re" -#define YYMAXFILL 1 +#define YYMAXFILL 3 + + +#line 7 "" +{ + YYCTYPE yych; + + if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3); + yych = *YYCURSOR; + switch (yych) { + case 'A': goto yy2; + default: goto yy4; + } +yy2: + yych = *(YYMARKER = ++YYCURSOR); + switch (yych) { + case 'B': goto yy5; + default: goto yy3; + } +yy3: +#line 6 "error13.1.re" + { return 0; } +#line 26 "" +yy4: + yych = *++YYCURSOR; + goto yy3; +yy5: + yych = *++YYCURSOR; + switch (yych) { + case 'C': goto yy7; + case 'D': goto yy9; + default: goto yy6; + } +yy6: + YYCURSOR = YYMARKER; + goto yy3; +yy7: + ++YYCURSOR; +#line 4 "error13.1.re" + { return 1; } +#line 44 "" +yy9: + ++YYCURSOR; +#line 5 "error13.1.re" + { return 2; } +#line 49 "" +} +#line 7 "error13.1.re" -re2c: error: line 3, column 1: found scanner block after YYMAXFILL declaration diff --git a/re2c/test/error14.1.c b/re2c/test/error14.1.c index 23bdd383..a21eaab6 100755 --- a/re2c/test/error14.1.c +++ b/re2c/test/error14.1.c @@ -50,4 +50,4 @@ yy9: #define YYMAXFILL 3 -re2c: error: line 9, column 1: cannot generate YYMAXFILL twice +#define YYMAXFILL 3 diff --git a/re2c/test/error14.c b/re2c/test/error14.c index 3583e1d6..27ac5ff7 100755 --- a/re2c/test/error14.c +++ b/re2c/test/error14.c @@ -1 +1,53 @@ -re2c: error: line 9, column 1: cannot generate YYMAXFILL twice +/* Generated by re2c */ +#line 1 "error14.re" + +#line 5 "" +{ + YYCTYPE yych; + + if ((YYLIMIT - YYCURSOR) < 3) YYFILL(3); + yych = *YYCURSOR; + switch (yych) { + case 'A': goto yy2; + default: goto yy4; + } +yy2: + yych = *(YYMARKER = ++YYCURSOR); + switch (yych) { + case 'B': goto yy5; + default: goto yy3; + } +yy3: +#line 4 "error14.re" + { return 0; } +#line 24 "" +yy4: + yych = *++YYCURSOR; + goto yy3; +yy5: + yych = *++YYCURSOR; + switch (yych) { + case 'C': goto yy7; + case 'D': goto yy9; + default: goto yy6; + } +yy6: + YYCURSOR = YYMARKER; + goto yy3; +yy7: + ++YYCURSOR; +#line 2 "error14.re" + { return 1; } +#line 42 "" +yy9: + ++YYCURSOR; +#line 3 "error14.re" + { return 2; } +#line 47 "" +} +#line 5 "error14.re" + + +#define YYMAXFILL 3 + +#define YYMAXFILL 3