001: // This file is part of KeY - Integrated Deductive Software Design
002: // Copyright (C) 2001-2007 Universitaet Karlsruhe, Germany
003: // Universitaet Koblenz-Landau, Germany
004: // Chalmers University of Technology, Sweden
005: //
006: // The KeY system is protected by the GNU General Public License.
007: // See LICENSE.TXT for details.
008: //
009: //
010:
011: package de.uka.ilkd.key.util.make;
012:
013: import java.io.ByteArrayOutputStream;
014: import java.io.File;
015: import java.io.FileInputStream;
016: import java.io.FileOutputStream;
017: import java.util.HashSet;
018:
019: public class GenericParser {
020:
021: /** .gjava directory */
022: public static String genericPath = "./de/uka/ilkd/key/collection/";
023:
024: /** The generated makefile will write the names of generated
025: * java files into this file */
026: public static String compileListFileName;
027:
028: /** the existing java classes with its dividers.
029: * The value of genClass[i].length has to be equal to
030: * the amount of templates.
031: */
032: public static String[][] genClass = { { "HashMapFrom", "To" },
033: { "ListOf" }, { "SLListOf" }, { "SetOf" },
034: { "SetAsListOf" }, { "IteratorOf" }, { "MapFrom", "To" },
035: { "EntryOf", "And" }, { "MapAsListFrom", "To" },
036: { "ArrayOf", "Ext", "In" }, { "VectorOf" }, { "HeapOf" },
037: { "LeftistHeapOf" }, { "SimpleStackOf" } };
038:
039: /** dependencies as the .gjava-file (same position as above)
040: * if you write <name>%<nr> the %<nr> will be replaced with the nr-th
041: * template (nr<=9) e.g. IteratorOf%1 becomes IteratorOfString if it is
042: * a dependency of SetOfString
043: */
044: public static String[][] dep = {
045: { "HashMapFrom<S>To<T>.gjava", "IteratorOf%1.java" },//,"IteratorOf%2.java"},
046: { "ListOf<T>.gjava", "IteratorOf%1.java" },
047: { "SLListOf<T>.gjava", "ListOf%1.java" },
048: { "SetOf<T>.gjava" },
049: { "SetAsListOf<T>.gjava", "SetOf%1.java", "SLListOf%1.java" },
050: { "IteratorOf<T>.gjava" },
051: { "MapFrom<S>To<T>.gjava" },
052: { "EntryOf<S>And<T>.gjava" },
053: { "MapAsListFrom<S>To<T>.gjava", "MapFrom%1To%2.java",
054: "SLListOfEntryOf%1And%2.java",
055: "EntryOf%1And%2.java",//"SLListOf%1.java","SLListOf%2.java", disabled
056: // because of distributed packages
057: "IteratorOfEntryOf%1And%2.java" },
058: { "ArrayOf<S>.gjava" },
059: { "VectorOf<T>.gjava", "IteratorOf%1.java" },
060: { "HeapOf<T>.gjava", "IteratorOf%1.java" },
061: { "LeftistHeapOf<T>.gjava", "HeapOf%1.java" },
062: { "SimpleStackOf<T>.gjava", "IteratorOf%1.java" } };
063:
064: public static String generatedSrcPath;
065:
066: // Hashes rules that have been created
067: private static HashSet ruleSet = new HashSet();
068:
069: // STATIC METHODS
070:
071: public static String parse(String parseStr) {
072: GenericParser gp = new GenericParser();
073: String path = getPath(parseStr);
074: if (path.equals("")) {
075: path = "./";
076: }
077:
078: String className = getClassName(parseStr);
079: Template top = gp.start(className);
080: String[] depend = dependencies(top, path);
081: String makeStr = createMakefileEntry(top, path);
082:
083: for (int i = 1; i < depend.length; i++) {// create Makefile entry for
084: // dependencies (generic ones only)
085: makeStr += parse(depend[i]);
086: }
087:
088: // if this generic build up on other generic file
089: // create a makefile entry for them too
090: for (int i = 0; i < top.size(); i++) {
091: makeStr += parse(path + top.template(i).toString());
092: }
093: if (!makeStr.equals("")) {
094: System.out.print(".");
095: }
096: return makeStr;
097: }
098:
099: // MAIN - MAIN - MAIN - MAIN - MAIN - MAIN
100: /** run parser and create makestr */
101: public static void main(String[] args) {
102: generatedSrcPath = args[0];
103: if (!generatedSrcPath.endsWith("/")) {
104: generatedSrcPath = generatedSrcPath + "/";
105: }
106: File genericMakefile = new File(args[1]);
107: compileListFileName = args[2];
108: ruleSet = new MakefileReader(genericMakefile).getRules();
109: ByteArrayOutputStream bos = new ByteArrayOutputStream();
110: try {
111: if (genericMakefile.exists()) {
112: FileInputStream fr = new FileInputStream(
113: genericMakefile);
114: int chr = fr.read();
115: while (chr != -1) {
116: bos.write(chr);
117: chr = fr.read();
118: }
119: bos.write((byte) '\n');
120: }
121: if (args.length > 1) {
122: System.out.print("[creating Makefile entries ");
123: }
124: for (int i = 3; i < args.length; i++) {
125: bos.write(parse(args[i]).getBytes());
126: }
127: FileOutputStream fw = new FileOutputStream(genericMakefile);
128: bos.writeTo(fw);
129: fw.close();
130: } catch (Exception e) {
131: System.out.println("File operation failed: " + e);
132: }
133: System.out.println(" READY]");
134: }
135:
136: /** creates a single Makefile entry */
137: public static String createMakefileEntry(Template t, String path) {
138: if (t.id() == -1) { // no generic file
139: return "";
140: }
141: // first get rule
142: String tmpPath = path + t.toString() + ".java";
143: String makeStr = tmpPath + ": " + generatedSrcPath + tmpPath
144: + ";\n";
145: makeStr += generatedSrcPath + path
146: + makeRule(t.toString(), dependencies(t, path));
147: if (!ruleSet.contains(path + t.toString() + ".java")) {
148: ruleSet.add(path + t.toString() + ".java");
149: // append make generic action
150: makeStr += "\n" + makeAction(t, path) + "\n";
151: // append move name of created .java file to compileListFileName
152:
153: // handle special extension of ArrayOf (delete Ext...)
154: String fileName = t.toString();
155: if (t.id() == matchGenClass("ArrayOf")) {
156: fileName = fileName.substring(0, fileName
157: .indexOf("Ext"));
158: }
159: if (path.startsWith("./")) {
160: path = path.substring(2);
161: }
162: makeStr += "\t@echo " + generatedSrcPath + path + ""
163: + fileName + ".java >>" + compileListFileName
164: + "\n";
165: } else {
166: makeStr = "";
167: }
168: return makeStr;
169: }
170:
171: /** create dependencies */
172: public static String[] dependencies(Template t, String path) {
173: if (t.id() == -1) {
174: return new String[0];
175: }
176: String[] deps = new String[dep[t.id()].length];
177: for (int i = 0; i < dep[t.id()].length; i++) {
178: deps[i] = (i == 0 ? genericPath : path);
179: deps[i] += replace(dep[t.id()][i], t);
180: }
181:
182: return deps;
183: }
184:
185: /** create rule */
186: public static String makeRule(String pattern, String[] dep) {
187: String depStr = "";
188: for (int i = 0; i < dep.length; i++) {
189: depStr += (i == 0 ? "" : generatedSrcPath) + dep[i] + " ";
190: }
191:
192: return pattern + ".java" + ": " + depStr;
193: }
194:
195: /** create action */
196: public static String makeAction(Template t, String path) {
197: StringBuffer action = new StringBuffer("\t@");
198: action.append(genericPath + dep[t.id()][0]); // calls .gjava script
199:
200: StringBuffer pck = new StringBuffer(path); // the package name
201: replaceAll(pck, "/", ".");
202: if (pck.charAt(pck.length() - 1) == '.') {
203: pck.delete(pck.length() - 1, pck.length());
204: }
205: action.append(" " + pck + " ");
206:
207: // creates : path/<file>.gjava packagename template1 t2 ...
208: for (int i = 0; i < t.size(); i++) {
209: action.append(" " + t.template(i));
210: }
211:
212: // adds created .gjava created file to a container
213: // for (int i=0;i<t.size();i++) {
214: // action.append(" "+t.template(i)+" ");
215: // }
216:
217: // the char < has to be declared as \<
218: replaceAll(action, "<", "\\<");
219: replaceAll(action, ">", "\\>");
220:
221: return action.toString();
222: }
223:
224: /** gets path */
225: public static String getPath(String file) {
226: File f = new File(file);
227: String path = f.getPath(); // path/<name>.java
228: return path.substring(0, path.lastIndexOf('/') + 1); // skip <name>.java
229: }
230:
231: /** get name of class (filename without suffix) */
232: public static String getClassName(String file) {
233: File f = new File(file);
234: String name = f.getName();
235: if (name.lastIndexOf('.') >= 0) {
236: return name.substring(0, name.lastIndexOf('.')); // skip .java
237: }
238: return name;
239: }
240:
241: /** replace all occurrences of search in sb with repl */
242: public static void replaceAll(StringBuffer sb, String search,
243: String repl) {
244: int idx = 0;
245: int add = 0;
246: String sbStr = sb.toString();
247: while ((idx = sbStr.indexOf(search, idx)) != -1) {
248: int start = idx + add;
249: int end = idx + search.length() + add;
250: end = (end >= sb.length() ? sb.length() : end);
251: sb.replace(start, end, repl);
252: add += repl.length() - search.length();
253: idx += add + 1;
254: }
255: }
256:
257: /** replace char at position pos with pos+len in str with replaceStr
258: * @param str String to be edited
259: * @param pos int the position
260: * @param len int the len of the substring being replaced
261: * @param replaceStr the String we put at pos in str
262: */
263: public static String replace(String str, int pos, int len,
264: String replaceStr) {
265: return str.substring(0, pos) + replaceStr
266: + str.substring(pos + len);
267: }
268:
269: /** @param String str the String we want to replace %nr
270: * @param Template tpl the corresponding template
271: * @return str replace took place
272: */
273: public static String replace(String str, Template tpl) {
274: String replaced = str;
275: int occur = 0;
276: int value = 0;
277: while ((occur = replaced.indexOf('%')) != -1) {
278: value = Integer.valueOf("" + replaced.charAt(occur + 1))
279: .intValue() - 1;
280: replaced = replace(replaced, occur, 2, tpl.template(value)
281: .toString());
282: occur += 2;
283: }
284: return replaced;
285: }
286:
287: // DYNAMIC PART STARTS HERE
288:
289: /** @return number of different generic classes */
290: private static int genSize() {
291: return genClass.length;
292: }
293:
294: /** @return template that fits for the op-represented type */
295: private static int matchGenClass(String op) {
296: int i = 0;
297: while (i < genSize()) {
298: if (op.startsWith(genClass[i][0])) {
299: return i;
300: }
301: i++;
302: }
303: return -1;
304: }
305:
306: /** @return String representation of the next expected separator */
307: private String nextExpectedSep(Template child) {
308: Template tpl = child;
309: while (tpl.hasParent() && tpl.nextSep().equals("")) {
310: // look for next sep
311: tpl = tpl.parent();
312: }
313: return tpl.nextSep();
314: }
315:
316: private Template parse(String rest, Template parent) {
317: // rest=A(<SEP>B)
318: // extract A
319: // split
320: // look left side is it generic
321: Template top = null;
322: Template child = null;
323: int childID = matchGenClass(rest);
324: if (childID == -1 && parent == null) { // no generic class at top level
325: return new Template(childID, "", null);
326: } else if (childID == -1) { // A is not generic type lets extract A
327: String sep = nextExpectedSep(parent);
328: if (sep.equals("")) { // case rest=A
329: top = new Template(childID, rest, parent);
330: } else { // case rest=A<SEP>B
331: int idx = rest.indexOf(sep);
332: top = new Template(childID, rest.substring(0, idx),
333: parent);
334: }
335: } else { // A is a generic type
336: top = new Template(childID, genClass[childID][0], parent);
337: // parse A
338: child = parse(
339: rest.substring(genClass[childID][0].length()), top);
340: top.add(child);
341: // parseB
342:
343: String newRest = rest.substring(top.type().length());
344: for (int i = 1; i < top.size(); i++) {
345: int sepLen = top.sep(top.indexOfSep() - 1).length();
346: int newRestStartsAtIdx = child.toString().length()
347: + sepLen;
348: newRest = newRest.substring(newRestStartsAtIdx);
349: if (!newRest.equals("")) {
350: child = parse(newRest, top);
351: top.add(child);
352: }
353:
354: }
355: }
356:
357: return top;
358: }
359:
360: private Template start(String str) {
361: return parse(str, null);
362: }
363:
364: class Template {
365: private int id;
366: private String type;
367: private Template parent;
368: private Template[] tpl;
369: private int idx;
370: private int indexOfSep;
371:
372: Template() {
373: id = -1;
374: parent = null;
375: type = "";
376: tpl = null;
377: idx = 0;
378: indexOfSep = 0;
379: }
380:
381: Template(int id, String type, Template parent) {
382: this ();
383: this .id = id;
384: this .type = type;
385: this .parent = parent;
386: tpl = new Template[(id == -1 ? 0 : genClass[id].length)];
387: }
388:
389: String nextSep() {
390: return sep(indexOfSep());
391: }
392:
393: int indexOfSep() {
394: return indexOfSep;
395: }
396:
397: int sep() {
398: return genClass[id].length - 1;
399: }
400:
401: String sep(int i) {
402: if (i < sep()) {
403: return genClass[id][i + 1];
404: }
405: return "";
406: }
407:
408: Template parent() {
409: return parent;
410: }
411:
412: boolean hasParent() {
413: return parent != null;
414: }
415:
416: void add(Template t) {
417: tpl[idx] = t;
418: indexOfSep++;
419: idx++;
420: }
421:
422: int size() {
423: return tpl.length;
424: }
425:
426: int id() {
427: return id;
428: }
429:
430: Template template(int i) {
431: return tpl[i];
432: }
433:
434: String type() {
435: return type;
436: }
437:
438: public String toString() {
439: String str = type();
440: if (size() == 0) {
441: return str;
442: }
443: str += template(0);
444: for (int i = 1; i < size(); i++) {
445: if (size() > 1) {
446: str += genClass[id()][i];
447: }
448: str += template(i);
449: }
450: return str;
451: }
452:
453: }
454:
455: }
|