001: package fri.patterns.interpreter.parsergenerator.util;
002:
003: import java.io.*;
004: import java.util.*;
005: import fri.patterns.interpreter.parsergenerator.Token;
006: import fri.patterns.interpreter.parsergenerator.parsertables.*;
007: import fri.patterns.interpreter.parsergenerator.syntax.*;
008: import fri.patterns.interpreter.parsergenerator.syntax.builder.SyntaxBuilder;
009:
010: /**
011: Java source generator. Following code generations are supported:
012: <ul>
013: <li>SemanticSkeleton, code base for a Semantic-implementation of big syntaxes.</li>
014: <li>Turn ParserTables (built from a Syntax) into compileable Java-code (for faster loading).</li>
015: <li>Turn a Syntax object into compileable Java code (for faster loading).</li>
016: </ul>
017: <pre>
018: SYNTAX: java fri.patterns.interpreter.parsergenerator.util.SourceGenerator [semantic|LALR|SLR|LR] file.syntax [file.syntax ...]
019: LALR|SLR|LR: Generates ParserTable implementation(s) of passed grammar file(s).
020: else: Generates Syntax implementation(s) of passed grammar file(s).
021: CAUTION: Files MUST have relative pathes!
022: </pre>
023:
024: @author (c) 2002, Fritz Ritzberger
025: */
026:
027: public abstract class SourceGenerator {
028: /**
029: Generates a semantic skeleton implementation for a given syntax.
030: @param input syntax the semantic is meant for
031: @param className basename of class to generate, semantic will be named className+"Semantic.java"
032: @param pkgName package-name of class to generate
033: */
034: public static void generateSemanticSkeleton(Syntax syntax,
035: String className, String pkgName) throws Exception {
036: String fileName = className + "Semantic.java";
037:
038: String dirName = pkgName != null && pkgName.length() > 0 ? pkgName
039: .replace('.', File.separatorChar)
040: : System.getProperty("user.dir");
041:
042: File out = new File(dirName, fileName);
043:
044: if (out.exists()) {
045: throw new IllegalStateException(
046: "Will not overwrite "
047: + out.getAbsolutePath()
048: + ". Please check the file for implementation and remove it!");
049: } else {
050: new File(dirName).mkdirs(); // ensure directory exists
051: FileWriter fw = new FileWriter(out);
052: new SemanticSkeletonGenerator(syntax, className, pkgName,
053: fw);
054: System.err.println("Wrote semantic skeleton to file: "
055: + out);
056: }
057: }
058:
059: /**
060: Generates Java code from parser tables. makes the output filename and calls <i>parserTables.toSourceFile()</i> then.
061: @param parserTables ParserTables for which the source should stand
062: @param className basename of class to generate
063: @param pkgName name of package of class to generate, can be null
064: */
065: public static void generateParserTable(
066: AbstractParserTables parserTables, String className,
067: String pkgName) throws Exception {
068: String fullName = (pkgName != null ? pkgName + "." : "")
069: + className;
070: parserTables.toSourceFile(fullName);
071: }
072:
073: /**
074: Generates a Java implementation from the passed Syntax object.
075: @param syntax Syntax to convert to Java code.
076: @param className basename of class to generate
077: @param pkgName name of package of class to generate
078: */
079: public static void generateSyntaxImpl(Syntax syntax,
080: String className, String pkgName, List initialNonterminals)
081: throws IOException {
082: String origClsName = className;
083: className = className + "Syntax";
084: String fileName = (pkgName != null ? pkgName + "." + className
085: : className);
086: fileName = fileName.replace('.', File.separatorChar) + ".java";
087: Writer f = new BufferedWriter(new FileWriter(fileName));
088:
089: if (pkgName != null)
090: fwrite("package " + pkgName + ";\n\n", f);
091:
092: fwrite("/**\n", f);
093: fwrite(" * DO NOT EDIT - Syntax generated from " + origClsName
094: + ".syntax\n", f);
095: fwrite(" * at " + new Date() + "\n", f);
096: fwrite(
097: " * by fri.patterns.interpreter.parsergenerator.util.SourceGenerator.\n",
098: f);
099: fwrite(" */\n\n", f);
100:
101: fwrite(
102: "import fri.patterns.interpreter.parsergenerator.syntax.*;\n\n",
103: f);
104: fwrite("public final class " + className + " extends Syntax\n",
105: f); // class definition
106: fwrite("{\n", f);
107:
108: for (int i = 0; i < initialNonterminals.size(); i++)
109: // define String constants for every nonterminal
110: fwrite(" public static final String "
111: + initialNonterminals.get(i) + " = \""
112: + initialNonterminals.get(i) + "\";\n", f);
113: fwrite("\n", f);
114:
115: fwrite(" public " + className + "() {\n", f); // constructor
116: fwrite(" super(" + syntax.size() + ");\n\n", f);
117: fwrite(" Rule rule;\n", f);
118:
119: for (int i = 0; i < syntax.size(); i++) {
120: Rule rule = syntax.getRule(i);
121: String nt = rule.getNonterminal();
122: if (initialNonterminals.indexOf(nt) < 0) // have not been defined as String constant
123: nt = "\"" + nt + "\"";
124: fwrite("\n rule = new Rule(" + nt + ", "
125: + rule.rightSize() + "); // " + i + "\n", f);
126:
127: for (int j = 0; j < rule.rightSize(); j++) {
128: String rightSymbol = rule.getRightSymbol(j);
129: if (Token.isTerminal(rightSymbol))
130: fwrite(" rule.addRightSymbol(\""
131: + SyntaxUtil
132: .maskQuoteAndBackslash(rightSymbol)
133: + "\");\n", f);
134: else if (initialNonterminals.indexOf(rightSymbol) >= 0) // have been defined as String constants
135: fwrite(" rule.addRightSymbol(" + rightSymbol
136: + ");\n", f);
137: else
138: fwrite(" rule.addRightSymbol(\"" + rightSymbol
139: + "\");\n", f);
140: }
141: fwrite(" addRule(rule);\n", f);
142: }
143: fwrite(" }\n", f);
144: fwrite("}\n", f);
145:
146: f.close();
147: System.err.println("Generated Syntax source file: " + fileName);
148: }
149:
150: private static void fwrite(String line, Writer f)
151: throws IOException {
152: f.write(line, 0, line.length());
153: }
154:
155: private SourceGenerator() {
156: } // do not instantiate
157:
158: /** Source generator main. Writes syntax to stderr when launched with no arguments or -h. */
159: public static void main(String[] args) {
160: if (args.length <= 0 || args[0].startsWith("-h")) {
161: System.err
162: .println("SYNTAX: java "
163: + SourceGenerator.class.getName()
164: + " [semantic|LALR|SLR|LR] file.syntax [file.syntax ...]");
165: System.err
166: .println(" LALR|SLR|LR: Generates ParserTable implementation(s) of passed grammar file(s).");
167: System.err
168: .println(" else: Generates syntax implementation(s) of passed grammar file(s).");
169: System.err
170: .println(" CAUTION: Files MUST have relative pathes!");
171: System.exit(1);
172: } else {
173: String type = args[0].equals("SLR") || args[0].equals("LR")
174: || args[0].equals("LALR") ? args[0] : null;
175: boolean semantic = args[0].equals("semantic");
176: int i = (type != null || semantic) ? 1 : 0;
177:
178: for (; i < args.length; i++) {
179: File f = new File(args[i]);
180:
181: if (f.exists() == false || f.isFile() == false
182: || f.canRead() == false) {
183: System.err
184: .println("ERROR: Can not open syntax specification: "
185: + f);
186: } else {
187: if (f.getAbsolutePath().equals(f.getPath())) {
188: throw new IllegalArgumentException(
189: "File MUST have relative path (to make package name): "
190: + f);
191: }
192:
193: String clsName = f.getName(); // make class name
194: int idx = clsName.indexOf("."); // cut extension
195: if (idx > 0)
196: clsName = clsName.substring(0, idx);
197:
198: String pkgName = f.getParent(); // make package name
199: if (pkgName != null) {
200: if (pkgName.endsWith(File.separator))
201: pkgName = pkgName.substring(0, pkgName
202: .length() - 1);
203: pkgName = pkgName.replace(File.separatorChar,
204: '.');
205: }
206:
207: try {
208: SyntaxBuilder builder = new SyntaxBuilder(
209: new File(args[i]));
210: if (semantic) {
211: Syntax syntax = builder.getParserSyntax();
212: generateSemanticSkeleton(syntax, clsName,
213: pkgName);
214: } else if (type != null) {
215: Syntax syntax = builder.getParserSyntax();
216: AbstractParserTables pt = type
217: .equals("SLR") ? new SLRParserTables(
218: syntax)
219: : type.equals("LR") ? new LRParserTables(
220: syntax)
221: : new LALRParserTables(
222: syntax);
223: generateParserTable(pt, clsName, pkgName);
224: } else {
225: Syntax syntax = builder.getSyntax();
226: generateSyntaxImpl(syntax, clsName,
227: pkgName, builder
228: .getInitialNonterminals());
229: }
230: } catch (Exception e) {
231: e.printStackTrace();
232: }
233: }
234: }
235: }
236: }
237:
238: }
|