⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 parsergen.cs

📁 c#源代码
💻 CS
字号:
/*-------------------------------------------------------------------------
ParserGen.cs -- Generation of the Recursive Descent Parser
Compiler Generator Coco/R,
Copyright (c) 1990, 2004 Hanspeter Moessenboeck, University of Linz
extended by M. Loeberbauer & A. Woess, Univ. of Linz
with improvements by Pat Terry, Rhodes University

This program is free software; you can redistribute it and/or modify it 
under the terms of the GNU General Public License as published by the 
Free Software Foundation; either version 2, or (at your option) any 
later version.

This program is distributed in the hope that it will be useful, but 
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License 
for more details.

You should have received a copy of the GNU General Public License along 
with this program; if not, write to the Free Software Foundation, Inc., 
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

As an exception, it is allowed to write an extension of Coco/R that is
used as a plugin in non-free software.

If not otherwise stated, any source code generated by Coco/R (other than 
Coco/R itself) does not fall under the GNU General Public License.
-------------------------------------------------------------------------*/
using System;
using System.IO;
using System.Collections;
using System.Text;

namespace at.jku.ssw.Coco {

public class ParserGen {

	const int maxTerm = 3;		// sets of size < maxTerm are enumerated
	const char CR  = '\r';
	const char LF  = '\n';
	const int EOF = -1;

	const int tErr = 0;			// error codes
	const int altErr = 1;
	const int syncErr = 2;
	
	public static Position usingPos; // "using" definitions from the attributed grammar
	// CHANGES BY M.KRUEGER
	public static string productionModifiers = String.Empty;
	//EOC
	
	static int errorNr;				// highest parser error number
	static Symbol curSy;			// symbol whose production is currently generated
	static FileStream fram;		// parser frame file
	static StreamWriter gen;	// generated parser source file
	static StringWriter err;	// generated parser error messages
	static string srcName;    // name of attributed grammar file
	static string srcDir;     // directory of attributed grammar file
	static ArrayList symSet = new ArrayList();
	
	static void Indent (int n) {
		for (int i = 1; i <= n; i++) gen.Write('\t');
	}
	
	// AW: use a switch if more than 5 alternatives and none starts with a resolver
	static bool UseSwitch (Node p) {
		if (p.typ != Node.alt) return false;
		int nAlts = 0;
		while (p != null) {
		  ++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;
	}
	
	static void CopyFramePart (string stop) {
		char startCh = stop[0];
		int endOfStopString = stop.Length-1;
		int ch = fram.ReadByte();
		while (ch != EOF)
			if (ch == startCh) {
				int i = 0;
				do {
					if (i == endOfStopString) return; // stop[0..i] found
					ch = fram.ReadByte(); i++;
				} while (ch == stop[i]);
				// stop[0..i-1] found; continue with last read character
				gen.Write(stop.Substring(0, i));
			} else {
				gen.Write((char)ch); ch = fram.ReadByte();
			}
		Errors.Exception(" -- incomplete or corrupt parser frame file");
	}

	static void CopySourcePart (Position pos, int indent) {
		// Copy text described by pos from atg to gen
		int ch, nChars, i;
		if (pos != null) {
			Buffer.Pos = pos.beg; ch = Buffer.Read(); nChars = pos.len - 1;
// CHANGES BY M.KRUEGER	(#line pragma generation)
			gen.WriteLine();
			gen.WriteLine(String.Format("#line  {0} \"{1}\" ", Buffer.CountLines(pos.beg) + 1, Scanner.fileName));
// EOC
			Indent(indent);
			while (nChars >= 0) {
				while (ch == CR || ch == LF) {  // eol is either CR or CRLF or LF
					gen.WriteLine(); Indent(indent);
					if (ch == CR) { ch = Buffer.Read(); nChars--; }  // skip CR
					if (ch == LF) { ch = Buffer.Read(); nChars--; }  // skip LF
					for (i = 1; i <= pos.col && (ch == ' ' || ch == '\t'); i++) { 
						// skip blanks at beginning of line
						ch = Buffer.Read(); nChars--;
					}
					if (i <= pos.col) pos.col = i - 1; // heading TABs => not enough blanks
					if (nChars < 0) goto done;
				}
				gen.Write((char)ch);
				ch = Buffer.Read(); nChars--;
			}
			done:
			if (indent > 0) gen.WriteLine();
		}
	}

	static void GenErrorMsg (int errTyp, Symbol sym) {
		errorNr++;
		err.Write("\t\t\tcase " + errorNr + ": s = \"");
		switch (errTyp) {
			case tErr: 
				if (sym.name[0] == '"') err.Write(DFA.Escape(sym.name) + " expected");
				else err.Write(sym.name + " expected"); 
				break;
			case altErr: err.Write("invalid " + sym.name); break;
			case syncErr: err.Write("this symbol not expected in " + sym.name); break;
		}
		err.WriteLine("\"; break;");
	}
	
	static int NewCondSet (BitArray s) {
		for (int i = 1; i < symSet.Count; i++) // skip symSet[0] (reserved for union of SYNC sets)
			if (Sets.Equals(s, (BitArray)symSet[i])) return i;
		symSet.Add(s.Clone());
		return symSet.Count - 1;
	}
	
	static 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 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));
			/*
			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 PutCaseLabels (BitArray s) {
		foreach (Symbol sym in Symbol.terminals)
			if (s[sym.n]) gen.Write("case {0}: ", sym.n);
	}
	
	static 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);

// CHANGES BY M.KRUEGER
					//if (isChecked[p.sym.n]) gen.WriteLine("Get();");
					if (isChecked[p.sym.n]) gen.WriteLine("lexer.NextToken();");
//EOC
					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);
// CHANGES BY M.KRUEGER
					//gen.WriteLine("Get();");
					gen.WriteLine("lexer.NextToken();");
//EOC
					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(")) {");
// CHANGES BY M.KRUEGER
					//gen.Write("SynErr({0}); Get();", errorNr);
					gen.Write("SynErr({0}); lexer.NextToken(); ", errorNr);
//EOC
					 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(Symbol.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(Symbol.terminals.Count);
			if (p.up) break;
			p = p.next;
		}
	}
	
	static void GenTokens() {
		foreach (Symbol sym in Symbol.terminals) {
			if (Char.IsLetter(sym.name[0]))
				gen.WriteLine("\tconst int _{0} = {1};", sym.name, sym.n);
		}
	}

	static void GenCodePragmas() {
		foreach (Symbol sym in Symbol.pragmas) {
			gen.WriteLine("\t\t\t\tif (la.kind == {0}) {{", sym.n);
			CopySourcePart(sym.semPos, 4);
			gen.WriteLine("\t\t\t\t}");
		}
	}

	static void GenProductions() {
		foreach (Symbol sym in Symbol.nonterminals) {
			curSy = sym;
			// CHANGES BY M.KRUEGER
			gen.Write("\t" + productionModifiers + " void {0}(", sym.name);
			// OLD VERSION: gen.Write("\tstatic void {0}(", sym.name);
			//EOC
			CopySourcePart(sym.attrPos, 0);
			gen.WriteLine(") {");
			CopySourcePart(sym.semPos, 2);
			GenCode(sym.graph, 2, new BitArray(Symbol.terminals.Count));
			gen.WriteLine("\t}"); gen.WriteLine();
		}
	}
	
	static void InitSets() {
		for (int i = 0; i < symSet.Count; i++) {
			BitArray s = (BitArray)symSet[i];
			gen.Write("\t\t{");
			int j = 0;
			foreach (Symbol sym in Symbol.terminals) {
				if (s[sym.n]) gen.Write("T,"); else gen.Write("x,");
				++j;
				if (j%4 == 0) gen.Write(" ");
			}
			if (i == symSet.Count-1) gen.WriteLine("x}"); else gen.WriteLine("x},");
		}
	}
	
	static void OpenGen(bool backUp) { /* pdt */
		try {
			string fn = srcDir + "Parser.cs"; /* pdt */
			if (File.Exists(fn) && backUp) File.Copy(fn, fn + ".old", true);
			gen = new StreamWriter(new FileStream(fn, FileMode.Create)); /* pdt */
		} catch (IOException) {
			Errors.Exception("-- Cannot generate parser file");
		}
	}

	public static void WriteParser () {
		symSet.Add(Tab.allSyncSets);
		string fr = srcDir + "Parser.frame";
		if (!File.Exists(fr)) {
			if (Tab.frameDir != null) fr = Tab.frameDir.Trim() + Path.DirectorySeparatorChar + "Parser.frame";
			if (!File.Exists(fr)) Errors.Exception("-- Cannot find Parser.frame");
		}
		try {
			fram = new FileStream(fr, FileMode.Open, FileAccess.Read, FileShare.Read);
		} catch (IOException) {
			Errors.Exception("-- Cannot open Parser.frame.");
		}
		OpenGen(true); /* pdt */
		err = new StringWriter();
		foreach (Symbol sym in Symbol.terminals) GenErrorMsg(tErr, sym);
		
		CopyFramePart("-->begin");
		if (!srcName.ToLower().EndsWith("coco.atg")) {
			gen.Close(); OpenGen(false); /* pdt */
		}
		if (usingPos != null) {CopySourcePart(usingPos, 0); gen.WriteLine();}
		CopyFramePart("-->namespace");
		/* AW open namespace, if it exists */
		if (Tab.nsName != null && Tab.nsName.Length > 0) {
			gen.WriteLine("namespace {0} {{", Tab.nsName);
			gen.WriteLine();
		}
		CopyFramePart("-->constants");
		GenTokens(); /* ML 2002/09/07 write the token kinds */
		gen.WriteLine("\tconst int maxT = {0};", Symbol.terminals.Count-1);
		CopyFramePart("-->declarations"); CopySourcePart(Tab.semDeclPos, 0);
		CopyFramePart("-->pragmas"); GenCodePragmas();
		CopyFramePart("-->productions"); GenProductions();
		CopyFramePart("-->parseRoot"); gen.WriteLine("\t\t{0}();", Tab.gramSy.name);
		CopyFramePart("-->initialization"); InitSets();
		CopyFramePart("-->errors"); gen.Write(err.ToString());
		CopyFramePart("$$$");
		/* AW 2002-12-20 close namespace, if it exists */
		if (Tab.nsName != null && Tab.nsName.Length > 0) gen.Write("}");
		gen.Close();
	}
	
	public static void WriteStatistics () {
		Trace.WriteLine();
		Trace.WriteLine("{0} terminals", Symbol.terminals.Count);
		Trace.WriteLine("{0} symbols", Symbol.terminals.Count + Symbol.pragmas.Count +
		                               Symbol.nonterminals.Count);
		Trace.WriteLine("{0} nodes", Node.nodes.Count);
		Trace.WriteLine("{0} sets", symSet.Count);
	}

	public static void Init (string file, string dir) {
		srcName = file;
		srcDir = dir;	
		errorNr = -1;
		usingPos = null;
	}

} // end ParserGen

} // end namespace

⌨️ 快捷键说明

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