static string Str(Node p) { StringBuilder s = new StringBuilder(); while (p != null) { if (p.typ == Node.chr) { s.Append((char)p.val); } else if (p.typ == Node.clas) { BitArray set = CharClass.Set(p.val); if (Sets.Elements(set) != 1) { Parser.SemErr("character set contains more than 1 character"); } s.Append((char)Sets.First(set)); } else { Parser.SemErr("comment delimiters may not be structured"); } p = p.next; } if (s.Length == 0 || s.Length > 2) { Parser.SemErr("comment delimiters must be 1 or 2 characters long"); s = new StringBuilder("?"); } return(s.ToString()); }
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"); // happens if an ANY set matches no symbol } 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)); } } }
static void GenCond(BitArray s) { int n = Sets.Elements(s); if (n == 0) { gen.Write("false"); // should never happen } else if (n <= maxTerm) { foreach (Symbol sym in Symbol.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)); } }
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; } } */ } }
static void CheckAlts(Node p) { BitArray s1, s2; while (p != null) { if (p.typ == Node.alt) { Node q = p; s1 = new BitArray(Symbol.terminals.Count); while (q != null) { // for all alternatives s2 = Expected(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) { s1 = Expected(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; } }
// for autocomplete/intellisense // same as GenCond(), but we only notfiy the 'alt' list of alternatives of new members void GenAutocomplete(BitArray s, Node p, int indent, string comment) { if (!GenerateAutocompleteInformation) { return; // we don't want autocomplete information in the parser } if (p.typ == Node.rslv) { return; // if we have a resolver, we don't know what to do (yet), so we do nothing } int c = Sets.Elements(s); if (c == 0) { return; } if (c > maxTerm) { gen.WriteLine("addAlt(set0, {0}); // {1}", NewCondSet(s), comment); } else { gen.Write("addAlt("); if (c > 1) { gen.Write("new int[] {"); } int n = 0; foreach (Symbol sym in tab.terminals) { if (s[sym.n]) { n++; if (n > 1) { gen.Write(", "); } gen.Write(sym.n); // note: we don't need to take sym.inherits or isKind() into account here // because we only want to see alternatives as specified in the parser productions. // So a keyword:indent = "keyword". token spec will produce only an "ident" variant // and not a "keyword" as well as an "ident". } } if (c > 1) { gen.Write("}"); } gen.WriteLine("); // {0}", comment); } Indent(indent); }
public void ShiftWith(BitArray s) { if (Sets.Elements(s) == 1) { typ = Node.chr; sym = Sets.First(s); } else { CharClass c = CharClass.Find(s); if (c == null) { c = new CharClass("#", s); // class with dummy name } typ = Node.clas; sym = c.n; } }
static void SetDecl() { BitArray s; Expect(1); string name = t.val; CharClass c = CharClass.Find(name); if (c != null) { SemErr("name declared twice"); } Expect(8); Set(out s); if (Sets.Elements(s) == 0) { SemErr("character set must not be empty"); } c = new CharClass(name, s); Expect(9); }
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); // assert: if isChecked[p.sym.n] is true, then isChecked contains only p.sym.n 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); int acc = Sets.Elements(p.set); if (tab.terminals.Count == (acc + 1) || (acc > 0 && Sets.Equals(p.set, isChecked))) { // either this ANY accepts any terminal (the + 1 = end of file), or exactly what's allowed here gen.WriteLine("Get();"); } else { GenErrorMsg(altErr, curSy); if (acc > 0) { gen.Write("if ("); GenCond(p.set, p); gen.WriteLine(") Get(); else SynErr({0});", errorNr); } else { gen.WriteLine("SynErr({0}); // ANY node that matches no symbol", errorNr); } } 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(") {"); } 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: s1 = tab.First(p.sub); Indent(indent); gen.Write("if ("); GenCond(s1, p.sub); gen.WriteLine(") {"); 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; } }
void GenCode(Node p, int indent, BitArray isChecked) { Node p2; BitArray s1, s2; while (p != null) { switch (p.typ) { case Node.nt: { // generate a production method call ... Indent(indent); GenAstBuilder(p, indent); gen.Write("{0}{1}(", p.sym.name, PROD_SUFFIX); CopySourcePart(p.pos, 0); // ... with actual arguments gen.WriteLine(");"); break; } case Node.t: { GenSymboltableCheck(p, indent); Indent(indent); // assert: if isChecked[p.sym.n] is true, then isChecked contains only p.sym.n if (isChecked[p.sym.n]) { GenAstBuilder(p, indent); gen.WriteLine("Get();"); } else { GenAutocomplete(p.sym.n, indent, "T"); GenAutocompleteSymboltable(p, indent, "T"); GenAstBuilder(p, indent); gen.WriteLine("Expect({0}); // {1}", p.sym.n, p.sym.name); } break; } case Node.wt: { GenSymboltableCheck(p, indent); Indent(indent); s1 = tab.Expected(p.next, curSy); s1.Or(tab.allSyncSets); int ncs1 = NewCondSet(s1); Symbol ncs1sym = (Symbol)tab.terminals[ncs1]; GenAutocomplete(p.sym.n, indent, "WT"); GenAutocompleteSymboltable(p, indent, "WT"); GenAstBuilder(p, indent); gen.WriteLine("ExpectWeak({0}, {1}); // {2} followed by {3}", p.sym.n, ncs1, p.sym.name, ncs1sym.name); break; } case Node.any: { Indent(indent); int acc = Sets.Elements(p.set); if (tab.terminals.Count == (acc + 1) || (acc > 0 && Sets.Equals(p.set, isChecked))) { // either this ANY accepts any terminal (the + 1 = end of file), or exactly what's allowed here gen.WriteLine("Get();"); } else { GenErrorMsg(altErr, curSy); if (acc > 0) { GenAutocomplete(p.set, p, indent, "ANY"); gen.Write("if ("); GenCond(p.set, p); gen.WriteLine(") Get(); else SynErr({0});", errorNr); } else { gen.WriteLine("SynErr({0}); // ANY node that matches no symbol", errorNr); } } 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); // intellisense p2 = p; Indent(indent); while (p2 != null) { s1 = tab.Expected(p2.sub, curSy); GenAutocomplete(s1, p2.sub, indent, "ALT"); GenAutocompleteSymboltable(p2.sub, indent, "ALT"); p2 = p2.down; } // end intellisense bool useSwitch = UseSwitch(p); if (useSwitch) { gen.WriteLine("switch (la.kind) {"); } p2 = p; while (p2 != null) { s1 = tab.Expected(p2.sub, curSy); if (useSwitch) { PutCaseLabels(s1, indent); gen.WriteLine("{"); } else if (p2 == p) { gen.Write("if ("); GenCond(s1, p2.sub); gen.WriteLine(") {"); } else if (p2.down == null && equal) { Indent(indent); gen.WriteLine("} else {"); } else { Indent(indent); gen.Write("} else if ("); GenCond(s1, p2.sub); gen.WriteLine(") {"); } 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; Node pac = p2; BitArray sac = (BitArray)tab.First(pac); GenAutocomplete(sac, pac, indent, "ITER start"); GenAutocompleteSymboltable(pac, indent, "ITER start"); 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 + 1); GenAutocomplete(sac, pac, 0, "ITER end"); GenAutocompleteSymboltable(pac, indent, "ITER end"); Indent(indent); gen.WriteLine("}"); break; } case Node.opt: s1 = tab.First(p.sub); Indent(indent); GenAutocomplete(s1, p.sub, indent, "OPT"); gen.Write("if ("); GenCond(s1, p.sub); gen.WriteLine(") {"); 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; } }