From: nuno-lopes Date: Tue, 19 Feb 2008 16:19:29 +0000 (+0000) Subject: add --emit-dot flag to produce Graphviz dot files X-Git-Tag: 0.13.6~86 X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=19f8dd1571925c9127d99d2a76837758ff5494f6;p=re2c add --emit-dot flag to produce Graphviz dot files --- diff --git a/re2c/CHANGELOG b/re2c/CHANGELOG index 5aa8a176..973301b7 100644 --- a/re2c/CHANGELOG +++ b/re2c/CHANGELOG @@ -2,6 +2,7 @@ Version 0.13.3 (2008-??-??) --------------------------- - Partial support for flex syntax. - Changed to allow /* comments with -c switch. +- Added flag -D/--emit-dot. Version 0.13.2 (2008-02-14) --------------------------- diff --git a/re2c/bootstrap/scanner.cc b/re2c/bootstrap/scanner.cc index 7f9339df..3cad237e 100644 --- a/re2c/bootstrap/scanner.cc +++ b/re2c/bootstrap/scanner.cc @@ -1,4 +1,4 @@ -/* Generated by re2c 0.13.3.dev on Mon Feb 18 22:23:11 2008 */ +/* Generated by re2c 0.13.3.dev on Tue Feb 19 13:00:29 2008 */ /* $Id$ */ #include #include @@ -125,7 +125,7 @@ yy5: { ignore_cnt++; } - else + else if (!DFlag) { out.write((const char*)(tok), (const char*)(cursor) - (const char*)(tok)); } @@ -136,7 +136,7 @@ yy5: yy7: ++YYCURSOR; { - if (!ignore_eoc) + if (!ignore_eoc && !DFlag) { out.write((const char*)(tok), (const char*)(cursor) - (const char*)(tok) - 1); // -1 so we don't write out the \0 @@ -165,7 +165,7 @@ yy11: ignore_eoc = false; ignore_cnt = 0; } - else + else if (!DFlag) { out.write((const char*)(tok), (const char*)(cursor) - (const char*)(tok)); } @@ -195,7 +195,7 @@ yy14: ignore_eoc = false; ignore_cnt = 0; } - else + else if (!DFlag) { out.write((const char*)(tok), (const char*)(cursor) - (const char*)(tok)); } @@ -243,7 +243,10 @@ yy22: { fatal("found scanner block after YYMAXFILL declaration"); } - out.write((const char*)(tok), (const char*)(&cursor[-7]) - (const char*)(tok)); + if (!DFlag) + { + out.write((const char*)(tok), (const char*)(&cursor[-7]) - (const char*)(tok)); + } tok = cursor; RETURN(1); } @@ -266,7 +269,10 @@ yy27: { fatal("cannot generate YYMAXFILL twice"); } - out << "#define YYMAXFILL " << maxFill << std::endl; + if (!DFlag) + { + out << "#define YYMAXFILL " << maxFill << std::endl; + } tok = pos = cursor; ignore_eoc = true; bUsedYYMaxFill = true; @@ -352,7 +358,7 @@ yy59: } tok = pos = cursor; ignore_eoc = true; - if (bLastPass) + if (bLastPass && !DFlag) { out << outputFileInfo; out << "\n"; diff --git a/re2c/code.cc b/re2c/code.cc index 2add39e0..7b3b04ae 100644 --- a/re2c/code.cc +++ b/re2c/code.cc @@ -22,7 +22,7 @@ static std::string indent(uint ind) { std::string str; - while (ind-- > 0) + while (!DFlag && ind-- > 0) { str += indString; } @@ -362,6 +362,12 @@ void BitMap::stats() void genGoTo(std::ostream &o, uint ind, const State *from, const State *to, bool & readCh) { + if (DFlag) + { + o << from->label << " -> " << to->label << "\n"; + return; + } + if (readCh && from->label + 1 != to->label) { o << indent(ind) << mapCodeName["yych"] << " = " << yychConversion << "*" << mapCodeName["YYCURSOR"] << ";\n"; @@ -392,6 +398,11 @@ void genIf(std::ostream &o, uint ind, const char *cmp, uint v, bool &readCh) static void need(std::ostream &o, uint ind, uint n, bool & readCh, bool bSetMarker) { + if (DFlag) + { + return; + } + uint fillIndex = next_fill_index; if (fFlag) @@ -442,6 +453,11 @@ 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 { + if (DFlag) + { + return; + } + if (state->link) { o << indent(ind) << "++" << mapCodeName["YYCURSOR"] << ";\n"; @@ -536,6 +552,11 @@ 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 { + if (DFlag) + { + return; + } + if (bUsedYYAccept) { o << indent(ind) << mapCodeName["yyaccept"] << " = " << selector << ";\n"; @@ -614,7 +635,10 @@ void Accept::emit(std::ostream &o, uint ind, bool &readCh, const std::string&) c if (mapRules.size() > 0) { bUsedYYMarker = true; - o << indent(ind) << mapCodeName["YYCURSOR"] << " = " << mapCodeName["YYMARKER"] << ";\n"; + if (!DFlag) + { + o << indent(ind) << mapCodeName["YYCURSOR"] << " = " << mapCodeName["YYMARKER"] << ";\n"; + } if (readCh) // shouldn't be necessary, but might become at some point { @@ -643,6 +667,14 @@ void Accept::emit(std::ostream &o, uint ind, bool &readCh, const std::string&) c { emitBinary(o, ind, 0, mapRules.size() - 1, readCh); } + else if (DFlag) + { + for (RuleMap::const_iterator it = mapRules.begin(); it != mapRules.end(); ++it) + { + o << state->label << " -> " << it->second->label; + o << " [label=\"yyaccept=" << it->first << "\"]\n"; + } + } else { o << indent(ind) << "switch (" << mapCodeName["yyaccept"] << ") {\n"; @@ -671,6 +703,12 @@ Rule::Rule(State *s, RuleOp *r) : Action(s), rule(r) void Rule::emit(std::ostream &o, uint ind, bool &, const std::string& condName) const { + if (DFlag) + { + o << state->label << " [label=\"" << sourceFileInfo.fname << ":" << rule->code->line << "\"];\n"; + return; + } + uint back = rule->ctx->fixedLength(); if (back != 0u) @@ -719,7 +757,7 @@ void doLinear(std::ostream &o, uint ind, Span *s, uint n, const State *from, con genIf(o, ind, "!=", s[0].ub, readCh); genGoTo(o, 0, from, bg, readCh); } - if (next->label != from->label + 1) + if (next->label != from->label + 1 || DFlag) { genGoTo(o, ind, from, next, readCh); } @@ -741,7 +779,7 @@ void doLinear(std::ostream &o, uint ind, Span *s, uint n, const State *from, con if (n == 1) { // if(bg != next){ - if (s[0].to->label != from->label + 1) + if (s[0].to->label != from->label + 1 || DFlag) { genGoTo(o, ind, from, s[0].to, readCh); } @@ -755,7 +793,7 @@ void doLinear(std::ostream &o, uint ind, Span *s, uint n, const State *from, con genIf(o, ind, ">=", s[0].ub, readCh); genGoTo(o, 0, from, s[1].to, readCh); } - if (next->label != from->label + 1) + if (next->label != from->label + 1 || DFlag) { genGoTo(o, ind, from, next, readCh); } @@ -773,7 +811,7 @@ void doLinear(std::ostream &o, uint ind, Span *s, uint n, const State *from, con } } - if (next->label != from->label + 1) + if (next->label != from->label + 1 || DFlag) { genGoTo(o, ind, from, next, readCh); } @@ -784,7 +822,7 @@ void Go::genLinear(std::ostream &o, uint ind, const State *from, const State *ne doLinear(o, ind, span, nSpans, from, next, readCh, mask); } -bool genCases(std::ostream &o, uint ind, uint lb, Span *s, bool &newLine, uint mask) +bool genCases(std::ostream &o, uint ind, uint lb, Span *s, bool &newLine, uint mask, const State *from, const State *to) { bool used = false; @@ -799,9 +837,19 @@ bool genCases(std::ostream &o, uint ind, uint lb, Span *s, bool &newLine, uint m { if (!mask || lb > 0x00FF) { - o << indent(ind) << "case "; - prtChOrHex(o, lb); - o << ":"; + if (DFlag) + { + o << from->label << " -> " << to->label; + o << " [label="; + prtChOrHex(o, lb); + o << "]"; + } + else + { + o << indent(ind) << "case "; + prtChOrHex(o, lb); + o << ":"; + } newLine = false; used = true; } @@ -841,19 +889,22 @@ void Go::genSwitch(std::ostream &o, uint ind, const State *from, const State *ne } } - if (dFlag) + if (!DFlag) { - o << indent(ind) << mapCodeName["YYDEBUG"] << "(-1, " << mapCodeName["yych"] << ");\n"; - } + if (dFlag) + { + o << indent(ind) << mapCodeName["YYDEBUG"] << "(-1, " << mapCodeName["yych"] << ");\n"; + } - if (readCh) - { - o << indent(ind) << "switch ((" << mapCodeName["yych"] << " = " << yychConversion << "*" << mapCodeName["YYCURSOR"] << ")) {\n"; - readCh = false; - } - else - { - o << indent(ind) << "switch (" << mapCodeName["yych"] << ") {\n"; + if (readCh) + { + o << indent(ind) << "switch ((" << mapCodeName["yych"] << " = " << yychConversion << "*" << mapCodeName["YYCURSOR"] << ")) {\n"; + readCh = false; + } + else + { + o << indent(ind) << "switch (" << mapCodeName["yych"] << ") {\n"; + } } while (t != &sP[0]) @@ -862,22 +913,22 @@ void Go::genSwitch(std::ostream &o, uint ind, const State *from, const State *ne r = s = &sP[0]; + const State *to = (*s)->to; + if (*s == &span[0]) { - used |= genCases(o, ind, 0, *s, newLine, mask); + used |= genCases(o, ind, 0, *s, newLine, mask, from, to); } else { - used |= genCases(o, ind, (*s)[ -1].ub, *s, newLine, mask); + used |= genCases(o, ind, (*s)[ -1].ub, *s, newLine, mask, from, to); } - State *to = (*s)->to; - while (++s < t) { if ((*s)->to == to) { - used |= genCases(o, ind, (*s)[ -1].ub, *s, newLine, mask); + used |= genCases(o, ind, (*s)[ -1].ub, *s, newLine, mask, from, to); } else { @@ -885,7 +936,7 @@ void Go::genSwitch(std::ostream &o, uint ind, const State *from, const State *ne } } - if (used) + if (used && !DFlag) { genGoTo(o, newLine ? ind+1 : 1, from, to, readCh); newLine = true; @@ -893,9 +944,17 @@ void Go::genSwitch(std::ostream &o, uint ind, const State *from, const State *ne t = r; } - o << indent(ind) << "default:"; - genGoTo(o, 1, from, def, readCh); - o << indent(ind) << "}\n"; + if (DFlag) + { + o << "\n" << from->label << " -> " << def->label; + o << " [label=default]\n" ; + } + else + { + o << indent(ind) << "default:"; + genGoTo(o, 1, from, def, readCh); + o << indent(ind) << "}\n"; + } delete [] sP; } @@ -1667,7 +1726,13 @@ void DFA::emit(std::ostream &o, uint& ind, const RegExpMap* specMap, const std:: if (bProlog) { o << "\n" << outputFileInfo; - if ((!fFlag && bUsedYYAccept) + + if (DFlag) + { + bPrologBrace = true; + o << "digraph re2c {\n"; + } + else if ((!fFlag && bUsedYYAccept) || (!fFlag && bEmitYYCh) || (bFlag && !cFlag && BitMap::first) || (cFlag && !bWroteCondCheck && gFlag && !specMap->empty()) @@ -1681,8 +1746,8 @@ void DFA::emit(std::ostream &o, uint& ind, const RegExpMap* specMap, const std:: { ind = 1; } - - if (!fFlag) + + if (!fFlag && !DFlag) { if (bEmitYYCh) { @@ -1726,7 +1791,15 @@ void DFA::emit(std::ostream &o, uint& ind, const RegExpMap* specMap, const std:: { o << replaceParam(condDivider, condDividerParam, condName) << "\n"; } - o << condPrefix << condName << ":\n"; + + if (DFlag) + { + o << condName << " -> " << (start_label+1) << "\n"; + } + else + { + o << condPrefix << condName << ":\n"; + } } if (cFlag && bFlag && BitMap::first) { @@ -1928,6 +2001,13 @@ void genCondGoto(std::ostream &o, uint ind, const RegExpMap& specMap) } genCondGotoSub(o, ind, vCondList, 0, vCondList.size() - 1); } + else if (DFlag) + { + for(RegExpMap::const_iterator it = specMap.begin(); it != specMap.end(); ++it) + { + o << "0 -> " << it->first << " [label=\"state=" << it->first << "\"]\n"; + } + } else { o << indent(ind) << "switch (" << genGetCondition() << ") {\n"; diff --git a/re2c/dfa.cc b/re2c/dfa.cc index d7db03d5..249fa72a 100644 --- a/re2c/dfa.cc +++ b/re2c/dfa.cc @@ -14,13 +14,15 @@ void prtChOrHex(std::ostream& o, uint c, bool useTalx) if ((oc < 256) && isprint(oc)) { - o << '\''; + o << (DFlag ? '"' : '\''); prtCh(o, c); - o << '\''; + o << (DFlag ? '"' : '\''); } else { + if (DFlag) o << '"'; prtHex(o, c); + if (DFlag) o << '"'; } } @@ -63,7 +65,11 @@ void prtCh(std::ostream& o, uint c, bool useTalx) switch (oc) { case '\'': - o << "\\'"; + o << (DFlag ? "'" : "\\'"); + break; + + case '"': + o << (DFlag ? "\\\"" : "\""); break; case '\n': diff --git a/re2c/globals.h b/re2c/globals.h index 35ae798c..d89be924 100644 --- a/re2c/globals.h +++ b/re2c/globals.h @@ -19,6 +19,7 @@ extern file_info headerFileInfo; extern bool bFlag; extern bool cFlag; extern bool dFlag; +extern bool DFlag; extern bool eFlag; extern bool fFlag; extern bool FFlag; diff --git a/re2c/htdocs/index.html b/re2c/htdocs/index.html index 92094e18..aa1819d8 100755 --- a/re2c/htdocs/index.html +++ b/re2c/htdocs/index.html @@ -83,6 +83,7 @@ fixes which were incorporated. 2008-??-??: 0.13.3
  • Changed to allow /* comments with -c switch.
  • +
  • Added flag -D/--emit-dot.

2008-02-14: 0.13.2

    diff --git a/re2c/htdocs/manual.html b/re2c/htdocs/manual.html index 582c3d61..8b83e5c8 100755 --- a/re2c/htdocs/manual.html +++ b/re2c/htdocs/manual.html @@ -100,6 +100,10 @@ parser issues and states. If you use this switch you need to define a macro YYDEBUG that is called like a function with two parameters: void YYDEBUG(int state, char current). The first parameter receives the state or -1 and the second parameter receives the input at the current cursor.

    +
    -D
    +
    Emit Graphviz dot data. It can then be processed with e.g. +"dot -Tpng input.dot > output.png". Please note that scanners with many states +may crash dot.

    -e
    Cross-compile from an ASCII platform to an EBCDIC one.

    -f
    diff --git a/re2c/main.cc b/re2c/main.cc index 9cd57851..0833f4b1 100644 --- a/re2c/main.cc +++ b/re2c/main.cc @@ -25,6 +25,7 @@ file_info headerFileInfo; bool bFlag = false; bool cFlag = false; bool dFlag = false; +bool DFlag = false; bool eFlag = false; bool fFlag = false; bool FFlag = false; @@ -104,6 +105,7 @@ static const mbo_opt_struct OPTIONS[] = mbo_opt_struct('b', 0, "bit-vectors"), mbo_opt_struct('c', 0, "start-conditions"), mbo_opt_struct('d', 0, "debug-output"), + mbo_opt_struct('D', 0, "emit-dot"), mbo_opt_struct('e', 0, "ecb"), mbo_opt_struct('f', 0, "storable-state"), mbo_opt_struct('F', 0, "flex-syntax"), @@ -116,7 +118,7 @@ static const mbo_opt_struct OPTIONS[] = mbo_opt_struct('u', 0, "unicode"), mbo_opt_struct('v', 0, "version"), mbo_opt_struct('V', 0, "vernum"), - mbo_opt_struct('w', 0, "wide-chars"), + mbo_opt_struct('w', 0, "wide-chars"), mbo_opt_struct('1', 0, "single-pass"), mbo_opt_struct(10, 0, "no-generation-date"), mbo_opt_struct(11, 0, "case-insensitive"), @@ -126,7 +128,7 @@ static const mbo_opt_struct OPTIONS[] = static void usage() { - cerr << "usage: re2c [-bdefghisvVw1] [-o file] file\n" + cerr << "usage: re2c [-bcdDefFghisvVw1] [-o file] file\n" "\n" "-? -h --help Display this info.\n" "\n" @@ -141,6 +143,8 @@ static void usage() " about the current position and in which state the\n" " parser is.\n" "\n" + "-D --emit-dot Emit a Graphviz dot view of the DFA graph\n" + "\n" "-e --ecb Cross-compile from an ASCII platform to\n" " an EBCDIC one.\n" "\n" @@ -227,6 +231,11 @@ int main(int argc, char *argv[]) dFlag = true; break; + case 'D': + DFlag = true; + iFlag = true; + break; + case 'f': fFlag = true; break; diff --git a/re2c/re2c.1.in b/re2c/re2c.1.in index bd7f1628..3fff0feb 100644 --- a/re2c/re2c.1.in +++ b/re2c/re2c.1.in @@ -11,7 +11,7 @@ \*(re \- convert \*(rxs to C/C++ .SH SYNOPSIS -\*(re [\fB-bdefFghisuvVw1\fP] [\fB-o output\fP] [\fB-c\fP [\fB-t header\fP]] \fBfile\fP +\*(re [\fB-bdDefFghisuvVw1\fP] [\fB-o output\fP] [\fB-c\fP [\fB-t header\fP]] \fBfile\fP .SH DESCRIPTION \*(re is a preprocessor that generates C-based recognizers from regular @@ -109,6 +109,11 @@ parser issues and states. If you use this switch you need to define a macro \fIvoid YYDEBUG(int state, char current)\fP. The first parameter receives the state or -1 and the second parameter receives the input at the current cursor. .TP +\fB-D\fP +Emit Graphviz dot data. It can then be processed with e.g. +"dot -Tpng input.dot > output.png". Please note that scanners with many states +may crash dot. +.TP \fB-e\fP Cross-compile from an ASCII platform to an EBCDIC one. .TP diff --git a/re2c/scanner.re b/re2c/scanner.re index d5e4c4be..5c55b04c 100644 --- a/re2c/scanner.re +++ b/re2c/scanner.re @@ -116,7 +116,10 @@ echo: { fatal("found scanner block after YYMAXFILL declaration"); } - out.write((const char*)(tok), (const char*)(&cursor[-7]) - (const char*)(tok)); + if (!DFlag) + { + out.write((const char*)(tok), (const char*)(&cursor[-7]) - (const char*)(tok)); + } tok = cursor; RETURN(1); } @@ -125,7 +128,10 @@ echo: { fatal("cannot generate YYMAXFILL twice"); } - out << "#define YYMAXFILL " << maxFill << std::endl; + if (!DFlag) + { + out << "#define YYMAXFILL " << maxFill << std::endl; + } tok = pos = cursor; ignore_eoc = true; bUsedYYMaxFill = true; @@ -149,7 +155,7 @@ echo: } tok = pos = cursor; ignore_eoc = true; - if (bLastPass) + if (bLastPass && !DFlag) { out << outputFileInfo; out << "\n"; @@ -170,7 +176,7 @@ echo: ignore_eoc = false; ignore_cnt = 0; } - else + else if (!DFlag) { out.write((const char*)(tok), (const char*)(cursor) - (const char*)(tok)); } @@ -187,7 +193,7 @@ echo: ignore_eoc = false; ignore_cnt = 0; } - else + else if (!DFlag) { out.write((const char*)(tok), (const char*)(cursor) - (const char*)(tok)); } @@ -199,7 +205,7 @@ echo: { ignore_cnt++; } - else + else if (!DFlag) { out.write((const char*)(tok), (const char*)(cursor) - (const char*)(tok)); } @@ -208,7 +214,7 @@ echo: goto echo; } zero { - if (!ignore_eoc) + if (!ignore_eoc && !DFlag) { out.write((const char*)(tok), (const char*)(cursor) - (const char*)(tok) - 1); // -1 so we don't write out the \0 diff --git a/re2c/test/dot.D.c b/re2c/test/dot.D.c new file mode 100644 index 00000000..9d5bc3d1 --- /dev/null +++ b/re2c/test/dot.D.c @@ -0,0 +1,24 @@ +/* Generated by re2c */ + +digraph re2c { + + +1 -> 2 [label="a"] +1 -> 4 [label="e"] +1 -> 5 [label=default] +2 -> 10 [label="b"] +2 -> 3 [label=default] +3 [label="dot.D.re:8"]; +4 -> 6 [label="f"] +4 -> 3 [label=default] +5 -> 3 +6 -> 8 [label="g"] +6 -> 7 [label=default] +7 -> 3 +8 -> 9 +9 [label="dot.D.re:7"]; +10 -> 11 [label="c"] +10 -> 7 [label=default] +11 -> 12 +12 [label="dot.D.re:6"]; +} diff --git a/re2c/test/dot.D.re b/re2c/test/dot.D.re new file mode 100644 index 00000000..1de5f06d --- /dev/null +++ b/re2c/test/dot.D.re @@ -0,0 +1,13 @@ +int main(){ + printf("some code that will be stripped"); + +/*!re2c + +"abc" { return 1; } +"efg" { return 2; } +[^] { return 3; } + +*/ + + printf("here too"); +} diff --git a/re2c/test/dot_conditions.Dc.c b/re2c/test/dot_conditions.Dc.c new file mode 100644 index 00000000..ac95120d --- /dev/null +++ b/re2c/test/dot_conditions.Dc.c @@ -0,0 +1,35 @@ +/* Generated by re2c */ + +digraph re2c { + +0 -> state1 [label="state=state1"] +0 -> state2 [label="state=state2"] +/* *********************************** */ +state1 -> 1 + +1 -> 3 [label="a"] +1 -> 4 [label="f"] +1 -> 2 [label=default] +3 -> 8 [label="b"] +3 -> 2 [label=default] +4 -> 5 [label="o"] +4 -> 2 [label=default] +5 -> 6 [label="o"] +5 -> 2 [label=default] +6 -> 7 +7 [label="dot_conditions.Dc.re:8"]; +8 -> 9 [label="c"] +8 -> 2 [label=default] +9 -> 10 +10 [label="dot_conditions.Dc.re:6"]; +/* *********************************** */ +state2 -> 12 +12 -> 14 [label="a"] +12 -> 13 [label=default] +14 -> 15 [label="b"] +14 -> 13 [label=default] +15 -> 16 [label="c"] +15 -> 13 [label=default] +16 -> 17 +17 [label="dot_conditions.Dc.re:7"]; +} diff --git a/re2c/test/dot_conditions.Dc.re b/re2c/test/dot_conditions.Dc.re new file mode 100644 index 00000000..7e3f18a0 --- /dev/null +++ b/re2c/test/dot_conditions.Dc.re @@ -0,0 +1,13 @@ +int main() { + printf("some code that will be stripped"); + +/*!re2c + +"abc" { return 1; } +"abc" { return 2; } +"foo" { return 3; } + +*/ + + printf("here too\n"); +}