package edu.neu.ccs.demeterf.demfgen; import edu.neu.ccs.demeterf.demfgen.classes.*; import edu.neu.ccs.demeterf.*; import edu.neu.ccs.demeterf.demfgen.ClassHier.InhrtPair; import edu.neu.ccs.demeterf.lib.Cons; import edu.neu.ccs.demeterf.lib.Empty; import edu.neu.ccs.demeterf.lib.List; import edu.neu.ccs.demeterf.lib.ident; import edu.neu.ccs.demeterf.util.Util; import edu.neu.ccs.demeterf.demfgen.traversals.Travs; import edu.neu.ccs.demeterf.demfgen.TypeCollect.UseCollect; /** Generate a JavaCC Parser for the given CDs (included) */ public class ParseGen{ static void p(String s){{ System.err.print(s); }} public static void genParser(List CD, String dir, List inhrt, PackageDef basepkg){ LookDef look = IncludeCDs.maxLookAhead(CD); String prser = "options{ STATIC = false; "+(look.isLook()?"LOOKAHEAD = "+look.look()+";":"")+" }\n"+ "PARSER_BEGIN(TheParser)\n"+ basepkg.parserPackage()+ IncludeCDs.allImports(CD)+Diff.d.parserImport+"\n"+ " public class TheParser{\n"+Diff.d.parserBody+" }\n"+ "PARSER_END(TheParser)\n\n"+Diff.d.parserPreamble+"\n"; UseCollect uses = new UseCollect(); CombStr func = new CombStr(uses,inhrt); List allTypes = IncludeCDs.allTypes(CD); prser += Travs.TheFactory.makeParseGenTrav(func).traverse(allTypes, new YesGen()); UseCollect done = new UseCollect(); while(!uses.isEmpty()){ TypeUse use = uses.top(); uses.pop(); if(!done.has(UseCollect.comp(use))){ done.add(use); prser += toJJProd(DemFGenMain.instantiate(use, allTypes),uses,true,inhrt); } } prser += Preamble.lexer; Util.writeFile("theparser", ".jj", Preamble.header+prser, DemFGenMain.pkgdir(dir,basepkg,true), ""); } static String toJJProd(TypeDef td, TypeCollect tuc, boolean gen, List inhrt){ if(gen || td.typeParams().isEmpty()){ JJProd func = new JJProd(tuc,inhrt); return Travs.TheFactory.makeJJGenTrav(func).traverse(td, new YesGen()); } return ""; } static String strip(String s){ int f = s.indexOf('<'), e = s.lastIndexOf('>'); return s.substring(f+1, e); } // Parsing un-escapes strings... so we need to re-escape them for // the parser generation (javacc) public static String escape(char c){ switch(c){ case '\n':return "\\n"; case '\t':return "\\t"; case '\b':return "\\b"; case '\r':return "\\r"; case '\f':return "\\f"; case '\\':return "\\\\"; case '\'':return "\\\'"; case '\"':return "\\\""; default: return ""+c; } } public static String escape(String s){ char str[] = s.toCharArray(); StringBuffer ret = new StringBuffer(""); for(char c:str)ret.append(escape(c)); return ret.toString(); } // Left for reference static char unescapeChar(String s) { char c = s.charAt(0); if (c == '\\'){ switch (s.charAt(1)) { case 'n': return '\n'; case 't': return '\t'; case 'b': return '\b'; case 'r': return '\r'; case 'f': return '\f'; case '\\': return '\\'; case '\'': return '\''; case '\"': return '\"'; default: return (char)Integer.parseInt(s.substring(1, s.length()), 8); } } return c; } /** This one gets us to the TypeDefs, and combines the resulting parse descriptions into * a single file. Have to be sure to pass the generic use collection to be sure we get * all the type expansions for parse methods. * * Also, we can inline this one separately if needed. */ public static class CombStr extends FC{ TypeCollect genUses; List inhrt; CombStr(TypeCollect gu, List i){ genUses = gu; inhrt = i; } public String combine(TypeDef td){ return ParseGen.toJJProd(td, genUses, false, inhrt); } public String combine(List e){ return ""; } public String combine(EmptyList e){ return ""; } public String combine(Cons c, String f, String r){ return f+"\n"+r; } public String combine(ConsList c, String f, String r){ return f+"\n"+r; } } public static class JJProd extends SumGen{ TypeCollect genUses; List inhrt; JJProd(TypeCollect gu, List i){ super(i); genUses = gu; } void addGenUse(TypeUse tu){ genUses.add(tu); } public String combine(TypeUse tu, ident n, String p, DoGen gen){ if(gen.doParse() && !tu.getTparams().isEmpty()) addGenUse(tu); return ""+n+p; } public String combine(Impl imp){ return ""; } public String combine(EmptyToken e){ return ""; } public String combine(RealToken e, String s){ return "\""+ParseGen.escape(s)+"\""; } public String combine(Bound b){ return ""; } public String combine(NameDef d, ident id, String b){ return ""+id; } public String combine(NameEmpty e){ return ">"; } public String combine(NameCons c, String n, String r){ return ","+n+r; } public String combine(NENameList tl, String n, String e){ return "<"+n+e; } public String combine(DefParams p, String s){ return s; } public String combine(EmptyDefParams e){ return ""; } } static class SumGen extends ProductGen{ SumGen(List i){ super(i); } public String combine(TypeUseEmpty e){ return ">"; } public String combine(TypeUseCons c, ident n, String r){ return combine(c,""+n,r); } public String combine(TypeUseCons c, String n, String r){ return ","+n+r; } public String combine(NETypeUseList tl, String n, String e){ return "<"+n+e; } public String combine(UseParams p, String s){ return s; } public String combine(EmptyUseParams e){ return ""; } public List combine(SubtypeEmpty e){ return List.create(); } // Make the TypeChecker Happy... public List combine(NESubtypeList c, String tu, List r){ return comb(c,tu,r); } public List combine(SubtypeCons c, String tu, List r){ return comb(c,tu,r); } public List comb(ConsList c, String tu, List r){ return r.push("sup = "+methName(tu,"")+"()"); } public DoGen update(ClassDef td, Fields.any f){ return td.getGen(); } public String combine(TypeDef td, DoGen g, ident n, String par, List stl){ if(g.doParse()) return subtypeParse(n,par,stl); return ""; } } static class ProductGen extends FC{ List inhrt; ProductGen(List i){ inhrt = i; } public static String typeMethod(String s){ return s.replaceAll("[,<)>(]","\\"+Diff.d.genericSep); } public StrLTrip.StrTrip combine(Field f, ident n, String t){ return new StrLTrip.StrTrip(t+" "+n, n+" = "+methName(t,"")+"()",""+n); } public String combine(AddToken at, String tok){ return "\""+ParseGen.escape(tok)+"\""; } public String combine(Syntax other){ return ""; } public String combine(TheEOF eof){ return ""; } public StrLTrip combine(FieldList l, StrLTrip.StrTrip tr, StrLTrip tl) { return tl.add(tr.f, tr.a, tr.t); } public StrLTrip combine(FieldList l, String tok, StrLTrip tl) { return tok.length()==0?tl:tl.add(tok); } public StrLTrip combine(List l, StrLTrip.StrTrip tr, StrLTrip tl) { return tl.add(tr.f, tr.a, tr.t); } public StrLTrip combine(List l, String tok, StrLTrip tl) { return tok.length()==0?tl:tl.add(tok); } public StrLTrip combine(Empty e){ return new StrLTrip(); } public StrLTrip combine(FieldEmpty e){ return new StrLTrip(); } public EmptyList combine(EmptyList e){ return e; } public DoGen combine(DoGen g){ return g; } String methName(String n, String par){ return "parse_"+typeMethod(n+par); } String methSig(ident n, String par){ return "public "+n+ClassGen.unlocal(par)+" "+methName(n.toString(), par)+"():{\n"; } String subtypeParse(ident n, String par, List stl){ return (methSig(n,par)+ " "+n+par+" sup = null;"+"\n}{\n"+ "( "+stl.toString(" { return sup; } | \n "," ")+ " { return sup; } )\n}\n"); } public String combine(ClassDef td, DoGen g, ident n, String par, List stl, StrLTrip fs){ if(g.doParse()){ StrLTrip sup = Factory.newTraversalCtx(this) .traverseList_FieldOrSyntax_(ClassHier.superFieldsAndSyntax(td.getTparams().toList(), inhrt, ""+n),g); StrLTrip all = fs.append(sup); if(stl.isEmpty()) return (methSig(n,par)+ all.fieldDefs("")+"}{\n"+ all.assigns.toString("\n"," ")+"\n"+ " { return new "+n+par+"("+all.fNames.toString(",","")+ "); }\n}\n"); return subtypeParse(n,par,stl); } return ""; } } }