Template{ protected String expandLine(String line, MacroTable macros)(@ StringBuffer result = new StringBuffer(""); PatternMatcherInput input = new PatternMatcherInput(line); String name,value; int start; for(start=0; // index of next unscanned character of 'line' Main.om.match("%\\$\\[([^]]+)\\]%",input); start=Main.om.endOffset(0)) { result.append(line.substring(start,Main.om.beginOffset(0))); name = Main.om.group(1); value = macros.getValue(name); if(value == null){ System.err.println("undefined macro reference: "+name); value = Main.om.group(0); } result.append(value); } result.append(line.substring(start)); return result.toString(); @) } EntityTemplate { void expand(PrintWriter outfile, ExpansionContext context, MacroTable macros, CmdArgs args) (@ try{ File templateFile = new File(args.getTemplateDir(),get_file()); System.out.println("Expanding Template: "+ templateFile.toString()); BufferedReader template = new BufferedReader(new FileReader(templateFile)); expandText(outfile,template,context,macros); } catch(IOException e){ Main.die(e); } @) protected void expandText(PrintWriter out, BufferedReader in, ExpansionContext context, MacroTable macros) (@ try{ String line; while(null != (line=in.readLine())){ if(Main.om.match("/^\\$define\\s+(\\w+)\\s*(\\S)(.*)\\2/",line)){ String name = Main.om.group(1); String text = Main.om.group(3); macros.define(name,expandLine(text,macros)); continue; } if(Main.om.match("/^\\$forwards/",line)){ expandForwards(out,in,context,macros); continue; } if(Main.om.match("/^\\$includes/",line)){ expandIncludes(out,in,context,macros); continue; } if(Main.om.match("/^\\$methods/",line)){ expandMethods(out,in,context,macros); continue; } out.println(expandLine(line,macros)); } } catch(IOException e){ Main.die(e); } @) protected void expandForwards(PrintWriter out, BufferedReader in, ExpansionContext context, MacroTable mtable) (@ try{ // Collect text of a $forwards segment StringWriter outBuf = new StringWriter(); PrintWriter tempOut = new PrintWriter(outBuf); String line; while(null != (line=in.readLine()) && ! Main.om.match("/^\\$end-forwards/",line)){ tempOut.println(line); } if(line == null){ Main.die("Missing $end-forwards directive"); } tempOut.close(); BufferedReader tempIn = new BufferedReader(new StringReader(outBuf.toString())); tempIn.mark(8*1024); tempOut = null; outBuf = null; Enumeration itr = getForwards(context).elements(); MacroTable macros = new MacroTable(mtable); while(itr.hasMoreElements()){ String classDecl = (String)(itr.nextElement()); macros.define("ExternalClass",classDecl); tempIn.reset(); expandText(out,tempIn,context,macros); } tempIn = null; } catch(IOException e){ Main.die(e); } @) // Return a vector of Strings describing the classes needed a // forward declaration protected abstract Vector getForwards(ExpansionContext context); protected void expandIncludes(PrintWriter out, BufferedReader in, ExpansionContext context, MacroTable mtable) (@ try{ // Collect text of a $includes segment StringWriter outBuf = new StringWriter(); PrintWriter tempOut = new PrintWriter(outBuf); String line; while(null != (line=in.readLine()) && ! Main.om.match("/^\\$end-includes/",line)){ tempOut.println(line); } if(line == null){ Main.die("Missing $end-includes directive"); } tempOut.close(); BufferedReader tempIn = new BufferedReader(new StringReader(outBuf.toString())); tempIn.mark(8*1024); tempOut = null; outBuf = null; Enumeration itr = getIncludes(context).elements(); MacroTable macros = new MacroTable(mtable); while(itr.hasMoreElements()){ String headerFileName = (String)(itr.nextElement()); macros.define("Header",headerFileName); tempIn.reset(); expandText(out,tempIn,context,macros); } tempIn = null; } catch(IOException e){ Main.die(e); } @) protected abstract Vector getIncludes(ExpansionContext context); (@ // Inner classes implementing a dictionary of text segments. // This should be a local class to method, 'expandMethods'. // However because of an apparent bug in the JDK 1.1.5 compiler, // no '.class' file is generated for the nested class, // 'SegmentTable.Entry', a fault found only a run time. class SegmentTable { class Entry { private BufferedReader buffer_ = null; BufferedReader get_buffer() throws IOException { buffer_.reset(); return buffer_; } void set_buffer(String data) throws IOException { buffer_ = new BufferedReader(new StringReader(data)); buffer_.mark(8*1024); } } Entry makeEntry(){ return new Entry(); } private Hashtable table_ = new Hashtable(); // Register an entry under one or more keys. 'keyList' is a // comma separated list of keys. void put(String keyList, Entry entry){ Vector key = Main.om.split("/\\s*,\\s*/",keyList); if(key.size() == 0) Main.die("No tags for alternative method body"); for(int k = 0; k < key.size(); ++k) table_.put(key.elementAt(k),entry); } Entry get(String key){ return (Entry)(table_.get(key)); } boolean contains(String key){ return table_.containsKey(key); } Enumeration keys(){ return table_.keys(); } } @) protected void expandMethods(PrintWriter out, BufferedReader in, ExpansionContext context, MacroTable mtable) (@ try{ // Collect text of $methods segment // This text consists on one default segment and zero or more // alternative segments introduced by an $alt-method directive. // The segments are stored in a hash table. SegmentTable segTable = new SegmentTable(); SegmentTable.Entry segEntry =segTable.makeEntry(); segTable.put("default",segEntry); StringWriter outBuf = new StringWriter(); PrintWriter tempOut = new PrintWriter(outBuf); String line; while(null != (line=in.readLine())){ if(Main.om.match("/^\\$end-methods/",line)){ tempOut.close(); segEntry.set_buffer(outBuf.toString()); outBuf = null; tempOut = null; break; } if(Main.om.match("/^\\$alt-method\\s+(.+)?$/",line)){ tempOut.close(); segEntry.set_buffer(outBuf.toString()); outBuf = new StringWriter(); tempOut = new PrintWriter(outBuf); segEntry = segTable.makeEntry(); segTable.put(Main.om.group(1),segEntry); continue; } tempOut.println(line); } if(line == null) Main.die("Missing $end-methods directive"); // Expand the appropriate text segment for each method Enumeration itr = getMethods(context).elements(); MacroTable macros = new MacroTable(mtable); BufferedReader segIn = null; while(itr.hasMoreElements()){ Method method = (Method)(itr.nextElement()); // Calculate the body version MethodBodyVersion foo = method.get_bodyVersion(); String bodyVersion = null; if(method.get_isStatic()){ bodyVersion = (foo == null) ? "static" : "static-"+foo.get_value(); } else{ bodyVersion = (foo == null) ? "default" : foo.get_value(); } // Locate the text segment indicated by the body version if(segTable.contains(bodyVersion)) segIn = segTable.get(bodyVersion).get_buffer(); else{ System.err.println("Using default version: "+method.name()); segIn = segTable.get("default").get_buffer(); } // Update the macro table macros.define("MethodName",method.name()); macros.define("MethodType",methodType(method)); macros.define("MethodSignature",methodSignature(method)); macros.define("MethodCall",method.call()); macros.define("Return", methodType(method).equals("void") ? "" : "return "); // Expand ! expandText(out,segIn,context,macros); } } catch(IOException e){ Main.die(e); } @) protected abstract String methodSignature(Method method); protected abstract String methodType(Method method); Vector getMethods(ExpansionContext context)(@ return context.collectMethods(); @) } HeaderTemplate{ protected Vector getForwards(ExpansionContext context)(@ return context.collectHeaderForwards(); @) protected Vector getIncludes(ExpansionContext context)(@ return context.collectHeaderIncludes(); @) protected String methodSignature(Method method)(@ return method.sigHeader(); @) protected String methodType(Method method)(@ return method.typeHeader(); @) } ImplTemplate{ protected Vector getForwards(ExpansionContext context) (@ return new Vector(); @) protected Vector getIncludes(ExpansionContext context) (@ return context.collectImplIncludes(); @) protected String methodSignature(Method method)(@ return method.sigImpl(); @) protected String methodType(Method method)(@ return method.typeImpl(); @) } ExpansionContext{ // Header includes are // (a) any non-class type // (b) any class whose TypeUse.needHeader == true // Actually we should be able to visit any DefinedType via TypeUse. // and add in any visited DefinedType for which // TypeUse.needHeader==true Vector collectHeaderIncludes() bypassing Method to HeaderFile { (@ Vector result; @) init (@ result = new Vector(); @) return (@ result; @) around TypeUse (@ if( host.get_needHeader()){ subtraversal.apply(); } @) before HeaderFile (@ result.addElement(host.get_name()); @) } // ImplIncludes are just those classes that were // forward declared in the header file Vector collectImplIncludes() bypassing Method via ClassType to HeaderFile { (@ Vector result; @) init (@ result = new Vector(); @) return (@ result; @) around TypeUse (@ if(! host.get_needHeader()){ subtraversal.apply(); } @) before HeaderFile (@ result.addElement(host.get_name()); @) } Vector collectHeaderForwards() bypassing Method to ClassType { (@ Vector result; @) init (@ result = new Vector(); @) return (@ result; @) around TypeUse (@ if(! host.get_needHeader()){ subtraversal.apply(); } @) before ClassType (@ result.addElement(host.forwardDecl()); @) } Vector collectMethods() bypassing Entity to Method { (@ Vector result; @) init (@ result = new Vector(); @) return (@ result; @) before Method (@ result.addElement(host); @) } } ClassType{ abstract String forwardDecl(); } SimpleClassType{ String forwardDecl()(@ return "class "+get_name().get_value(); @) } TemplatedClassType{ String forwardDecl()(@ return "template "+get_args().get_value()+ " class "+get_name().get_value(); @) } Method { String name()(@ return get_name().get_value(); @) String typeImpl()(@ return get_returnDecl().image(); @) String typeHeader()(@ StringBuffer result = new StringBuffer(""); if(get_isVirtual()) result.append("virtual "); result.append(typeImpl()); return result.toString(); @) String sigImpl()(@ StringBuffer result = new StringBuffer(name()); result.append("("); if(args.size() > 0){ result.append(args.elementAt(0).image()); for(int k=1; k < args.size(); ++k){ result.append(","); result.append(args.elementAt(k).image()); } } result.append(")"); if(get_isConst()) result.append(" const"); return result.toString(); @) String sigHeader()(@ StringBuffer result = new StringBuffer(name()); result.append("("); for(int k=0; k < args.size(); ++k){ if(k > 0) result.append(","); ArgumentDecl arg = args.elementAt(k); result.append(arg.image()); if(arg.get_initializer() != null){ result.append("="); result.append(arg.get_initializer().image()); } } result.append(")"); if(get_isConst()) result.append(" const"); return result.toString(); @) String call()(@ StringBuffer result = new StringBuffer(name()); result.append("("); if(args.size() > 0){ result.append(args.elementAt(0).get_name().get_value()); for(int k = 1; k < args.size(); ++k){ result.append(","); result.append(args.elementAt(k).get_name().get_value()); } } result.append(")"); return result.toString(); @) }