Package AGEvalSwipl

Source Code of AGEvalSwipl.FlatCppGenerator

package AGEvalSwipl;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Map.Entry;
import java.util.Vector;

import jpl.Term;
import jpl.Variable;
import AGEval.AGEvaluator;
import AGEval.Class;
import AGEval.InvalidGrammarException;
import AGEvalSwipl.AGEvaluatorSwipl.Schedule;
import AGEvalSwipl.FlatCppFieldsHelper.Field;
import aleGrammar.ALEParser;
import aleGrammar.ALEParser.Assignment;

public class FlatCppGenerator implements Backend {
  static final String aleactions_filename = "aleactions.h";
  static final String fields_header_filename = "clustered_tree_generated_fields.h";
  static final String parse_body_filename = "clustered_tree_generated_parse.cpp";
  static final String unionvariants_filename = "unionvariants.h";
  static final String visit_header_filename = "clustered_tree_generated_visit.h";
  static final String visit_body_filename = "clustered_tree_generated_visit.cpp";
 
  private static final String generated_warning_header = "// Generated code. Modifcation to this file will be lost on next generation.\n\n";

  private FlatCppFieldsHelper fields;
  private Schedule sched;

  public static void main(String[] args) throws NumberFormatException, Exception {
    if (args.length == 7) {
      synthesizeFlatCpp(args[1], args[2], args[0], false, new Boolean(args[3]).booleanValue(), new Boolean(
          args[4]).booleanValue(), new Boolean(args[5]).booleanValue(), new Integer(args[6]).intValue());
    } else {
      System.err.println("Arg 0: resource dir (where to fine algorithm.pl");
      System.err.println("Arg 1: grammar path");
      System.err.println("Arg 2: output path");
      System.err.println("Arg 3: allow all child orderings?");
      System.err.println("Arg 4: use first parallel (vs. /variants subdirs)");
      System.err.println("Arg 5: exhaustive or greedy (first prefix)?");
      System.err.println("Arg 6: max length of traversal sequence");
      throw new Exception("Wrong number of arguments");
    }
  }

  // Bootstrap the Generator to use this backend
  public static void synthesizeFlatCpp(String alePath, String outputDir, String resourceDir, boolean verbose,
      boolean isFixedChildOrder, boolean useFirstParallel, boolean isExhaustive, int maxLen) throws Exception {
    System.err.println("Setup for Flat C++ build: ");
    System.err.println("  Grammar: " + alePath);
    System.err.println("  Return first found: " + useFirstParallel);
    System.err.println("  Fixed child orders (lexical): " + isFixedChildOrder);
    System.err.println("  Include non-greedy schedules: " + isExhaustive);
    System.err.println("  Max number of visits: " + maxLen);
    System.err.println("  Algorithm: " + resourceDir);
    System.err.println("  Output dest: " + outputDir);
    System.err.println("  Chain loops: " + AGEvaluatorSwipl.chainLoops);
    GeneratorI g = AGEvaluatorSwipl.chainLoops ? new AbstractGenerator(new FlatCppGenerator()) : new Generator(
        new FlatCppGenerator());

    if (useFirstParallel)
      g.synthesize(alePath, outputDir, resourceDir, verbose, isFixedChildOrder, isExhaustive, maxLen, false);
    else
      g.synthesizeAll(alePath, outputDir, resourceDir, verbose, isFixedChildOrder, isExhaustive, maxLen, false);
  }

  @Override
  public void generateParseFiles(ALEParser ast, Schedule sched, String outputDir, boolean verbose,
      String functionHeaders) throws InvalidGrammarException {
    fields = new FlatCppFieldsHelper(ast, sched);
    this.sched = sched;
   
    try {
      AGEvaluatorSwipl.writeFile(outputDir + File.separator + aleactions_filename, generateAleHeader(functionHeaders));
      AGEvaluatorSwipl.writeFile(outputDir + File.separator + fields_header_filename, generateFieldsHeader());
      AGEvaluatorSwipl.writeFile(outputDir + File.separator + parse_body_filename, generateParseBody());
      AGEvaluatorSwipl.writeFile(outputDir + File.separator + unionvariants_filename, generateUnionvariants(ast, true));
    } catch (IOException e) {
      System.out.println("Failure to generate parse header into directory " + outputDir + ": " + e.toString());
      System.exit(1);
    }
     
    if (verbose) {
      System.out.println("=== Ale Actions ===: \n" + generateAleHeader(functionHeaders));
      System.out.println("=== Fields Declaration ===:\n" + generateFieldsHeader());
      System.out.println("=== Parse-related Function Definitions ===\n" + generateParseBody());
      System.out.println("=== Unionvariants Enum ===\n" + generateUnionvariants(ast, true));
    }
  }

  @Override
  public String output(String baseName, String visitOut, String visitDispatches, String outputDir, boolean write,
      boolean verbose, ALEParser ast, Schedule sched, String fHeaders, Hashtable<Variable, Term> binding,
      AGEvaluator aleg) throws IOException, InvalidGrammarException {
    if (write) {
      AGEvaluatorSwipl.writeFile(outputDir + File.separator + visit_header_filename,
          generateVisitHeader(sched._aleg));
      AGEvaluatorSwipl.writeFile(outputDir + File.separator + visit_body_filename,
          visitOut + visitDispatches);
    }
    if (verbose) {
      System.out.println("=== Visitor Header ===: \n" + generateVisitHeader(sched._aleg));
      System.out.println("=== Visitor Body ===: \n" + visitOut + visitDispatches);
    }
    return "(no Flat C++ out)";

  }

  @Override
  public String lhsToAddress(String lhs, Class cls, ALEParser ast) throws InvalidGrammarException {
    boolean isParent;
    String child;
    String prop;

    if (lhs.split("@").length == 2) {
      child = lhs.split("@")[0];
      isParent = child.equals("self");
      prop = lhs.split("@")[1];
    } else {
      child = ""; // silly Java
      isParent = true;
      prop = lhs;
    }

    if (isParent) {
      // If we're assigning the data to this node
      return fields.findCppField(cls, prop).getCppName() + "[index]";
    } else if (AbstractGenerator.childrenContains(ast.extendedClasses.get(cls).multiChildren.keySet(), child)) {     
      // If we're assigning to our multiple children inside a loop
      AGEval.IFace child_class = cls.getChildByName(child);
      return fields.findCppField(child_class, prop).getCppName() + "[current_node]";
    } else {
      // If we're assigning the data to our single child
      AGEval.IFace child_class = cls.getChildByName(child);
      FlatCppFieldsHelper.Field child_field = fields.findCppField(cls, "child_" + child + "_leftmost_child");
      String child_index = "GetAbsoluteIndex(" + child_field.getCppName() + ", index)";

      return fields.findCppField(child_class, prop).getCppName() + "[" + child_index + "]";
    }
  }

  @Override
  public String rhsToVal(String lhs, Class cls, ALEParser ast) throws InvalidGrammarException {
    boolean isParent;
    String child;
    String prop;

    // Determine if this is a parent or we're interested in this class, and
    // then determine the property name
    if (lhs.split("@").length == 2) {
      child = lhs.split("@")[0];
      isParent = child.equals("self");
      prop = lhs.split("@")[1];
    } else {
      if (ast.types.get("displayType").contains(lhs.toLowerCase()))
        return CppParserGenerator.toEnum(lhs);
      child = "self";
      isParent = true;
      prop = lhs;
    }

    String cleanProp = prop.replace("$-", "").replace("$$", "").replace("$i", "").toLowerCase();

    // $$ means access the last value calculated in a loop
    if (prop.contains("$$")) {
      if (isParent) {
        return fields.findCppField(cls, cleanProp).getCppRhsName() + "[index]";
      } else if (Generator.childrenContains(ast.extendedClasses.get(cls).multiChildren.keySet(), child)) {
        return fields.findCppField(cls, child + "_" + cleanProp + "_last").getCppRhsName() + "[index]";
      } else {
        throw new InvalidGrammarException("Cannot access $$ attrib of a non-multi child / self reduction: "
            + lhs);
      }
      // $i means access the current iteration of a loop
    } else if (prop.contains("$i")) { // We're working with a multi child
      if (isParent) {
        throw new InvalidGrammarException("Cannot access $i of self attrib: " + lhs);
      } else if (Generator.childrenContains(ast.extendedClasses.get(cls).multiChildren.keySet(), child)) {
        AGEval.IFace child_class = cls.getChildByName(child);
       
        return fields.findCppField(child_class, cleanProp).getCppRhsName() + "[current_node]";
      } else {
        throw new InvalidGrammarException("Cannot access $i attrib of a non-multi child: " + lhs);
      }
      // $- means access the previous iteration of the loop
    } else if (prop.contains("$-")) {
      if (isParent) {
        return fields.findCppField(cls, cleanProp).getCppRhsName() + "[index]";
      } else if (Generator.childrenContains(ast.extendedClasses.get(cls).multiChildren.keySet(), child)) {
        String init = fields.findCppField(cls, child + "_" + cleanProp + "_last").getCppRhsName() + "[index]";
        String rest = fields.findCppField(cls.getChildByName(child), cleanProp).getCppRhsName() + "[PREV_FLATCPP()]";
        return "(STEP() == 1 ? (" + init + ") : (" + rest + "))";
      } else {
        throw new InvalidGrammarException("Cannot access $- attrib of a non-multi child: " + lhs);
      }
      // We're just working with regular variables
    } else {
      if (isParent) {
        return fields.findCppField(cls, cleanProp).getCppRhsName() + "[index]";
      } else if (ast.extendedClasses.get(cls).multiChildren.containsKey(child)) {
        return fields.findCppField(cls.getChildByName(child), cleanProp).getCppRhsName() + "[index]";
      } else {
        // If we're assigning the data to our single child
        FlatCppFieldsHelper.Field child_field = fields.findCppField(cls, "child_" + child + "_leftmost_child");
        String child_index = "GetAbsoluteIndex(" + child_field.getCppName() + ", index)";

        return fields.findCppField(cls.getChildByName(child), cleanProp).getCppRhsName() + "[" + child_index
            + "]";
      }
    }
  }

  @Override
  public String asgnE(String lhs, String rhs) {
     return lhs + " = " + rhs;
  }

  @Override
  public String asgnS(String lhs, String rhs) {
    return asgnE(lhs, rhs) + ";\n";
  }

  @Override
  public String toAcc(String lhsRaw, Class c) {
    String lhs = lhsRaw.toLowerCase();
    if (!lhs.contains("@")) return lhs + "_last";
    if (lhs.contains("self@")) return lhs.split("@")[1] + "_last";
    return lhs.replace("@", "_") + "_last";
  }

  @Override
  public String logStmt(int indentSrc, int indentOut, String msg, String rhs) {
    return "";
  }

  // Don't log anything
  @Override
  public String logStmtVar(int indentSrc, int indentOut, String msg, ALEParser ast, Class cls, String rhs,
      String rhsAddress) throws InvalidGrammarException {
    return "";
  }

  @Override
  public String printCurrentPipelineBuild(Hashtable<Variable, Term> binding) throws InvalidGrammarException {
    return "[printCurrentPipelineBuild]";
  }

  // Taken straight from the OpenCL backend
  @Override
  public String functionHeader(Assignment assign, ALEParser ast) throws InvalidGrammarException {
    StringBuilder contents = new StringBuilder();

    StringBuilder params = new StringBuilder();
    params.append("(");
    boolean isFirst = true;
    for (String arg : assign._variables.keySet()) {
      if (!isFirst) {
        params.append(", ");
      } else {
        isFirst = false;
      }

      ALEParser.ExtendedVertex ev = Generator.lookupAttributeExtended(arg, assign._class, ast);

      if (ev != null && ev.isMaybeType) {
        throw new InvalidGrammarException(
            "'maybe' types not currently implemented in Flat C++ backend. Yell at Matt.");
      } else {
        params.append(FlatCppFieldsHelper.typeStringToFlatCppType(Generator.extendedGet(ast, assign._class,
            arg).strType));
      }
      params.append(" " + assign._variables.get(arg));
    }
    params.append(")");

    contents.append("static ");
    contents.append(FlatCppFieldsHelper.typeStringToFlatCppType(Generator.extendedGet(ast, assign._class, assign._sink).strType));
    contents.append(" " + assign._class.getName().toLowerCase() + "_");
    contents.append(assign._sink.replace('.', '_').replace('@', '_') + " ");
    contents.append(params);
    contents.append(" { return " + assign._indexedBody + "; }\n");

    return contents.toString();
  }

  @Override
  public String visitHeader(Class cls, int visitNum, ALEParser ast) throws InvalidGrammarException {
    return "bool ClusteredTree::visit_" + cls.getName().toLowerCase() + "_" + visitNum
        + "(unsigned int index) {\n";
  }

  @Override
  public String visitFooter(Class cls, int visitNum, ALEParser ast) throws InvalidGrammarException {
    return "  return true;\n}\n\n";
  }

  @Override
  public String openChildLoop(Class parent_class, String loopVar, ALEParser ast) {
    return "SFORLOOPALIAS_FLATCPP(index, " + fields.findCppField(parent_class, "child_" + loopVar
        + "_leftmost_child").getCppName() + ", step) {\n";
  }

  @Override
  public String closeChildLoop() {
    return "  } SFORLOOPALIAS_FLATCPP_END();\n";
  }

  @Override
  public String openLastChild(Class cls, String loopVar) {
    return "    if (step == " + fields.findCppField(cls, "child_" + loopVar + "_count").getCppName() + "[index]) {\n";
  }

  @Override
  public String closeLastChild() {
    return "      break;\n    }\n";
  }

  @Override
  public String childrenRecur(Class cls, String childName, int visitNum, ALEParser ast)
      throws InvalidGrammarException {
    return "// Recur on current child\n\n  visit_" + visitNum + "(current_node);\n";
  }

  @Override
  public String childRecur(Class cls, String childName, int visitNum) throws InvalidGrammarException {
    FlatCppFieldsHelper.Field child_field = fields.findCppField(cls, "child_" + childName + "_leftmost_child");
    return "// Recur on fist child\n  visit_"+ visitNum + "(" + child_field.getCppName() + "[index]);\n";
  }

  @Override
  public String visitDispatcher(int visit, AGEvaluator aleg, HashSet<Class> buIns, HashSet<Class> bus) {
    // Flat C++ does not (yet) do suborder traversals
    if (buIns != null && buIns.size() > 0) {
      System.err.println("!!! FATAL ERROR !!! SubOrder traversals not supported in Flat C++");
      System.exit(-1);
    }
    if (bus != null && bus.size() > 0) {
      System.err.println("!!! FATAL ERROR !!! SubOrder traversals not supported in Flat C++");
      System.exit(-1);
    }
   
    StringBuilder contents = new StringBuilder();

    contents.append("bool ClusteredTree::visit_" + visit + "(unsigned int index) {\n");

    contents.append("\tswitch(" + fields.findCppField(null, "display").getCppRhsName() + "[index]) {\n");
    for (AGEval.Class cls : aleg.classes) {
      contents.append("\t\tcase TOK_" + cls.getName().toUpperCase() + ":\n");
      contents.append("\t\t\treturn visit_" + cls.getName().toLowerCase() + "_" + visit + "(index);\n");
    }
   
    contents.append("\t\tdefault:\n");
    contents.append("\t\t\tstd::cerr << \"Error: Node \" << index << \" has an unknown displayname of \"  << (enum unionvariants) displayname[index] << std::endl;\n");
    contents.append("\t\t\texit(-1);\n");
   
    contents.append("\t}\n}\n\n");

    return contents.toString();
  }

  @Override
  public String preVisits(AGEvaluator aleg, Schedule sched) {
    StringBuilder contents = new StringBuilder();
    contents.append(generated_warning_header);
    contents.append("#include \"clustered_tree.h\"\n");
    contents.append("#include \"sssmacros_flatcpp.h\"\n");
    contents.append("#include \"" + aleactions_filename + "\"\n");
    contents.append("#include <iostream>\n");
    contents.append("#include <cstdlib>\n\n");
   
    try {
      contents.append(generateRunTraversalsFunction(sched));
    } catch (InvalidGrammarException e) {
      System.err.println("!!!FATAL ERROR!!! Exception while attempting to generate _Gen_RunTraversals: " + e.getMessage());
      System.exit(-1);
    }
   
    return contents.toString();
  }

  @Override
  public String postVisits(AGEvaluator aleg, Schedule sched) throws InvalidGrammarException {
    return "";
  }

  @Override
  public String replaceTypeVals(String body, ALEParser ast) {
    return body;
  }
 
 
  ///////////////////////////////////////////////////////////////////////////
  // Helper functions
  ///////////////////////////////////////////////////////////////////////////
 
  // Copy+Paste from OpenCL backend
  // While the actual ale action functions are generated by functionHeaders() (whose results are correlated by the
  // generator and handed back to us in generateParseFiles() and then sent here), this function adds includes and
  // other things needed to complete the header.
  private String generateAleHeader(String functionHeaders) {
    StringBuilder contents = new StringBuilder();

    contents.append("#ifndef ALEACTIONS_H\n");
    contents.append("#define ALEACTIONS_H\n\n");
    contents.append("// Shut compiler up about unused functions. There _will_ be unused functions.\n");
    contents.append("// Yes, kind of evil to do this, but useless compiler warnings are more evil.\n");
    contents.append("#pragma clang diagnostic ignored \"-Wunused-function\"\n\n");
   
    contents.append("#include \"pi.h\"\n");
    contents.append("#include \"paint_stubs.h\"\n");
    contents.append("#include <math.h>\n\n");

    contents.append(functionHeaders);

    contents.append("\n#endif // ALEACTIONS_H\n");

    return contents.toString();
  }
 

  private String generateFieldsHeader() {
    StringBuilder contents = new StringBuilder();
    contents.append(generated_warning_header);
   
    for(FlatCppFieldsHelper.Field field : fields.getFields()) {
      contents.append(field.getCppType() +"* ");
      contents.append(field.getCppName() + ";\n");
    }
   
    return contents.toString();
  }
 
 
  // Generated the clustered_tree_generated_parse.cpp file
  private String generateParseBody() {
    StringBuilder contents = new StringBuilder();
    contents.append(generated_warning_header);
    contents.append("#include \"clustered_tree.h\"\n\n");
   
    contents.append(generateConstructor());
    contents.append(generateDestructor());
   
    return contents.toString();
  }
 
 
  private String generateConstructor() {
    StringBuilder contents = new StringBuilder();
   
    contents.append("void ClusteredTree::ConstructGeneratedFields() {\n");
   
    for(FlatCppFieldsHelper.Field field : fields.getFields()) {
      contents.append("\t" + field.getCppName());
      contents.append(" = new " + field.getCppType() + "[_size];\n");
     
      // If this is a collection, fill it with empty data so that we don't accidentally loop over garbage
      if(field.getCppName().contains("_count") || field.getCppName().contains("_leftmost_child")) {
        contents.append("\tstd::fill_n(" + field.getCppName() + ", _size, 0);\n");
      }
    }
   
    // Also fill right siblings with empty data
    contents.append("\tstd::fill_n(right_siblings, _size, 0);\n");
   
    contents.append("}\n\n\n");
   
    return contents.toString();
  }
 
 
  private String generateDestructor() {
    StringBuilder contents = new StringBuilder();
   
    contents.append("void ClusteredTree::DestructGeneratedFields() {\n");
   
    for(FlatCppFieldsHelper.Field field : fields.getFields()) {
      contents.append("\tdelete[] " + field.getCppName() + ";\n");
    }
   
    contents.append("}\n\n\n");
   
    return contents.toString();
  }
 
 
 
  public static HashMap<String, Integer> getTokens (HashMap<String, ArrayList<String>> types){
    HashMap<String, Integer> res = new HashMap<String, Integer>();       
   
    HashSet<String> names = new HashSet<String>();
    for (String name : types.keySet()) {
      for (String v : types.get(name)) {
        String token_name = CppParserGenerator.toEnum(v);
        names.add(token_name);
      }
    }
   
    Vector<String> sortedToks = new Vector<String>(names);
    Collections.sort(sortedToks);
   
    // Start the numbering at 5 so uninitialized data will be easier to detect when debugging
    int i = 5;
    for (String name : sortedToks){   
      res.put(name, i);
      i++;
    }
   
    return res;
  }
 
 
  public static String generateUnionvariants(ALEParser ast, boolean withWrapping) {
    StringBuilder contents = new StringBuilder();
    if (withWrapping){
      contents.append(generated_warning_header);
      contents.append("#ifndef UNIONVARIANTS_H\n");
      contents.append("#define UNIONVARIANTS_H\n\n");
    }

    contents.append("enum " + CppParserGenerator.clean("unionvariants") + " {");
   
    HashMap<String, Integer> tokens = getTokens(ast.types);
    boolean first = true;
    for (Entry<String, Integer>  entry : tokens.entrySet()) {
      if (first){ first = false; }
      else {
        contents.append(", ");
      }
      contents.append(entry.getKey());
      contents.append(" = ");
      contents.append(entry.getValue());
    }
   
    contents.append("};\n\n");
   
    if (withWrapping){
      contents.append("#endif // UNIONVARIANTS_H\n");
    }
   
    return contents.toString();
  }
 
 
  // Generates the contents of the header file for all the visit functions
  private String generateVisitHeader(AGEvaluator aleg) {
    StringBuilder contents = new StringBuilder();
    contents.append(generated_warning_header);
    contents.append("#ifndef CLUSTERED_TREE_VISIT_H\n");
    contents.append("#define CLUSTERED_TREE_VISIT_H\n\n");
   
    final int num_visits = sched.numVisits();

    for (int i = 0; i < num_visits; i++) {
      contents.append("bool visit_" + i + "(unsigned int index);\n");
     
      for (AGEval.Class cls : aleg.classes) {
        contents.append("bool visit_" + cls.getName().toLowerCase() + "_" + i);
        contents.append("(unsigned int index);\n");
      }
    }
   
    contents.append("\n#endif // CLUSTERED_TREE_VISIT_H\n");
   
    return contents.toString();
  }
 
 
  private String generateRunTraversalsFunction(Schedule sched) throws InvalidGrammarException {
    StringBuilder contents = new StringBuilder();

    contents.append("void ClusteredTree::_Gen_RunTraversals() {\n");
    Term[] visits = sched.binding.get("P").toTermArray();

    // The last traversal is the special render traversal, so don't write
    for (int i = 0; i < visits.length; i++) {
      String stencil = visits[i].arg(2).arg(1).toString();
      if (stencil.equals("tdLtrU")) {
          contents.append("  visit_" + i + "(0);\n");
      } else if (stencil.equals("td")) {
        contents.append(generateTopDownTraversal("visit_" + i));
      } else if (stencil.equals("bu")) {
        contents.append(generateBottomUpTraversal("visit_" + i));
      } else {
        throw new InvalidGrammarException("Unsupported traversal order: " + stencil);
      }
    }
    contents.append("}\n\n\n");

    return contents.toString();
  }
 
 
  private String generateTopDownTraversal(String visitFunctionName) {
    StringBuilder contents = new StringBuilder();
   
    contents.append("\t// Top-down traversal\n");
    contents.append("\tfor (std::vector<ClusteredTree::level_info>::iterator i = levels.begin(); i < levels.end(); i++) {\n");
    contents.append("\t\tfor(unsigned int j = (i->start_idx); j < (i->start_idx) + (i->size); j++) {\n");
    contents.append("\t\t\t" + visitFunctionName + "(j);\n");
    contents.append("\t\t}\n");
    contents.append("\t}\n\n");
   
    return contents.toString();
  }
 
 
  private String generateBottomUpTraversal(String visitFunctionName) {
    StringBuilder contents = new StringBuilder();
   
    contents.append("\t// Bottom-up traversal\n");
    contents.append("\tfor (std::vector<ClusteredTree::level_info>::const_reverse_iterator i = levels.rbegin(); i != levels.rend(); i++) {\n");
    contents.append("\t\t\tfor(unsigned int j = (i->start_idx); j < (i->start_idx) + (i->size); j++) {\n");
    contents.append("\t\t\t" + visitFunctionName + "(j);\n");
    contents.append("\t\t}\n");
    contents.append("\t}\n\n");
   
    return contents.toString();
  }
}
TOP

Related Classes of AGEvalSwipl.FlatCppGenerator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.