void CompSync(Node p) { while (p != null && !visited[p.n]) { visited[p.n] = true; if (p.typ == Node.sync) { BitArray s = Expected(p.next, curSy); s[eofSy.n] = true; allSyncSets.Or(s); p.set = s; } else if (p.typ == Node.alt) { CompSync(p.sub); CompSync(p.down); } else if (p.typ == Node.opt || p.typ == Node.iter) CompSync(p.sub); p = p.next; } }
void GenCond(BitArray s, Node p) { if (p.typ == Node.rslv) CopySourcePart(p.pos, 0); else { int n = Sets.Elements(s); if (n == 0) gen.Write("false"); // should never happen else if (n <= maxTerm) foreach (Symbol sym in tab.terminals) { if (s[sym.n]) { gen.Write("la.kind == {0}", sym.n); --n; if (n > 0) gen.Write(" || "); } } else gen.Write("StartOf({0})", NewCondSet(s)); /* if (p.typ == Node.alt) { // for { ... | IF ... | ... } or [ ... | IF ... | ... ] // check resolvers in addition to terminal start symbols of alternatives Node q = p; while (q != null) { if (q.sub.typ == Node.rslv) { gen.Write(" || "); CopySourcePart(q.sub.pos, 0); } q = q.down; } } */ } }
public void SetContextTrans(Node p) { // set transition code in the graph rooted at p while (p != null) { if (p.typ == Node.opt || p.typ == Node.iter) { SetContextTrans(p.sub); } else if (p.typ == Node.alt) { SetContextTrans(p.sub); SetContextTrans(p.down); } if (p.up) break; p = p.next; } }
void CheckRes(Node p, bool rslvAllowed) { while (p != null) { switch (p.typ) { case Node.alt: BitArray expected = new BitArray(terminals.Count); for (Node q = p; q != null; q = q.down) expected.Or(Expected0(q.sub, curSy)); BitArray soFar = new BitArray(terminals.Count); for (Node q = p; q != null; q = q.down) { if (q.sub.typ == Node.rslv) { BitArray fs = Expected(q.sub.next, curSy); if (Sets.Intersect(fs, soFar)) ResErr(q.sub, "Warning: Resolver will never be evaluated. " + "Place it at previous conflicting alternative."); if (!Sets.Intersect(fs, expected)) ResErr(q.sub, "Warning: Misplaced resolver: no LL(1) conflict."); } else soFar.Or(Expected(q.sub, curSy)); CheckRes(q.sub, true); } break; case Node.iter: case Node.opt: if (p.sub.typ == Node.rslv) { BitArray fs = First(p.sub.next); BitArray fsNext = Expected(p.next, curSy); if (!Sets.Intersect(fs, fsNext)) ResErr(p.sub, "Warning: Misplaced resolver: no LL(1) conflict."); } CheckRes(p.sub, true); break; case Node.rslv: if (!rslvAllowed) ResErr(p, "Warning: Misplaced resolver: no alternative."); break; } if (p.up) break; p = p.next; rslvAllowed = false; } }
public Node NewNode(int typ, Symbol sym, int line) { Node node = new Node(typ, sym, line); node.n = nodes.Count; nodes.Add(node); return node; }
public Graph(Node left, Node right) { l = left; r = right; }
//-------------- check if every nts can be reached ----------------- void MarkReachedNts(Node p) { while (p != null) { if (p.typ == Node.nt && !visited[p.sym.n]) { // new nt reached visited[p.sym.n] = true; MarkReachedNts(p.sym.graph); } else if (p.typ == Node.alt || p.typ == Node.iter || p.typ == Node.opt) { MarkReachedNts(p.sub); if (p.typ == Node.alt) MarkReachedNts(p.down); } if (p.up) break; p = p.next; } }
public BitArray First(Node p) { BitArray fs = First0(p, new BitArray(nodes.Count)); if (ddt[3]) { trace.WriteLine(); if (p != null) trace.WriteLine("First: node = {0}", p.n); else trace.WriteLine("First: node = null"); PrintSet(fs, 0); } return fs; }
//--------- check if every nts can be derived to terminals ------------ bool IsTerm(Node p, BitArray mark) { // true if graph can be derived to terminals while (p != null) { if (p.typ == Node.nt && !mark[p.sym.n]) return false; if (p.typ == Node.alt && !IsTerm(p.sub, mark) && (p.down == null || !IsTerm(p.down, mark))) return false; if (p.up) break; p = p.next; } return true; }
Node LeadingAny(Node p) { if (p == null) return null; Node a = null; if (p.typ == Node.any) a = p; else if (p.typ == Node.alt) { a = LeadingAny(p.sub); if (a == null) a = LeadingAny(p.down); } else if (p.typ == Node.opt || p.typ == Node.iter) a = LeadingAny(p.sub); else if (DelNode(p) && !p.up) a = LeadingAny(p.next); return a; }
void GetSingles(Node p, ArrayList singles) { if (p == null) return; // end of graph if (p.typ == Node.nt) { if (p.up || DelGraph(p.next)) singles.Add(p.sym); } else if (p.typ == Node.alt || p.typ == Node.iter || p.typ == Node.opt) { if (p.up || DelGraph(p.next)) { GetSingles(p.sub, singles); if (p.typ == Node.alt) GetSingles(p.down, singles); } } if (!p.up && DelNode(p)) GetSingles(p.next, singles); }
//--------------------------------------------------------------------- // Symbol set computations //--------------------------------------------------------------------- /* Computes the first set for the graph rooted at p */ BitArray First0(Node p, BitArray mark) { BitArray fs = new BitArray(terminals.Count); while (p != null && !mark[p.n]) { mark[p.n] = true; switch (p.typ) { case Node.nt: { if (p.sym.firstReady) fs.Or(p.sym.first); else fs.Or(First0(p.sym.graph, mark)); break; } case Node.t: case Node.wt: { fs[p.sym.n] = true; break; } case Node.any: { fs.Or(p.set); break; } case Node.alt: { fs.Or(First0(p.sub, mark)); fs.Or(First0(p.down, mark)); break; } case Node.iter: case Node.opt: { fs.Or(First0(p.sub, mark)); break; } } if (!DelNode(p)) break; p = p.next; } return fs; }
// use a switch if more than 5 alternatives and none starts with a resolver bool UseSwitch(Node p) { BitArray s1, s2; if (p.typ != Node.alt) return false; int nAlts = 0; s1 = new BitArray(tab.terminals.Count); while (p != null) { s2 = tab.Expected0(p.sub, curSy); // must not optimize with switch statement, if there are ll1 warnings if (Overlaps(s1, s2)) { return false; } s1.Or(s2); ++nAlts; // must not optimize with switch-statement, if alt uses a resolver expression if (p.sub.typ == Node.rslv) return false; p = p.down; } return nAlts > 5; }
public BitArray Expected(Node p, Symbol curSy) { BitArray s = First(p); if (DelGraph(p)) s.Or(curSy.follow); return s; }
int Num(Node p) { if (p == null) return 0; else return p.n; }
// does not look behind resolvers; only called during LL(1) test and in CheckRes public BitArray Expected0(Node p, Symbol curSy) { if (p.typ == Node.rslv) return new BitArray(terminals.Count); else return Expected(p, curSy); }
//----------------- graph printing ---------------------- int Ptr(Node p, bool up) { if (p == null) return 0; else if (up) return -p.n; else return p.n; }
public Node r; // right end of graph = list of nodes to be linked to successor graph #endregion Fields #region Constructors public Graph() { l = null; r = null; }
//------------- check if resolvers are legal -------------------- void ResErr(Node p, string msg) { errors.Warning(p.line, p.pos.col, msg); }
public Node NewNode(int typ, Node sub) { Node node = NewNode(typ, null, 0); node.sub = sub; return node; }
public bool DelAlt(Node p) { return p == null || DelNode(p) && (p.up || DelAlt(p.next)); }
public Graph(Node p) { l = p; r = p; }
//------------ graph deletability check ----------------- public bool DelGraph(Node p) { return p == null || DelNode(p) && DelGraph(p.next); }
void CheckAlts(Node p) { BitArray s1, s2; while (p != null) { if (p.typ == Node.alt) { Node q = p; s1 = new BitArray(terminals.Count); while (q != null) { // for all alternatives s2 = Expected0(q.sub, curSy); CheckOverlap(s1, s2, 1); s1.Or(s2); CheckAlts(q.sub); q = q.down; } } else if (p.typ == Node.opt || p.typ == Node.iter) { if (DelSubGraph(p.sub)) LL1Error(4, null); // e.g. [[...]] else { s1 = Expected0(p.sub, curSy); s2 = Expected(p.next, curSy); CheckOverlap(s1, s2, 2); } CheckAlts(p.sub); } else if (p.typ == Node.any) { if (Sets.Elements(p.set) == 0) LL1Error(3, null); // e.g. {ANY} ANY or [ANY] ANY } if (p.up) break; p = p.next; } }
public bool DelNode(Node p) { if (p.typ == Node.nt) return p.sym.deletable; else if (p.typ == Node.alt) return DelAlt(p.sub) || p.down != null && DelAlt(p.down); else return p.typ == Node.iter || p.typ == Node.opt || p.typ == Node.sem || p.typ == Node.eps || p.typ == Node.rslv || p.typ == Node.sync; }
void CompFollow(Node p) { while (p != null && !visited[p.n]) { visited[p.n] = true; if (p.typ == Node.nt) { BitArray s = First(p.next); p.sym.follow.Or(s); if (DelGraph(p.next)) p.sym.nts[curSy.n] = true; } else if (p.typ == Node.opt || p.typ == Node.iter) { CompFollow(p.sub); } else if (p.typ == Node.alt) { CompFollow(p.sub); CompFollow(p.down); } p = p.next; } }
public bool DelSubGraph(Node p) { return p == null || DelNode(p) && (p.up || DelSubGraph(p.next)); }
void FindAS(Node p) { // find ANY sets Node a; while (p != null) { if (p.typ == Node.opt || p.typ == Node.iter) { FindAS(p.sub); a = LeadingAny(p.sub); if (a != null) Sets.Subtract(a.set, First(p.next)); } else if (p.typ == Node.alt) { BitArray s1 = new BitArray(terminals.Count); Node q = p; while (q != null) { FindAS(q.sub); a = LeadingAny(q.sub); if (a != null) Sets.Subtract(a.set, First(q.down).Or(s1)); else s1.Or(First(q.sub)); q = q.down; } } if (p.up) break; p = p.next; } }
void GenCode(Node p, int indent, BitArray isChecked) { Node p2; BitArray s1, s2; while (p != null) { switch (p.typ) { case Node.nt: { Indent(indent); gen.Write(p.sym.name + "("); CopySourcePart(p.pos, 0); gen.WriteLine(");"); break; } case Node.t: { Indent(indent); if (isChecked[p.sym.n]) gen.WriteLine("Get();"); else gen.WriteLine("Expect({0});", p.sym.n); break; } case Node.wt: { Indent(indent); s1 = tab.Expected(p.next, curSy); s1.Or(tab.allSyncSets); gen.WriteLine("ExpectWeak({0}, {1});", p.sym.n, NewCondSet(s1)); break; } case Node.any: { Indent(indent); gen.WriteLine("Get();"); break; } case Node.eps: break; // nothing case Node.rslv: break; // nothing case Node.sem: { CopySourcePart(p.pos, indent); break; } case Node.sync: { Indent(indent); GenErrorMsg(syncErr, curSy); s1 = (BitArray)p.set.Clone(); gen.Write("while (!("); GenCond(s1, p); gen.Write(")) {"); gen.Write("SynErr({0}); Get();", errorNr); gen.WriteLine("}"); break; } case Node.alt: { s1 = tab.First(p); bool equal = Sets.Equals(s1, isChecked); bool useSwitch = UseSwitch(p); if (useSwitch) { Indent(indent); gen.WriteLine("switch (la.kind) {"); } p2 = p; while (p2 != null) { s1 = tab.Expected(p2.sub, curSy); Indent(indent); if (useSwitch) { PutCaseLabels(s1); gen.WriteLine("{"); } else if (p2 == p) { gen.Write("if ("); GenCond(s1, p2.sub); gen.WriteLine(") {"); } else if (p2.down == null && equal) { gen.WriteLine("} else {"); } else { gen.Write("} else if ("); GenCond(s1, p2.sub); gen.WriteLine(") {"); } s1.Or(isChecked); //if (p2.sub.typ == Node.rslv) GenCode(p2.sub.next, indent + 1, s1); //else GenCode(p2.sub, indent + 1, s1); GenCode(p2.sub, indent + 1, s1); if (useSwitch) { Indent(indent); gen.WriteLine("\tbreak;"); Indent(indent); gen.WriteLine("}"); } p2 = p2.down; } Indent(indent); if (equal) { gen.WriteLine("}"); } else { GenErrorMsg(altErr, curSy); if (useSwitch) { gen.WriteLine("default: SynErr({0}); break;", errorNr); Indent(indent); gen.WriteLine("}"); } else { gen.Write("} "); gen.WriteLine("else SynErr({0});", errorNr); } } break; } case Node.iter: { Indent(indent); p2 = p.sub; gen.Write("while ("); if (p2.typ == Node.wt) { s1 = tab.Expected(p2.next, curSy); s2 = tab.Expected(p.next, curSy); gen.Write("WeakSeparator({0},{1},{2}) ", p2.sym.n, NewCondSet(s1), NewCondSet(s2)); s1 = new BitArray(tab.terminals.Count); // for inner structure if (p2.up || p2.next == null) p2 = null; else p2 = p2.next; } else { s1 = tab.First(p2); GenCond(s1, p2); } gen.WriteLine(") {"); GenCode(p2, indent + 1, s1); Indent(indent); gen.WriteLine("}"); break; } case Node.opt: //if (p.sub.typ == Node.rslv) s1 = tab.First(p.sub.next); //else s1 = tab.First(p.sub); s1 = tab.First(p.sub); Indent(indent); gen.Write("if ("); GenCond(s1, p.sub); gen.WriteLine(") {"); //if (p.sub.typ == Node.rslv) GenCode(p.sub.next, indent + 1, s1); //else GenCode(p.sub, indent + 1, s1); GenCode(p.sub, indent + 1, s1); Indent(indent); gen.WriteLine("}"); break; } if (p.typ != Node.eps && p.typ != Node.sem && p.typ != Node.sync) isChecked.SetAll(false); // = new BitArray(tab.terminals.Count); if (p.up) break; p = p.next; } }