package de.gaalop.clucalc.output; import de.gaalop.Notifications; import de.gaalop.cfg.*; import de.gaalop.clucalc.input.CluCalcFileHeader; import de.gaalop.dfg.Expression; import de.gaalop.dfg.MultivectorComponent; import de.gaalop.dfg.Variable; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; /** * Visits the control structure of the control dataflow graph. */ public class CfgVisitor implements ControlFlowVisitor { private static final String MAPLE_SUFFIX = "_opt"; String codeSuffix; private Log log = LogFactory.getLog(CfgVisitor.class); private Map<String, Set<Integer>> assignedComponents = new HashMap<String, Set<Integer>>(); StringBuilder code = new StringBuilder(); int indent; public CfgVisitor(String suffix) { codeSuffix = suffix; } public String getCode() { return code.toString(); } @Override public void visit(StartNode startNode) { CluCalcFileHeader header = CluCalcFileHeader.get(startNode); if (header != null) { if (header.getNullSpace() != null) { switch (header.getNullSpace()) { case IPNS: code.append(":IPNS;\n"); break; case OPNS: code.append(":OPNS;\n"); break; } } code.append("\n"); } // TODO add "Generated by" header etc. // Generate the local variables for all local variables for (Variable localVariable : startNode.getGraph().getLocalVariables()) { code.append(localVariable.getName() + codeSuffix); code.append(" = List("); code.append(startNode.getGraph().getAlgebraDefinitionFile().getBladeCount()); code.append(");\n"); } code.append("\n"); startNode.getSuccessor().accept(this); } @Override public void visit(EndNode node) { } @Override public void visit(AssignmentNode assignmentNode) { Set<Integer> assigned = assignedComponents.get(assignmentNode.getVariable().getName()); if (assigned != null && assigned.isEmpty()) { // in this case the variable is reused and should be reset String message = "Variable " + assignmentNode.getVariable().getName() + " has been reset for reuse."; log.warn(message); Notifications.addWarning(message); appendIndent(); code.append(assignmentNode.getVariable().getName()); code.append(" = List(32); // reset for reuse\n"); } appendIndent(); addCode(assignmentNode.getVariable()); code.append(" = "); addCode(assignmentNode.getValue()); if (assignmentNode.getVariable() instanceof MultivectorComponent) { code.append("; // "); MultivectorComponent component = (MultivectorComponent) assignmentNode.getVariable(); code.append(assignmentNode.getGraph().getAlgebraDefinitionFile().getBladeString(component.getBladeIndex())); code.append("\n"); // Record that this component has been set for the multivector if (!assignedComponents.containsKey(component.getName())) { assignedComponents.put(component.getName(), new HashSet<Integer>()); } assignedComponents.get(component.getName()).add(component.getBladeIndex()); } else { code.append(";\n"); } assignmentNode.getSuccessor().accept(this); } @Override public void visit(ExpressionStatement node) { appendIndent(); addCode(node.getExpression()); code.append(";\n"); node.getSuccessor().accept(this); } @Override public void visit(StoreResultNode node) { appendIndent(); code.append('?'); // Reassemble all output variables in the value Variable outputVariable = (Variable) node.getValue(); String variableName = outputVariable.getName(); String opt = variableName + MAPLE_SUFFIX; code.append(variableName); Set<Integer> var = assignedComponents.get(opt); if (var == null) { // no assignment for this variable at all -> keep ? operator } else { code.append(" = "); int bladeCount = node.getGraph().getAlgebraDefinitionFile().getBladeCount(); for (int i = 0; i < bladeCount; ++i) { if (!var.contains(i)) { continue; } Expression blade = node.getGraph().getAlgebraDefinitionFile().getBladeExpression(i); code.append(opt.replace(MAPLE_SUFFIX, codeSuffix)); code.append("("); code.append(i + 1); code.append(")"); code.append(" * "); addCode(blade); code.append(" + "); } // Remove the last " + " code.setLength(code.length() - 3); } // reset the set of assigned components, so variable can be reused assignedComponents.put(opt, new HashSet<Integer>()); code.append(";\n"); node.getSuccessor().accept(this); } @Override public void visit(IfThenElseNode node) { code.append('\n'); appendIndent(); code.append("if ("); addCode(node.getCondition()); code.append(") {\n"); indent++; node.getPositive().accept(this); indent--; appendIndent(); code.append("}"); if (node.getNegative() instanceof BlockEndNode) { code.append("\n\n"); } else { code.append(" else "); boolean isElseIf = false; if (node.getNegative() instanceof IfThenElseNode) { IfThenElseNode ifthenelse = (IfThenElseNode) node.getNegative(); isElseIf = ifthenelse.isElseIf(); } if (!isElseIf) { code.append("{\n"); indent++; } node.getNegative().accept(this); if (!isElseIf) { indent--; appendIndent(); code.append("}\n\n"); } } node.getSuccessor().accept(this); } @Override public void visit(LoopNode node) { appendIndent(); code.append("loop {\n"); indent++; node.getBody().accept(this); indent--; appendIndent(); code.append("}\n"); node.getSuccessor().accept(this); } @Override public void visit(BreakNode breakNode) { appendIndent(); code.append("break;\n"); } @Override public void visit(BlockEndNode node) { // nothing to do } void addCode(Expression value) { DfgVisitor visitor = new DfgVisitor(codeSuffix, MAPLE_SUFFIX); value.accept(visitor); code.append(visitor.getCode()); } void appendIndent() { for (int i = 0; i < indent; i++) { code.append("\t"); } } @Override public void visit(Macro node) { throw new IllegalStateException("Macros should have been inlined."); } @Override public void visit(ColorNode node) { appendIndent(); code.append(":"); code.append(node); code.append(";\n"); node.getSuccessor().accept(this); } }