/* $Id: code.cc 717 2007-04-29 22:29:59Z helly $ */ #include #include #include #include #include #include "substr.h" #include "globals.h" #include "dfa.h" #include "parser.h" #include "code.h" namespace re2c { // there must be at least one span in list; all spans must cover // same range std::string indent(uint ind) { std::string str; while (ind-- > 0) { str += indString; } return str; } static std::string space(uint this_label) { int nl = next_label > 999999 ? 6 : next_label > 99999 ? 5 : next_label > 9999 ? 4 : next_label > 999 ? 3 : next_label > 99 ? 2 : next_label > 9 ? 1 : 0; int tl = this_label > 999999 ? 6 : this_label > 99999 ? 5 : this_label > 9999 ? 4 : this_label > 999 ? 3 : this_label > 99 ? 2 : this_label > 9 ? 1 : 0; return std::string(std::max(1, nl - tl + 1), ' '); } void Go::compact() { // arrange so that adjacent spans have different targets uint i = 0; for (uint j = 1; j < nSpans; ++j) { if (span[j].to != span[i].to) { ++i; span[i].to = span[j].to; } span[i].ub = span[j].ub; } nSpans = i + 1; } void Go::unmap(Go *base, const State *x) { Span *s = span, *b = base->span, *e = &b[base->nSpans]; uint lb = 0; s->ub = 0; s->to = NULL; for (; b != e; ++b) { if (b->to == x) { if ((s->ub - lb) > 1) { s->ub = b->ub; } } else { if (b->to != s->to) { if (s->ub) { lb = s->ub; ++s; } s->to = b->to; } s->ub = b->ub; } } s->ub = e[ -1].ub; ++s; nSpans = s - span; } void doGen(const Go *g, const State *s, uint *bm, uint f, uint m) { Span *b = g->span, *e = &b[g->nSpans]; uint lb = 0; for (; b < e; ++b) { if (b->to == s) { for (; lb < b->ub && lb < 256; ++lb) { bm[lb-f] |= m; } } lb = b->ub; } } 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; } } bool matches(const Go *g1, const State *s1, const Go *g2, const State *s2) { Span *b1 = g1->span, *e1 = &b1[g1->nSpans]; uint lb1 = 0; Span *b2 = g2->span, *e2 = &b2[g2->nSpans]; uint lb2 = 0; for (;;) { for (; b1 < e1 && b1->to != s1; ++b1) { lb1 = b1->ub; } for (; b2 < e2 && b2->to != s2; ++b2) { lb2 = b2->ub; } if (b1 == e1) { return b2 == e2; } if (b2 == e2) { return false; } if (lb1 != lb2 || b1->ub != b2->ub) { return false; } ++b1; ++b2; } } BitMap *BitMap::first = NULL; BitMap::BitMap(const Go *g, const State *x) : go(g) , on(x) , next(first) , i(0) , m(0) { first = this; } BitMap::~BitMap() { delete next; } const BitMap *BitMap::find(const Go *g, const State *x) { for (const BitMap *b = first; b; b = b->next) { if (matches(b->go, b->on, g, x)) { return b; } } return new BitMap(g, x); } const BitMap *BitMap::find(const State *x) { for (const BitMap *b = first; b; b = b->next) { if (b->on == x) { return b; } } return NULL; } void BitMap::gen(std::ostream &o, uint ind, uint lb, uint ub) { if (first && bLastPass) { o << indent(ind) << "static const unsigned char " << mapCodeName["yybm"] << "[] = {"; uint c = 1, n = ub - lb; const BitMap *cb = first; while((cb = cb->next) != NULL) { ++c; } BitMap *b = first; uint *bm = new uint[n]; for (uint i = 0, t = 1; b; i += n, t += 8) { memset(bm, 0, n * sizeof(uint)); for (uint m = 0x80; b && m; m >>= 1) { b->i = i; b->m = m; doGen(b->go, b->on, bm, lb, m); b = const_cast(b->next); } if (c > 8) { o << "\n" << indent(ind+1) << "/* table " << t << " .. " << std::min(c, t+7) << ": " << i << " */"; } for (uint j = 0; j < n; ++j) { if (j % 8 == 0) { o << "\n" << indent(ind+1); } if (yybmHexTable) { prtHex(o, bm[j], false); } else { o << std::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; } void genGoTo(std::ostream &o, uint ind, const State *from, const State *to, bool & readCh) { if (readCh && from->label + 1 != to->label) { o << indent(ind) << mapCodeName["yych"] << " = " << yychConversion << "*" << mapCodeName["YYCURSOR"] << ";\n"; readCh = false; } o << indent(ind) << "goto " << labelPrefix << to->label << ";\n"; vUsedLabels.insert(to->label); } void genIf(std::ostream &o, uint ind, const char *cmp, uint v, bool &readCh) { o << indent(ind) << "if("; if (readCh) { o << "(" << mapCodeName["yych"] << " = " << yychConversion << "*" << mapCodeName["YYCURSOR"] << ")"; readCh = false; } else { o << mapCodeName["yych"]; } o << " " << cmp << " "; prtChOrHex(o, v); o << ") "; } static void need(std::ostream &o, uint ind, uint n, bool & readCh, bool bSetMarker) { uint fillIndex = next_fill_index; if (fFlag) { next_fill_index++; o << indent(ind) << mapCodeName["YYSETSTATE"] << "(" << fillIndex << ");\n"; } if (bUseYYFill) { if (n == 1) { o << indent(ind) << "if(" << mapCodeName["YYLIMIT"] << " == " << mapCodeName["YYCURSOR"] << ") " << mapCodeName["YYFILL"]; } else { o << indent(ind) << "if((" << mapCodeName["YYLIMIT"] << " - " << mapCodeName["YYCURSOR"] << ") < " << n << ") " << mapCodeName["YYFILL"]; } if (bUseYYFillParam) { o << "(" << n << ")"; } o << ";\n"; } if (fFlag) { o << mapCodeName["yyFillLabel"] << fillIndex << ":\n"; } if (bSetMarker) { o << indent(ind) << mapCodeName["yych"] << " = " << yychConversion << "*(" << mapCodeName["YYMARKER"] << " = " << mapCodeName["YYCURSOR"] << ");\n"; } else { o << indent(ind) << mapCodeName["yych"] << " = " << yychConversion << "*" << mapCodeName["YYCURSOR"] << ";\n"; } readCh = false; } void Match::emit(std::ostream &o, uint ind, bool &readCh) const { if (state->link) { o << indent(ind) << "++" << mapCodeName["YYCURSOR"] << ";\n"; } else if (!readAhead()) { /* do not read next char if match */ o << indent(ind) << "++" << mapCodeName["YYCURSOR"] << ";\n"; readCh = true; } else { o << indent(ind) << mapCodeName["yych"] << " = " << yychConversion << "*++" << mapCodeName["YYCURSOR"] << ";\n"; readCh = false; } if (state->link) { need(o, ind, state->depth, readCh, false); } } void Enter::emit(std::ostream &o, uint ind, bool &readCh) const { if (state->link) { o << indent(ind) << "++" << mapCodeName["YYCURSOR"] << ";\n"; if (vUsedLabels.count(label)) { o << labelPrefix << label << ":\n"; } need(o, ind, state->depth, readCh, false); } else { /* we shouldn't need 'rule-following' protection here */ o << indent(ind) << mapCodeName["yych"] << " = " << yychConversion << "*++" << mapCodeName["YYCURSOR"] << ";\n"; if (vUsedLabels.count(label)) { o << labelPrefix << label << ":\n"; } readCh = false; } } void Initial::emit(std::ostream &o, uint ind, bool &readCh) const { if (!startLabelName.empty()) { o << startLabelName << ":\n"; } if (vUsedLabels.count(1)) { if (state->link) { o << indent(ind) << "++" << mapCodeName["YYCURSOR"] << ";\n"; } else { o << indent(ind) << mapCodeName["yych"] << " = " << yychConversion << "*++" << mapCodeName["YYCURSOR"] << ";\n"; } } if (vUsedLabels.count(label)) { o << labelPrefix << label << ":\n"; } else if (!label) { o << "\n"; } if (dFlag) { o << indent(ind) << mapCodeName["YYDEBUG"] << "(" << label << ", *" << mapCodeName["YYCURSOR"] << ");\n"; } if (state->link) { need(o, ind, state->depth, readCh, setMarker && bUsedYYMarker); } else { if (setMarker && bUsedYYMarker) { o << indent(ind) << mapCodeName["YYMARKER"] << " = " << mapCodeName["YYCURSOR"] << ";\n"; } readCh = false; } } void Save::emit(std::ostream &o, uint ind, bool &readCh) const { if (bUsedYYAccept) { o << indent(ind) << mapCodeName["yyaccept"] << " = " << selector << ";\n"; } if (state->link) { if (bUsedYYMarker) { o << indent(ind) << mapCodeName["YYMARKER"] << " = ++" << mapCodeName["YYCURSOR"] << ";\n"; } need(o, ind, state->depth, readCh, false); } else { if (bUsedYYMarker) { o << indent(ind) << mapCodeName["yych"] << " = " << yychConversion << "*(" << mapCodeName["YYMARKER"] << " = ++" << mapCodeName["YYCURSOR"] << ");\n"; } else { o << indent(ind) << mapCodeName["yych"] << " = " << yychConversion << "*++" << mapCodeName["YYCURSOR"] << ";\n"; } readCh = false; } } Move::Move(State *s) : Action(s) { ; } void Move::emit(std::ostream &, uint, bool &) const { ; } Accept::Accept(State *x, uint n, uint *s, State **r) : Action(x), nRules(n), saves(s), rules(r) { ; } void Accept::genRuleMap() { for (uint i = 0; i < nRules; ++i) { if (saves[i] != ~0u) { mapRules[saves[i]] = rules[i]; } } } void Accept::emitBinary(std::ostream &o, uint ind, uint l, uint r, bool &readCh) const { if (l < r) { uint m = (l + r) >> 1; o << indent(ind) << "if(" << mapCodeName["yyaccept"] << " <= " << m << ") {\n"; emitBinary(o, ++ind, l, m, readCh); o << indent(--ind) << "} else {\n"; emitBinary(o, ++ind, m + 1, r, readCh); o << indent(--ind) << "}\n"; } else { genGoTo(o, ind, state, mapRules.find(l)->second, readCh); } } void Accept::emit(std::ostream &o, uint ind, bool &readCh) const { if (mapRules.size() > 0) { bUsedYYMarker = true; o << indent(ind) << mapCodeName["YYCURSOR"] << " = " << mapCodeName["YYMARKER"] << ";\n"; if (readCh) // shouldn't be necessary, but might become at some point { o << indent(ind) << mapCodeName["yych"] << " = " << yychConversion << "*" << mapCodeName["YYCURSOR"] << ";\n"; readCh = false; } if (mapRules.size() > 1) { bUsedYYAccept = true; if (gFlag && mapRules.size() >= cGotoThreshold) { o << indent(ind++) << "{\n"; o << indent(ind++) << "static void *" << mapCodeName["yytarget"] << "[" << mapRules.size() << "] = {\n"; for (RuleMap::const_iterator it = mapRules.begin(); it != mapRules.end(); ++it) { o << indent(ind) << "&&" << labelPrefix << it->second->label << ",\n"; vUsedLabels.insert(it->second->label); } o << indent(--ind) << "};\n"; o << indent(ind) << "goto *" << mapCodeName["yytarget"] << "[" << mapCodeName["yyaccept"] << "];\n"; o << indent(--ind) << "}\n"; } else if (sFlag) { emitBinary(o, ind, 0, mapRules.size() - 1, readCh); } else { o << indent(ind) << "switch(" << mapCodeName["yyaccept"] << ") {\n"; for (RuleMap::const_iterator it = mapRules.begin(); it != mapRules.end(); ++it) { o << indent(ind) << "case " << it->first << ": \t"; genGoTo(o, 0, state, it->second, readCh); } o << indent(ind) << "}\n"; } } else { // no need to write if statement here since there is only case 0. genGoTo(o, ind, state, mapRules.find(0)->second, readCh); } } } Rule::Rule(State *s, RuleOp *r) : Action(s), rule(r) { ; } void Rule::emit(std::ostream &o, uint ind, bool &) const { uint back = rule->ctx->fixedLength(); if (back != 0u) { o << indent(ind) << mapCodeName["YYCURSOR"] << " = " << mapCodeName["YYCTXMARKER"] << ";\n"; } RuleLine rl(*rule); o << file_info(sourceFileInfo, &rl); o << indent(ind); o << rule->code->text; o << "\n"; o << outputFileInfo; } void doLinear(std::ostream &o, uint ind, Span *s, uint n, const State *from, const State *next, bool &readCh, uint mask) { for (;;) { State *bg = s[0].to; while (n >= 3 && s[2].to == bg && (s[1].ub - s[0].ub) == 1) { if (s[1].to == next && n == 3) { if (!mask || (s[0].ub > 0x00FF)) { genIf(o, ind, "!=", s[0].ub, readCh); genGoTo(o, 0, from, bg, readCh); } if (next->label != from->label + 1) { genGoTo(o, ind, from, next, readCh); } return ; } else { if (!mask || (s[0].ub > 0x00FF)) { genIf(o, ind, "==", s[0].ub, readCh); genGoTo(o, 0, from, s[1].to, readCh); } } n -= 2; s += 2; } if (n == 1) { // if(bg != next){ if (s[0].to->label != from->label + 1) { genGoTo(o, ind, from, s[0].to, readCh); } // } return ; } else if (n == 2 && bg == next) { if (!mask || (s[0].ub > 0x00FF)) { genIf(o, ind, ">=", s[0].ub, readCh); genGoTo(o, 0, from, s[1].to, readCh); } if (next->label != from->label + 1) { genGoTo(o, ind, from, next, readCh); } return ; } else { if (!mask || ((s[0].ub - 1) > 0x00FF)) { genIf(o, ind, "<=", s[0].ub - 1, readCh); genGoTo(o, 0, from, bg, readCh); } n -= 1; s += 1; } } if (next->label != from->label + 1) { genGoTo(o, ind, from, next, readCh); } } void Go::genLinear(std::ostream &o, uint ind, const State *from, const State *next, bool &readCh, uint mask) const { 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 used = false; if (!newLine) { o << "\n"; } newLine = true; if (lb < s->ub) { for (;;) { if (!mask || lb > 0x00FF) { o << indent(ind) << "case "; prtChOrHex(o, lb); o << ":"; newLine = false; used = true; } if (++lb == s->ub) { break; } o << "\n"; newLine = true; } } return used; } void Go::genSwitch(std::ostream &o, uint ind, const State *from, const State *next, bool &readCh, uint mask) const { bool newLine = true; if ((mask ? wSpans : nSpans) <= 2) { genLinear(o, ind, from, next, readCh, mask); } else { State *def = span[nSpans - 1].to; Span **sP = new Span * [nSpans - 1], **r, **s, **t; t = &sP[0]; for (uint i = 0; i < nSpans; ++i) { if (span[i].to != def) { *(t++) = &span[i]; } } 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"; } while (t != &sP[0]) { bool used = false; r = s = &sP[0]; if (*s == &span[0]) { used |= genCases(o, ind, 0, *s, newLine, mask); } else { used |= genCases(o, ind, (*s)[ -1].ub, *s, newLine, mask); } State *to = (*s)->to; while (++s < t) { if ((*s)->to == to) { used |= genCases(o, ind, (*s)[ -1].ub, *s, newLine, mask); } else { *(r++) = *s; } } if (used) { genGoTo(o, newLine ? ind+1 : 1, from, to, readCh); newLine = true; } t = r; } o << indent(ind) << "default:"; genGoTo(o, 1, from, def, readCh); o << indent(ind) << "}\n"; delete [] sP; } } void doBinary(std::ostream &o, uint ind, Span *s, uint n, const State *from, const State *next, bool &readCh, uint mask) { if (n <= 4) { doLinear(o, ind, s, n, from, next, readCh, mask); } else { uint h = n / 2; genIf(o, ind, "<=", s[h - 1].ub - 1, readCh); o << "{\n"; doBinary(o, ind+1, &s[0], h, from, next, readCh, mask); o << indent(ind) << "} else {\n"; doBinary(o, ind+1, &s[h], n - h, from, next, readCh, mask); o << indent(ind) << "}\n"; } } void Go::genBinary(std::ostream &o, uint ind, const State *from, const State *next, bool &readCh, uint mask) const { if (mask) { Span * sc = new Span[wSpans]; for (uint i = 0, j = 0; i < nSpans; i++) { if (span[i].ub > 0xFF) { sc[j++] = span[i]; } } doBinary(o, ind, sc, wSpans, from, next, readCh, mask); delete[] sc; } else { doBinary(o, ind, span, nSpans, from, next, readCh, mask); } } void Go::genBase(std::ostream &o, uint ind, const State *from, const State *next, bool &readCh, uint mask) const { if ((mask ? wSpans : nSpans) == 0) { return ; } if (!sFlag) { genSwitch(o, ind, from, next, readCh, mask); return ; } if ((mask ? wSpans : nSpans) > 8) { Span *bot = &span[0], *top = &span[nSpans - 1]; uint util; if (bot[0].to == top[0].to) { util = (top[ -1].ub - bot[0].ub) / (nSpans - 2); } else { if (bot[0].ub > (top[0].ub - top[ -1].ub)) { util = (top[0].ub - bot[0].ub) / (nSpans - 1); } else { util = top[ -1].ub / (nSpans - 1); } } if (util <= 2) { genSwitch(o, ind, from, next, readCh, mask); return ; } } if ((mask ? wSpans : nSpans) > 5) { genBinary(o, ind, from, next, readCh, mask); } else { genLinear(o, ind, from, next, readCh, mask); } } void Go::genCpGoto(std::ostream &o, uint ind, const State *from, const State *next, bool &readCh) const { std::string sYych; if (readCh) { sYych = "(" + mapCodeName["yych"] + " = " + yychConversion + "*" + mapCodeName["YYCURSOR"] + ")"; } else { sYych = mapCodeName["yych"]; } readCh = false; if (wFlag) { o << indent(ind) << "if(" << sYych <<" & ~0xFF) {\n"; genBase(o, ind+1, from, next, readCh, 1); o << indent(ind++) << "} else {\n"; sYych = mapCodeName["yych"]; } else { o << indent(ind++) << "{\n"; } o << indent(ind++) << "static void *" << mapCodeName["yytarget"] << "[256] = {\n"; o << indent(ind); uint ch = 0; for (uint i = 0; i < lSpans; ++i) { vUsedLabels.insert(span[i].to->label); for(; ch < span[i].ub; ++ch) { o << "&&" << labelPrefix << span[i].to->label; if (ch == 255) { o << "\n"; i = lSpans; break; } else if (ch % 8 == 7) { o << ",\n" << indent(ind); } else { o << "," << space(span[i].to->label); } } } o << indent(--ind) << "};\n"; o << indent(ind) << "goto *" << mapCodeName["yytarget"] << "[" << sYych << "];\n"; o << indent(--ind) << "}\n"; } void Go::genGoto(std::ostream &o, uint ind, const State *from, const State *next, bool &readCh) { if ((gFlag || wFlag) && wSpans == ~0u) { uint nBitmaps = 0; std::set vTargets; wSpans = 0; lSpans = 1; dSpans = 0; for (uint i = 0; i < nSpans; ++i) { if (span[i].ub > 0xFF) { wSpans++; } if (span[i].ub < 0x100 || !wFlag) { lSpans++; State *to = span[i].to; if (to && to->isBase) { const BitMap *b = BitMap::find(to); if (b && matches(b->go, b->on, this, to)) { nBitmaps++; } else { dSpans++; vTargets.insert(to->label); } } else { dSpans++; vTargets.insert(to->label); } } } lTargets = vTargets.size() >> nBitmaps; } if (gFlag && (lTargets >= cGotoThreshold || dSpans >= cGotoThreshold)) { genCpGoto(o, ind, from, next, readCh); return; } else if (bFlag) { for (uint i = 0; i < nSpans; ++i) { State *to = span[i].to; if (to && to->isBase) { const BitMap *b = BitMap::find(to); std::string sYych; if (b && matches(b->go, b->on, this, to)) { Go go; go.span = new Span[nSpans]; go.unmap(this, to); if (readCh) { sYych = "(" + mapCodeName["yych"] + " = " + yychConversion + "*" + mapCodeName["YYCURSOR"] + ")"; } else { sYych = mapCodeName["yych"]; } readCh = false; if (wFlag) { o << indent(ind) << "if(" << sYych << " & ~0xFF) {\n"; sYych = mapCodeName["yych"]; genBase(o, ind+1, from, next, readCh, 1); o << indent(ind) << "} else "; } else { o << indent(ind); } o << "if(" << mapCodeName["yybm"] << "[" << b->i << "+" << sYych << "] & "; if (yybmHexTable) { prtHex(o, b->m, false); } else { o << (uint) b->m; } o << ") {\n"; genGoTo(o, ind+1, from, to, readCh); o << indent(ind) << "}\n"; go.genBase(o, ind, from, next, readCh, 0); delete [] go.span; return ; } } } } genBase(o, ind, from, next, readCh, 0); } void State::emit(std::ostream &o, uint ind, bool &readCh) const { if (vUsedLabels.count(label)) { o << labelPrefix << label << ":\n"; } if (dFlag && !action->isInitial()) { o << indent(ind) << mapCodeName["YYDEBUG"] << "(" << label << ", *" << mapCodeName["YYCURSOR"] << ");\n"; } if (isPreCtxt) { o << indent(ind) << mapCodeName["YYCTXMARKER"] << " = " << mapCodeName["YYCURSOR"] << " + 1;\n"; } action->emit(o, ind, readCh); } uint merge(Span *x0, State *fg, State *bg) { Span *x = x0, *f = fg->go.span, *b = bg->go.span; uint nf = fg->go.nSpans, nb = bg->go.nSpans; State *prev = NULL, *to; // NB: we assume both spans are for same range for (;;) { if (f->ub == b->ub) { to = f->to == b->to ? bg : f->to; if (to == prev) { --x; } else { x->to = prev = to; } x->ub = f->ub; ++x; ++f; --nf; ++b; --nb; if (nf == 0 && nb == 0) { return x - x0; } } while (f->ub < b->ub) { to = f->to == b->to ? bg : f->to; if (to == prev) { --x; } else { x->to = prev = to; } x->ub = f->ub; ++x; ++f; --nf; } while (b->ub < f->ub) { to = b->to == f->to ? bg : f->to; if (to == prev) { --x; } else { x->to = prev = to; } x->ub = b->ub; ++x; ++b; --nb; } } } const uint cInfinity = ~0; class SCC { public: State **top, **stk; public: SCC(uint); ~SCC(); void traverse(State*); #ifdef PEDANTIC private: SCC(const SCC& oth) : top(oth.top) , stk(oth.stk) { } SCC& operator = (const SCC& oth) { new(this) SCC(oth); return *this; } #endif }; SCC::SCC(uint size) : top(new State * [size]) , stk(top) { } SCC::~SCC() { delete [] stk; } void SCC::traverse(State *x) { *top = x; uint k = ++top - stk; x->depth = k; for (uint i = 0; i < x->go.nSpans; ++i) { State *y = x->go.span[i].to; if (y) { if (y->depth == 0) { traverse(y); } if (y->depth < x->depth) { x->depth = y->depth; } } } if (x->depth == k) { do { (*--top)->depth = cInfinity; (*top)->link = x; } while (*top != x); } } static bool state_is_in_non_trivial_SCC(const State* s) { // does not link to self if (s->link != s) { return true; } // or exists i: (s->go.spans[i].to->link == s) // // Note: (s->go.spans[i].to == s) is allowed, corresponds to s // looping back to itself. // for (uint i = 0; i < s->go.nSpans; ++i) { const State* t = s->go.span[i].to; if (t && t->link == s) { return true; } } // otherwise no return false; } uint maxDist(State *s) { if (s->depth != cInfinity) { // Already calculated, just return result. return s->depth; } uint mm = 0; for (uint i = 0; i < s->go.nSpans; ++i) { State *t = s->go.span[i].to; if (t) { uint m = 1; if (!t->link) // marked as non-key state { if (t->depth == cInfinity) { t->depth = maxDist(t); } m += t->depth; } if (m > mm) { mm = m; } } } s->depth = mm; return mm; } void calcDepth(State *head) { State* s; // mark non-key states by s->link = NULL ; for (s = head; s; s = s->next) { if (s != head && !state_is_in_non_trivial_SCC(s)) { s->link = NULL; } //else: key state, leave alone } for (s = head; s; s = s->next) { s->depth = cInfinity; } // calculate max number of transitions before guarantied to reach // a key state. for (s = head; s; s = s->next) { maxDist(s); } } void DFA::findSCCs() { SCC scc(nStates); State *s; for (s = head; s; s = s->next) { s->depth = 0; s->link = NULL; } for (s = head; s; s = s->next) { if (!s->depth) { scc.traverse(s); } } calcDepth(head); } void DFA::split(State *s) { State *move = new State; (void) new Move(move); addState(&s->next, move); move->link = s->link; move->rule = s->rule; move->go = s->go; s->rule = NULL; s->go.nSpans = 1; s->go.span = new Span[1]; s->go.span[0].ub = ubChar; s->go.span[0].to = move; } void DFA::findBaseState() { Span *span = new Span[ubChar - lbChar]; for (State *s = head; s; s = s->next) { if (!s->link) { for (uint i = 0; i < s->go.nSpans; ++i) { State *to = s->go.span[i].to; if (to && to->isBase) { to = to->go.span[0].to; uint nSpans = merge(span, s, to); if (nSpans < s->go.nSpans) { delete [] s->go.span; s->go.nSpans = nSpans; s->go.span = new Span[nSpans]; memcpy(s->go.span, span, nSpans*sizeof(Span)); } break; } } } } delete [] span; } void DFA::emit(std::ostream &o, uint ind) { State *s; uint i, bitmap_brace = 0; findSCCs(); head->link = head; uint nRules = 0; for (s = head; s; s = s->next) { s->depth = maxDist(s); if (maxFill < s->depth) { maxFill = s->depth; } if (s->rule && s->rule->accept >= nRules) { nRules = s->rule->accept + 1; } } uint nSaves = 0; uint *saves = new uint[nRules]; memset(saves, ~0, (nRules)*sizeof(*saves)); // mark backtracking points bool bSaveOnHead = false; for (s = head; s; s = s->next) { if (s->rule) { for (i = 0; i < s->go.nSpans; ++i) { if (s->go.span[i].to && !s->go.span[i].to->rule) { delete s->action; s->action = NULL; if (saves[s->rule->accept] == ~0u) { saves[s->rule->accept] = nSaves++; } bSaveOnHead |= s == head; (void) new Save(s, saves[s->rule->accept]); // sets s->action } } } } // insert actions State **rules = new State * [nRules]; memset(rules, 0, (nRules)*sizeof(*rules)); State *accept = NULL; Accept *accfixup = NULL; for (s = head; s; s = s->next) { State * ow; if (!s->rule) { ow = accept; } else { if (!rules[s->rule->accept]) { State *n = new State; (void) new Rule(n, s->rule); rules[s->rule->accept] = n; addState(&s->next, n); } ow = rules[s->rule->accept]; } for (i = 0; i < s->go.nSpans; ++i) { if (!s->go.span[i].to) { if (!ow) { ow = accept = new State; accfixup = new Accept(accept, nRules, saves, rules); addState(&s->next, accept); } s->go.span[i].to = ow; } } } if (accfixup) { accfixup->genRuleMap(); } // split ``base'' states into two parts for (s = head; s; s = s->next) { s->isBase = false; if (s->link) { for (i = 0; i < s->go.nSpans; ++i) { if (s->go.span[i].to == s) { s->isBase = true; split(s); if (bFlag) { BitMap::find(&s->next->go, s); } s = s->next; break; } } } } // find ``base'' state, if possible findBaseState(); delete head->action; head->action = NULL; if (bFlag) { o << indent(ind++) << "{\n"; bitmap_brace = 1; BitMap::gen(o, ind, lbChar, ubChar <= 256 ? ubChar : 256); } bUsedYYAccept = false; uint start_label = next_label; (void) new Initial(head, next_label++, bSaveOnHead); if (bUseStartLabel) { if (startLabelName.empty()) { vUsedLabels.insert(start_label); } } for (s = head; s; s = s->next) { s->label = next_label++; } // 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; for (s = head; s; s = s->next) { bool readCh = false; s->emit(null_dev, ind, readCh); s->go.genGoto(null_dev, ind, s, s->next, readCh); } if (last_fill_index < next_fill_index) { last_fill_index = next_fill_index; } next_fill_index = save_fill_index; // Generate prolog o << "\n" << outputFileInfo; o << indent(ind++) << "{\n"; if (!fFlag) { o << indent(ind) << mapCodeName["YYCTYPE"] << " " << mapCodeName["yych"] << ";\n"; if (bUsedYYAccept) { o << indent(ind) << "unsigned int "<< mapCodeName["yyaccept"] << " = 0;\n"; } } else { o << "\n"; } genGetState(o, ind, start_label); if (vUsedLabels.count(1)) { vUsedLabels.insert(0); o << indent(ind) << "goto " << labelPrefix << "0;\n"; } // Generate code for (s = head; s; s = s->next) { bool readCh = false; s->emit(o, ind, readCh); s->go.genGoto(o, ind, s, s->next, readCh); } // Generate epilog o << indent(--ind) << "}\n"; if (bitmap_brace) { o << indent(--ind) << "}\n"; } // Cleanup if (BitMap::first) { delete BitMap::first; BitMap::first = NULL; } delete [] saves; delete [] rules; bUseStartLabel = false; } void genGetState(std::ostream &o, uint& ind, uint start_label) { if (fFlag && !bWroteGetState) { vUsedLabels.insert(start_label); o << indent(ind) << "switch(" << mapCodeName["YYGETSTATE"] << "()) {\n"; if (bUseStateAbort) { o << indent(ind) << "default: abort();\n"; o << indent(ind) << "case -1: goto " << labelPrefix << start_label << ";\n"; } else { o << indent(ind) << "default: goto " << labelPrefix << start_label << ";\n"; } for (size_t i=0; iget_line() << " \"" << li.fname << "\"\n"; } return o; } uint Scanner::get_line() const { return cline; } void Scanner::config(const Str& cfg, int num) { if (cfg.to_string() == "indent:top") { if (num < 0) { fatal("configuration 'indent:top' must be a positive integer"); } topIndent = num; } else if (cfg.to_string() == "yybm:hex") { yybmHexTable = num != 0; } else if (cfg.to_string() == "startlabel") { bUseStartLabel = num != 0; startLabelName = ""; } else if (cfg.to_string() == "state:abort") { bUseStateAbort = num != 0; } else if (cfg.to_string() == "state:nextlabel") { bUseStateNext = num != 0; } else if (cfg.to_string() == "yyfill:enable") { bUseYYFill = num != 0; } else if (cfg.to_string() == "yyfill:parameter") { bUseYYFillParam = num != 0; } else if (cfg.to_string() == "cgoto:threshold") { cGotoThreshold = num; } else if (cfg.to_string() == "yych:conversion") { if (num) { yychConversion = "("; yychConversion += mapCodeName["YYCTYPE"]; yychConversion += ")"; } else { yychConversion = ""; } } else { fatal("unrecognized configuration name or illegal integer value"); } } static std::set mapVariableKeys; static std::set mapDefineKeys; static std::set mapLabelKeys; void Scanner::config(const Str& cfg, const Str& val) { if (mapDefineKeys.empty()) { mapVariableKeys.insert("variable:yyaccept"); mapVariableKeys.insert("variable:yybm"); mapVariableKeys.insert("variable:yych"); mapVariableKeys.insert("variable:yytarget"); mapDefineKeys.insert("define:YYCTXMARKER"); mapDefineKeys.insert("define:YYCTYPE"); mapDefineKeys.insert("define:YYCURSOR"); mapDefineKeys.insert("define:YYDEBUG"); mapDefineKeys.insert("define:YYFILL"); mapDefineKeys.insert("define:YYGETSTATE"); mapDefineKeys.insert("define:YYLIMIT"); mapDefineKeys.insert("define:YYMARKER"); mapDefineKeys.insert("define:YYSETSTATE"); mapLabelKeys.insert("label:yyFillLabel"); mapLabelKeys.insert("label:yyNext"); } std::string strVal; if (val.len >= 2 && val.str[0] == val.str[val.len-1] && (val.str[0] == '"' || val.str[0] == '\'')) { SubStr tmp(val.str + 1, val.len - 2); unescape(tmp, strVal); } else { strVal = val.to_string(); } if (cfg.to_string() == "indent:string") { indString = strVal; } else if (cfg.to_string() == "startlabel") { startLabelName = strVal; bUseStartLabel = !startLabelName.empty(); } else if (cfg.to_string() == "labelprefix") { labelPrefix = strVal; } else if (mapVariableKeys.find(cfg.to_string()) != mapVariableKeys.end()) { if (bFirstPass && !mapCodeName.insert( std::make_pair(cfg.to_string().substr(sizeof("variable:") - 1), strVal) ).second) { fatal("variable already being used and cannot be changed"); } } else if (mapDefineKeys.find(cfg.to_string()) != mapDefineKeys.end()) { if (bFirstPass && !mapCodeName.insert( std::make_pair(cfg.to_string().substr(sizeof("define:") - 1), strVal) ).second) { fatal("define already being used and cannot be changed"); } } else if (mapLabelKeys.find(cfg.to_string()) != mapLabelKeys.end()) { if (bFirstPass && !mapCodeName.insert( std::make_pair(cfg.to_string().substr(sizeof("label:") - 1), strVal) ).second) { fatal("label already being used and cannot be changed"); } } else { fatal("unrecognized configuration name or illegal string value"); } } } // end namespace re2c