001: package fri.patterns.interpreter.parsergenerator.util;
002:
003: import java.util.*;
004: import java.io.*;
005: import fri.patterns.interpreter.parsergenerator.syntax.*;
006:
007: /**
008: This class can be called using SourceGenerator by commandline.
009: <p>
010: Generates Java code that contains empty method bodies for the
011: implementation of a given Syntax. For every rule there will
012: be a method with the name of the nonterminal on the left side
013: and one argument for each symbol on the right side. All arguments
014: are of type Object.
015: The created implementation derives <i>ReflectSemantic</i>.
016: <pre>
017: File in = new File("MySyntax.grammar);
018: String basename = "MySemantic";
019: Writer out = new FileWriter(basename+".java");
020: new SemanticSkeletonGenerator(in, basename, "my.pkg.name", out);
021: // the Java source "my/pkg/name/MySemantic.java" will be generated
022: </pre>
023:
024: @see fri.patterns.interpreter.parsergenerator.semantics.ReflectSemantic
025: @see fri.patterns.interpreter.parsergenerator.util.SourceGenerator
026: @author (c) 2002, Fritz Ritzberger
027: */
028:
029: public class SemanticSkeletonGenerator {
030: private static Hashtable keyWords;
031: private BufferedWriter bw;
032:
033: /**
034: Reads the passed Syntax and turns it into a semantic skeleton implementation.
035: The passed Write will be closed.
036: @param syntax Syntax the semantc is meant for
037: @param className basname of the class to generate (without package)
038: @param pkgName name of package, can be null
039: @param skeletonOutput Writer where Java source should be written to
040: */
041: public SemanticSkeletonGenerator(Syntax syntax, String className,
042: String pkgName, Writer skeletonOutput) throws Exception {
043: if (skeletonOutput instanceof BufferedWriter)
044: bw = (BufferedWriter) skeletonOutput;
045: else
046: bw = new BufferedWriter(skeletonOutput);
047:
048: // start of java file
049: if (pkgName != null && pkgName.length() > 0) {
050: writeLine("package " + pkgName + ";");
051: writeLine();
052: }
053: writeLine("/** ");
054: writeLine(" * IMPLEMENT ME: Semantic skeleton will not be overwritten, generated");
055: writeLine(" * at " + new Date() + "\n");
056: writeLine(" * by fri.patterns.interpreter.parsergenerator.util.SemanticSkeletonGenerator.");
057: writeLine(" */");
058: writeLine();
059: writeLine("import fri.patterns.interpreter.parsergenerator.semantics.ReflectSemantic;");
060: writeLine();
061: writeLine("public class " + className
062: + " extends ReflectSemantic");
063: writeLine("{");
064:
065: Map methods = new Hashtable();
066:
067: // output default method bodies
068: for (int i = 0; i < syntax.size(); i++) {
069: Rule rule = syntax.getRule(i);
070:
071: String nonterminal = rule.getNonterminal();
072:
073: // check if methodname candidate is a Java keyword - refuse when it is
074: checkMethodNameAgainstKeywords(nonterminal); // throws IllegalArgumentException
075:
076: // check if already used, argument types are always Object
077: int countArgs = rule.rightSize();
078: String signature = nonterminal + "(" + countArgs + ")";
079: boolean alreadyHaveMethod = false;
080:
081: write("\t");
082:
083: if (methods.get(signature) != null) {
084: alreadyHaveMethod = true;
085: // already have this method, make comment
086: write("//");
087: }
088:
089: // open method and argument list
090: write("public Object " + nonterminal + "("); // must be public to be found by reflection
091:
092: List args = new ArrayList(countArgs);
093:
094: for (int j = 0; j < rule.rightSize(); j++) {
095: String s = rule.getRightSymbol(j);
096:
097: if (j > 1 || s != null && s.trim().length() > 0)
098: write((j == 1 ? "" : ", ") + "Object "
099: + getValidParamName(s, args, j));
100: }
101: // close argument list
102: writeLine(")");
103:
104: if (alreadyHaveMethod == false) {
105: writeLine("\t{");
106:
107: write("\t\tSystem.err.println(\"" + nonterminal + " (");
108: for (int j = 0; j < args.size(); j++) {
109: write((j == 0 ? "" : ", ") + "'\"+" + args.get(j)
110: + "+\"'");
111: }
112: writeLine(")\");");
113:
114: writeLine("\t\treturn \"" + signature + "\";"); // return name of method
115: writeLine("\t}");
116:
117: methods.put(signature, signature);
118: }
119:
120: writeLine();
121: }
122:
123: // end of java file
124: writeLine();
125: writeLine("}");
126: writeLine();
127:
128: bw.close();
129: }
130:
131: private void writeLine() throws IOException {
132: bw.newLine();
133: }
134:
135: private void writeLine(String line) throws IOException {
136: bw.write(line, 0, line.length());
137: writeLine();
138: }
139:
140: private void write(String s) throws IOException {
141: bw.write(s, 0, s.length());
142: }
143:
144: // Make a compileable parameter name from syntax symbol.
145: // Returns words for standard symbols.
146: private String getValidParamName(String symbol, List argsUntilNow,
147: int position) {
148: String s = SymbolToName.makeIdentifier(symbol, true);
149:
150: if (argsUntilNow.indexOf(s) >= 0)
151: s = s + position;
152:
153: argsUntilNow.add(s);
154:
155: return s;
156: }
157:
158: // Check against Java key words.
159: private void checkMethodNameAgainstKeywords(String method) {
160: if (keyWords == null) {
161: keyWords = new Hashtable();
162: keyWords.put("boolean", "");
163: keyWords.put("byte", "");
164: keyWords.put("short", "");
165: keyWords.put("int", "");
166: keyWords.put("long", "");
167: keyWords.put("char", "");
168: keyWords.put("float", "");
169: keyWords.put("double", "");
170: keyWords.put("abstract", "");
171: keyWords.put("break", "");
172: keyWords.put("case", "");
173: keyWords.put("catch", "");
174: keyWords.put("class", "");
175: keyWords.put("const", "");
176: keyWords.put("continue", "");
177: keyWords.put("default", "");
178: keyWords.put("do", "");
179: keyWords.put("else", "");
180: keyWords.put("extends", "");
181: keyWords.put("false", "");
182: keyWords.put("final", "");
183: keyWords.put("finally", "");
184: keyWords.put("for", "");
185: keyWords.put("goto", "");
186: keyWords.put("if", "");
187: keyWords.put("implements", "");
188: keyWords.put("import", "");
189: keyWords.put("instanceof", "");
190: keyWords.put("interface", "");
191: keyWords.put("native", "");
192: keyWords.put("new", "");
193: keyWords.put("null", "");
194: keyWords.put("package", "");
195: keyWords.put("public", "");
196: keyWords.put("protected", "");
197: keyWords.put("private", "");
198: keyWords.put("return", "");
199: keyWords.put("static", "");
200: keyWords.put("strictfp", "");
201: keyWords.put("super", "");
202: keyWords.put("switch", "");
203: keyWords.put("synchronized", "");
204: keyWords.put("this", "");
205: keyWords.put("throw", "");
206: keyWords.put("throws", "");
207: keyWords.put("transient", "");
208: keyWords.put("true", "");
209: keyWords.put("try", "");
210: keyWords.put("volatile", "");
211: keyWords.put("void", "");
212: keyWords.put("while", "");
213: }
214:
215: if (keyWords.get(method) != null)
216: throw new IllegalArgumentException(
217: "Nonterminal \""
218: + method
219: + "\" is a Java keyword and can not be used as methodname with AbstractSemantic!");
220: }
221:
222: }
|