tab.cs

来自「全功能c#编译器」· CS 代码 · 共 1,069 行 · 第 1/3 页

CS
1,069
字号
			&& AllNtToTerm();
    if (ok) CheckLL1();
    return ok;
	}

	//--------------- check for circular productions ----------------------
	
	class CNode {	// node of list for finding circular productions
		public Symbol left, right;
	
		public CNode (Symbol l, Symbol r) {
			left = l; right = r;
		}
	}

	static void GetSingles(Node p, ArrayList singles) {
		if (p == null) return;  // end of graph
		if (p.typ == Node.nt) {
			if (p.up || Node.DelGraph(p.next)) singles.Add(p.sym);
		} else if (p.typ == Node.alt || p.typ == Node.iter || p.typ == Node.opt) {
			if (p.up || Node.DelGraph(p.next)) {
				GetSingles(p.sub, singles);
				if (p.typ == Node.alt) GetSingles(p.down, singles);
			}
		}
		if (!p.up && Node.DelNode(p)) GetSingles(p.next, singles);
	}
	
	public static bool NoCircularProductions() {
		bool ok, changed, onLeftSide, onRightSide;
		ArrayList list = new ArrayList();
		foreach (Symbol sym in Symbol.nonterminals) {
			ArrayList singles = new ArrayList();
			GetSingles(sym.graph, singles); // get nonterminals s such that sym-->s
			foreach (Symbol s in singles) list.Add(new CNode(sym, s));
		}
		do {
			changed = false;
			for (int i = 0; i < list.Count; i++) {
				CNode n = (CNode)list[i];
				onLeftSide = false; onRightSide = false;
				foreach (CNode m in list) {
					if (n.left == m.right) onRightSide = true;
					if (n.right == m.left) onLeftSide = true;
				}
				if (!onLeftSide || !onRightSide) {
					list.Remove(n); i--; changed = true;
				}
			}
		} while(changed);
		ok = true;
		foreach (CNode n in list) {
			ok = false; Errors.count++;
			Console.WriteLine("  {0} --> {1}", n.left.name, n.right.name);
		}
		return ok;
	}
	
	//--------------- check for LL(1) errors ----------------------
	
	static void LL1Error(int cond, Symbol sym) {
		Console.Write("  LL1 warning in {0}: ", curSy.name);
		if (sym != null) Console.Write("{0} is ", sym.name);
		switch (cond) {
			case 1: Console.WriteLine(" start of several alternatives"); break;
			case 2: Console.WriteLine(" start & successor of deletable structure"); break;
			case 3: Console.WriteLine(" an ANY node that matches no symbol"); break;
		}
	}
	
	static void CheckOverlap(BitArray s1, BitArray s2, int cond) {
		foreach (Symbol sym in Symbol.terminals) {
			if (s1[sym.n] && s2[sym.n]) LL1Error(cond, sym);
		}
	}
	
	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;
		}
	}

	static void RSlvError(string msg) {
		Console.WriteLine(msg);
	}


	static void CheckResolver(Node p) {
		while (p != null) {
			// check subnodes of current node p
			if ((p.typ == Node.alt || p.typ == Node.iter || p.typ == Node.opt) &&
			    !p.sub.up)
				if (p.sub.typ == Node.rslv) CheckResolver(p.sub.next);
				else CheckResolver(p.sub);
			
			// check current node p
			switch (p.typ) {
				case Node.alt:
					BitArray uncovered = new BitArray(Symbol.terminals.Count);  // first symbols of alternatives without a resolver (not "covered" by a resolver)
					ArrayList coveredList = new ArrayList();  // list of follow symbols of each resolver (these are "covered" by the resolver)
					ArrayList rslvList = new ArrayList();

					// build set of uncovered first symbols & check for misplaced resolvers 
					// (= not at the first n-1 of n conflicting alternatives)
					Node q = p;
					while (q != null) {
						BitArray curCovered;
						if (q.sub.typ == Node.rslv) {
						  // get followers of resolver (these are "covered" by it)
							if (q.sub.next == null) curCovered = curSy.follow;
							else curCovered = First0(q.sub.next, new BitArray(Node.nodes.Count));
							coveredList.Add(curCovered);
							rslvList.Add(q.sub);
							// resolver must "cover" all but the last occurrence of a conflicting symbol
							if (Sets.Intersect(uncovered, curCovered))
								RSlvError("Misplaced resolver at line " + q.sub.line + " will never be evaluated. " +
								          "Place resolver at previous conflicting alternative.");
						} else uncovered.Or(First0(q.sub, new BitArray(Node.nodes.Count)));
						q = q.down;
					}

					// check for obsolete resolvers 
					// (= alternatives starting with resolvers, when there is no conflict)
					BitArray[] covered = (BitArray[]) coveredList.ToArray(typeof(BitArray));
					Node[] rslvs = (Node[]) rslvList.ToArray(typeof(Node));
					for (int i = 0; i < rslvs.Length; ++i) {
						if (!Sets.Intersect(uncovered, covered[i])) 
							RSlvError("Obsolete resolver at line " + rslvs[i].line + ". " +
							          "Neither of the start symbols of the alternative occurs without a resolver.");
						/*
						if (!Sets.Includes(uncovered, covered[i]))
							RSlvError("At least one of the symbols after the resolver at line " + rslvs[i].line + 
							          " does not appear without a resolver. Remove the last resolver covering this symbol.");
						*/
						/*
						if (Sets.Equals(, covered[i]))
							RSlvError("Resolver at line " + rslvArr[i].line + " covers more symbols than necessary.\n" +
							          "Place resolvers only in front of conflicting symbols.");
						*/
					}
					break;
				case Node.iter: case Node.opt:
					if (p.sub.typ == Node.rslv) {
						BitArray fs = First0(p.sub.next, new BitArray(Node.nodes.Count));
						BitArray fsNext;
						if (p.next == null) fsNext = curSy.follow;
						else fsNext = First0(p.next, new BitArray(Node.nodes.Count));
						if (!Sets.Intersect(fs, fsNext)) 
							RSlvError("Obsolete resolver expression (IF ...) at line " + p.sub.line);
					}
					break;
				case Node.rslv:
					RSlvError("Unexpected Resolver in line " + p.line + ". Will cause parsing error.");
					break;
			}
			if (p.up) break; 
			p = p.next;
		}
	}

	public static void CheckLL1() {
		foreach (Symbol sym in Symbol.nonterminals) {
			curSy = sym;
			CheckAlts(curSy.graph);
			CheckResolver(curSy.graph);
		}
	}
	
	//------------- check if every nts has a production --------------------
	
	public static bool NtsComplete() {
		bool complete = true;
		foreach (Symbol sym in Symbol.nonterminals) {
			if (sym.graph == null) {
				complete = false; Errors.count++;
				Console.WriteLine("  No production for {0}", sym.name);
			}
		}
		return complete;
	}
	
	//-------------- check if every nts can be reached  -----------------
	
	static 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 static bool AllNtReached() {
		bool ok = true;
		visited = new BitArray(Symbol.nonterminals.Count);
		visited[gramSy.n] = true;
		MarkReachedNts(gramSy.graph);
		foreach (Symbol sym in Symbol.nonterminals) {
			if (!visited[sym.n]) {
				ok = false; Errors.count++;
				Console.WriteLine("  {0} cannot be reached", sym.name);
			}
		}
		return ok;
	}
	
	//--------- check if every nts can be derived to terminals  ------------
	
	static 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;
	}
	
	public static bool AllNtToTerm() {
		bool changed, ok = true;
		BitArray mark = new BitArray(Symbol.nonterminals.Count);
		// a nonterminal is marked if it can be derived to terminal symbols
		do {
			changed = false;
			foreach (Symbol sym in Symbol.nonterminals)
				if (!mark[sym.n] && IsTerm(sym.graph, mark)) {
					mark[sym.n] = true; changed = true;
				}
		} while (changed);
		foreach (Symbol sym in Symbol.nonterminals)
			if (!mark[sym.n]) {
				ok = false; Errors.count++;
				Console.WriteLine("  {0} cannot be derived to terminals", sym.name);
			}
		return ok;
	}
	
	/*---------------------------------------------------------------------
	  Utility functions
	---------------------------------------------------------------------*/
	
	static int Num(Node p) {
		if (p == null) return 0; else return p.n;
	}
	
	static void PrintSym(Symbol sym) {
		Trace.Write("{0,3} {1,-14} {2}", sym.n, Node.Name(sym.name), Node.nTyp[sym.typ]);
		if (sym.attrPos==null) Trace.Write(" false "); else Trace.Write(" true  ");
		if (sym.typ == Node.nt) {
			Trace.Write("{0,5}", Num(sym.graph));
			if (sym.deletable) Trace.Write(" true  "); else Trace.Write(" false ");
		} else
			Trace.Write("            ");
		Trace.WriteLine("{0,5}", sym.line);
	}

	public static void PrintSymbolTable() {
		Trace.WriteLine("Symbol Table:");
		Trace.WriteLine("------------"); Trace.WriteLine();
		Trace.WriteLine(" nr name          typ  hasAt graph  del   line");
		foreach (Symbol sym in Symbol.terminals) PrintSym(sym);
		foreach (Symbol sym in Symbol.pragmas) PrintSym(sym);
		foreach (Symbol sym in Symbol.nonterminals) PrintSym(sym);
		Trace.WriteLine();
	}
	
	public static void XRef() {
		SortedList tab = new SortedList();
		// collect lines where symbols have been defined
		foreach (Symbol sym in Symbol.nonterminals) {
			ArrayList list = (ArrayList)tab[sym];
			if (list == null) {list = new ArrayList(); tab[sym] = list;}
			list.Add(- sym.line);
		}
		// collect lines where symbols have been referenced
		foreach (Node n in Node.nodes) {
			if (n.typ == Node.t || n.typ == Node.wt || n.typ == Node.nt) {
				ArrayList list = (ArrayList)tab[n.sym];
				if (list == null) {list = new ArrayList(); tab[n.sym] = list;}
				list.Add(n.line);
			}
		}
		// print cross reference list
		Trace.WriteLine();
		Trace.WriteLine("Cross reference list:");
		Trace.WriteLine("--------------------"); Trace.WriteLine();
		foreach (Symbol sym in tab.Keys) {
			Trace.Write("  {0,-12}", Node.Name(sym.name));
			ArrayList list = (ArrayList)tab[sym];
			int col = 14;
			foreach (int line in list) {
				if (col + 5 > 80) {
					Trace.WriteLine();
					for (col = 1; col <= 14; col++) Trace.Write(" ");
				}
				Trace.Write("{0,5}", line); col += 5;
			}
			Trace.WriteLine();
		}
		Trace.WriteLine(); Trace.WriteLine();
	}
	
	public static void SetDDT(string s) {
		s = s.ToUpper();
		foreach (char ch in s) {
			if ('0' <= ch && ch <= '9') ddt[ch - '0'] = true;
			else switch (ch) {
				case 'A' : ddt[0] = true; break; // trace automaton
				case 'F' : ddt[1] = true; break; // list first/follow sets
				case 'G' : ddt[2] = true; break; // print syntax graph
				case 'I' : ddt[3] = true; break; // trace computation of first sets
				case 'J' : ddt[4] = true; break; // print ANY and SYNC sets
				case 'P' : ddt[8] = true; break; // print statistics
				case 'S' : ddt[6] = true; break; // list symbol table
				case 'X' : ddt[7] = true; break; // list cross reference table
				default : break;
			}
		}
	}

	public static void Init () {
		eofSy = new Symbol(Node.t, "EOF", 0);
	}
	
} // end Tab

} // end namespace

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?