001: package ro.infoiasi.donald.compiler.parser;
002:
003: import ro.infoiasi.donald.compiler.cfg.*;
004:
005: import java.io.*;
006: import java.util.*;
007:
008: public class CodeWriter {
009: public String prefix = "SJCC$";
010:
011: public static final int LALR1_PARSER = 0;
012: public static final int LR1_PARSER = 1;
013: public static final int SLR1_PARSER = 2;
014:
015: private String packageName;
016: private List imports;
017: private String actionCode;
018: private String parserCode;
019: private String initCode;
020: private String scanCode;
021: private CFG g;
022: private NonTerminals v;
023: private Terminals t;
024: private NonTerminal s;
025: private Productions p;
026: private Production sp;
027:
028: private String parserClassName = "Parser";
029: private String symbolClassName = "Token";
030:
031: private AbstractLR1Parser lr1Parser;
032:
033: public CodeWriter(ParserSpec spec, int parserType,
034: String _parserClassName, String _symbolClassName) {
035: packageName = spec.getPackageName();
036: imports = spec.getImports();
037: actionCode = spec.getActionCode();
038: parserCode = spec.getParserCode();
039: initCode = spec.getInitCode();
040: scanCode = spec.getScanCode();
041: g = spec.getGrammar();
042: v = g.getNonTerminals();
043: t = g.getTerminals();
044: s = g.getStartSymbol();
045: p = g.getProductions();
046:
047: switch (parserType) {
048: case LALR1_PARSER:
049: lr1Parser = new LALR1Parser(spec);
050: break;
051: case LR1_PARSER:
052: lr1Parser = new LR1Parser(spec);
053: break;
054: case SLR1_PARSER:
055: lr1Parser = new SLR1Parser(spec);
056: break;
057: default:
058: throw new RuntimeException("Unknown LR1 parser type");
059: }
060: lr1Parser.precompute();
061: sp = lr1Parser.getStartProduction();
062:
063: if (_parserClassName != null) {
064: this .parserClassName = _parserClassName;
065: }
066:
067: if (_symbolClassName != null) {
068: this .symbolClassName = _symbolClassName;
069: }
070:
071: }
072:
073: private String pre(String str) {
074: return prefix + parserClassName + "$" + str;
075: }
076:
077: public void generateSymbolClass(PrintWriter out) {
078: generatePackage(out);
079: out.println("public interface " + symbolClassName + " {");
080: Iterator it = g.getTerminals().iterator();
081: while (it.hasNext()) {
082: Terminal a = (Terminal) it.next();
083: out.println("\tint " + a.getName() + " = " + g.getSID(a)
084: + ";");
085: }
086: out.println("}");
087: }
088:
089: public void generateParser(PrintWriter out) {
090: generatePackage(out);
091: generateImports(out);
092: generateParserClass(out);
093: generateActionClass(out);
094: }
095:
096: private void generatePackage(PrintWriter out) {
097: if (packageName != null) {
098: out.println("package " + packageName + ";");
099: out.println();
100: }
101: }
102:
103: private void generateImports(PrintWriter out) {
104: Iterator it = imports.iterator();
105: while (it.hasNext()) {
106: out.println("import " + it.next() + ";");
107: }
108: if (!imports.isEmpty()) {
109: out.println();
110: }
111: }
112:
113: private void generateParserClass(PrintWriter out) {
114: out.println();
115: out.println("public class " + parserClassName
116: + " extends SkeletonLRParser {");
117: out.println("\tpublic " + parserClassName + "() {");
118: out.println("\t\tsuper();");
119: out.println("\t}");
120: out.println();
121: out.println("\tpublic " + parserClassName
122: + "(parser.runtime.Lexer lex) {");
123: out.println("\t\tsuper(lex);");
124: out.println("\t}");
125: out.println();
126: generateProductionTable(out);
127: out.println();
128: generateActionTable(out);
129: out.println();
130: generateGotoTable(out);
131: out.println();
132: out.println("\tprotected " + pre("Actions") + " actionObject;");
133: out.println();
134: out.println("\tprotected void initActions() {");
135: out.println("\t\tactionObject = new " + pre("Actions")
136: + "(this);");
137: out.println("\t}");
138: out.println();
139: out
140: .println("\tpublic final parser.runtime.StackSymbol doAction (");
141: out.println("\t\t\tint action, "
142: + "parser.runtime.SkeletonLRParser parser,");
143: out.println("\t\t\tjava.util.Stack stack"
144: + ") throws java.lang.Exception {");
145: out.println("\t\treturn actionObject." + pre("doAction")
146: + "(action, parser, stack);");
147: out.println("\t}");
148: out.println();
149: out.println("\tpublic int getStartState() {");
150: out.println("\t\treturn " + lr1Parser.getStartState() + ";");
151: out.println("\t}");
152: out.println();
153: out.println("\tpublic int getStartProduction() {");
154: out.println("\t\treturn " + sp.getIndex() + ";");
155: out.println("\t}");
156: out.println();
157: out.println("\tpublic int getEOF() {");
158: out.println("\t\treturn " + t.EOF.getIndex() + ";");
159: out.println("\t}");
160: out.println("\tpublic int getTokenOffset() {");
161: out.println("\t\treturn " + v.count() + ";");
162: out.println("\t}");
163: if (initCode != null) {
164: out.println();
165: out.println("\tpublic int initCode() throws Exception {");
166: out.println(initCode);
167: out.println("\t}");
168: }
169: if (scanCode != null) {
170: out.println();
171: out.println("\tpublic int scan() throws Exception {");
172: out.println(scanCode);
173: out.println("\t}");
174: }
175: if (parserCode != null) {
176: out.println();
177: out.println(parserCode);
178: }
179: out.println("}");
180: }
181:
182: private void generateProductionTable(PrintWriter out) {
183: short[][] table = new short[p.count()][2];
184: Iterator it = p.iterator();
185: while (it.hasNext()) {
186: Production prod = (Production) it.next();
187: table[prod.getIndex()][0] = (short) prod.getLHS()
188: .getIndex();
189: table[prod.getIndex()][1] = (short) prod.getRHS().size();
190: }
191: out.println("\tpublic short[][] getProductionTable() {");
192: out.print("\t\treturn unpackFromStrings(");
193: generateTableAsString(out, table);
194: out.println(");\n\t}");
195: }
196:
197: private void generateActionTable(PrintWriter out) {
198: int n = lr1Parser.getStateNo();
199: short[][] table = new short[n][t.count()];
200: for (int i = 0; i < n; i++) {
201: Iterator it = t.iterator();
202: while (it.hasNext()) {
203: Terminal a = (Terminal) it.next();
204: short action;
205: AbstractLR1Parser.ParseAction pa = lr1Parser.getAction(
206: i, a);
207: if (pa != null) {
208: if (pa.isShiftAction()) {
209: AbstractLR1Parser.ShiftAction sa = (AbstractLR1Parser.ShiftAction) pa;
210: action = (short) (sa.getStateIndex().intValue() + 1);
211: } else {
212: AbstractLR1Parser.ReduceAction ra = (AbstractLR1Parser.ReduceAction) pa;
213: action = (short) (-ra.getProduction()
214: .getIndex() - 1);
215: }
216: } else {
217: action = 0;
218: }
219: table[i][a.getIndex()] = action;
220: }
221: }
222: out.println("\tpublic short[][] getActionTable() {");
223: out.print("\t\treturn unpackFromStrings(");
224: generateTableAsString(out, table);
225: out.println(");\n\t}");
226: }
227:
228: private void generateGotoTable(PrintWriter out) {
229: int n = lr1Parser.getStateNo();
230: short[][] table = new short[n][v.count()];
231: for (int i = 0; i < n; i++) {
232: Iterator it = v.iterator();
233: while (it.hasNext()) {
234: NonTerminal x = (NonTerminal) it.next();
235: table[i][x.getIndex()] = (short) lr1Parser
236: .getGoto(i, x);
237: }
238: }
239: out.println("\tpublic short[][] getGotoTable() {");
240: out.print("\t\treturn unpackFromStrings(");
241: generateTableAsString(out, table);
242: out.println(");\n\t}");
243: }
244:
245: private void generateActionClass(PrintWriter out) {
246: out.println();
247: out.println("class " + pre("Actions") + " {");
248: if (actionCode != null) {
249: out.println();
250: out.println(actionCode);
251: }
252: out.println("\tprivate final " + parserClassName + " parser;");
253: out.println();
254: out.println("\t" + pre("Actions") + "(" + parserClassName
255: + " parser) {");
256: out.println("\t\tthis.parser = parser;");
257: out.println("\t}");
258: out.println("");
259: out.println("\tpublic final parser.runtime.StackSymbol "
260: + pre("doAction") + "(\n\t\t\tint " + pre("action")
261: + ",\n\t\t\tparser.runtime.SkeletonLRParser "
262: + pre("parser") + ",\n\t\t\tjava.util.Stack "
263: + pre("stack") + ") throws java.lang.Exception {");
264: //out.println("\t\tparser.runtime.StackSymbol "+pre("result")+";");
265: out.println();
266: out.println("\t\tswitch (" + pre("action") + ") {");
267: Iterator it = p.iterator();
268: while (it.hasNext()) {
269: Production prod = (Production) it.next();
270: out.println("\t\t\tcase " + prod.getIndex() + ": // "
271: + prod.toString());
272: out.println("\t\t\t{");
273: String resultType = prod.getLHS().getType();
274: if (resultType == null) {
275: resultType = "java.lang.Object";
276: }
277: out.println("\t\t\t\t" + resultType + " RESULT = null;");
278: Word w = prod.getRHS();
279: int j = 0;
280: WordIterator wordIt = w.iterator();
281: while (wordIt.hasNext()) {
282: Symbol sym = (Symbol) wordIt.next();
283: if (!sym.isTerminal()
284: && sym.getName().indexOf("$ACTION") == 0) {
285: int off = w.size() - j - 1;
286: out.println("\t\t\t\t// propagate RESULT from "
287: + sym.getName());
288: String temp = "((parser.runtime.StackSymbol) "
289: + pre("stack") + ".elementAt("
290: + pre("stack") + ".size()-" + off
291: + ")).value";
292: out.println("\t\t\t\tif (" + temp + " != null) {");
293: out.println("\t\t\t\t\tRESULT = " + temp + ";");
294: out.println("\t\t\t\t}");
295: }
296: j++;
297: }
298: SemanticAction sa = prod.getSemanticAction();
299: if (sa != null && sa.getCode() != null
300: && sa.getCode().length() > 0) {
301: Iterator labelIt = sa.getLabels().iterator();
302: while (labelIt.hasNext()) {
303: Label label = (Label) labelIt.next();
304: int off = sa.getOffset() - label.getPosition();
305: String temp = "((parser.runtime.StackSymbol)"
306: + pre("stack") + ".elementAt("
307: + pre("stack") + ".size()-" + off + "))";
308: //out.println("\t\t\t\tint "+label.getName()+
309: // "left = "+temp+".left;");
310: //out.println("\t\t\t\tint "+label.getName()+
311: // "right = "+temp+".right;");
312: String type = label.getSymbol().getType();
313: if (type == null) {
314: type = "java.lang.Object";
315: }
316: out.println("\t\t\t\t" + type + " "
317: + label.getName() + " = (" + type + ")"
318: + temp + ".value;");
319: }
320: out.println(sa.getCode());
321: }
322: if (prod == sp) {
323: out.println("\t\t\t\tparser.doneParsing();");
324: }
325: // ... left and right?
326: out
327: .println("\t\t\t\treturn new parser.runtime.StackSymbol("
328: + g.getSID(prod.getLHS())
329: + " /*"
330: + prod.getLHS().getName() + "*/, RESULT);");
331: out.println("\t\t\t}");
332: }
333: out.println("\t\t\tdefault:");
334: out
335: .println("\t\t\t\tthrow new Exception(\"Invalid action number\");");
336: out.println("\t\t}"); // end switch
337: out.println("\t}"); // end doAction
338: out.println("}");
339: }
340:
341: private void generateTableAsString(PrintWriter out, short[][] sa) {
342: out.println("new String[] {");
343: out.print("\t\t\"");
344: int nchar = 0, nbytes = 0;
345: nbytes += generateEscapedChar(out, (char) (sa.length >> 16));
346: nchar = generateNewline(out, nchar, nbytes);
347: nbytes += generateEscapedChar(out, (char) (sa.length & 0xFFFF));
348: nchar = generateNewline(out, nchar, nbytes);
349: for (int i = 0; i < sa.length; i++) {
350: nbytes += generateEscapedChar(out,
351: (char) (sa[i].length >> 16));
352: nchar = generateNewline(out, nchar, nbytes);
353: nbytes += generateEscapedChar(out,
354: (char) (sa[i].length & 0xFFFF));
355: nchar = generateNewline(out, nchar, nbytes);
356: for (int j = 0; j < sa[i].length; j++) {
357: // contents of string are (value+2) to allow for common -1, 0 cases
358: // (UTF-8 encoding is most efficient for 0<c<0x80)
359: nbytes += generateEscapedChar(out,
360: (char) (2 + sa[i][j]));
361: nchar = generateNewline(out, nchar, nbytes);
362: }
363: }
364: out.print("\" }");
365: }
366:
367: private int generateNewline(PrintWriter out, int nchar, int nbytes) {
368: if (nbytes > 65500) {
369: out.println("\", ");
370: out.print("\t\t\"");
371: return 0;
372: } else if (nchar > 11) {
373: out.println("\" +");
374: out.print("\t\t\"");
375: return 0;
376: } else {
377: return nchar + 1;
378: }
379: }
380:
381: private int generateEscapedChar(PrintWriter out, char c) {
382: StringBuffer escape = new StringBuffer();
383: if (c <= 0xFF) {
384: escape.append(Integer.toOctalString(c));
385: while (escape.length() < 3)
386: escape.insert(0, '0');
387: } else {
388: escape.append(Integer.toHexString(c));
389: while (escape.length() < 4)
390: escape.insert(0, '0');
391: escape.insert(0, 'u');
392: }
393: escape.insert(0, '\\');
394: out.print(escape.toString());
395:
396: if (c == 0) {
397: return 2;
398: } else if (c >= 0x01 && c <= 0x7F) {
399: return 1;
400: } else if (c >= 0x80 && c <= 0x7FF) {
401: return 2;
402: } else {
403: return 3;
404: }
405: }
406: }
|