/* * To change this license header, choose License Headers in Project Properties. * To change this template file, choose Tools | Templates * and open the template in the editor. */ package de.gaalop.clucalc.input; import de.gaalop.cfg.ControlFlowGraph; import java.util.Collections; import java.util.ArrayList; import de.gaalop.cfg.*; import de.gaalop.dfg.*; import static de.gaalop.dfg.ExpressionFactory.*; import java.util.LinkedList; import java.util.List; /** * * @author Christian Steinmetz */ public class CluVisitor extends CluCalcBaseVisitor<Object> { public ControlFlowGraph graph; //TODO Fill graph private ArrayList<SequentialNode> nodes; private GraphBuilder graphBuilder; private int inIfBlock = 0; private boolean inMacro = false; private static final class ParserError extends Error { public ParserError(String message) { super("Parser error: " + message); } } private List<String> errors = new ArrayList<String>(); /*public void displayRecognitionError(String[] tokenNames, RecognitionException e) { String hdr = getErrorHeader(e); String msg = getErrorMessage(e, tokenNames); errors.add(hdr + " " + msg); } public List<String> getErrors() { return errors; }*/ @Override public Object visitScript(CluCalcParser.ScriptContext ctx) { graphBuilder = new GraphBuilder(); graph = graphBuilder.getGraph(); nodes = new ArrayList<SequentialNode>(); super.visitScript(ctx); //To change body of generated methods, choose Tools | Templates. graphBuilder.finish(); return graph; } @Override public Object visitOutputAssignmentCaseC(CluCalcParser.OutputAssignmentCaseCContext ctx) { AssignmentNode assignment = (AssignmentNode) visit(ctx.val); ExpressionStatement ex = graphBuilder.processExpressionStatement(assignment.getVariable()); if (inMacro) macroNodes.add(ex); else nodes.add(ex); graphBuilder.addVisualizerExpression(ex); return null; } @Override public Object visitOutputVariableCaseC(CluCalcParser.OutputVariableCaseCContext ctx) { ExpressionStatement ex = graphBuilder.processExpressionStatement(new Variable(ctx.val.getText())); if (inMacro) macroNodes.add(ex); else nodes.add(ex); graphBuilder.addVisualizerExpression(ex); return ex; } @Override public Object visitOutputAssignmentCaseQ(CluCalcParser.OutputAssignmentCaseQContext ctx) { AssignmentNode assignment = (AssignmentNode) visit(ctx.val); SequentialNode n2 = graphBuilder.handlePrint(assignment.getVariable().copy()); if (inMacro) macroNodes.add(n2); else nodes.add(n2); return null; } @Override public Object visitOutputVariableCaseQ(CluCalcParser.OutputVariableCaseQContext ctx) { StoreResultNode node = graphBuilder.handlePrint(new Variable(ctx.val.getText())); if (inMacro) macroNodes.add(node); else nodes.add(node); return node; } @Override public Object visitAssignment(CluCalcParser.AssignmentContext ctx) { Variable variable = (Variable) visit(ctx.var); Expression expression = (Expression) visit(ctx.expr); AssignmentNode result = graphBuilder.handleAssignment(variable, expression); return result; } @Override public Object visitVariable(CluCalcParser.VariableContext ctx) { return graphBuilder.processIdentifier(ctx.getText()); } @Override public Object visitConstant(CluCalcParser.ConstantContext ctx) { return new FloatConstant(Double.parseDouble(ctx.getText())); } @Override public Object visitArgument(CluCalcParser.ArgumentContext ctx) { return new FunctionArgument(Integer.parseInt(ctx.index.getText())); } @Override public Object visitDual(CluCalcParser.DualContext ctx) { return graphBuilder.processFunction("*", Collections.singletonList((Expression) visit(ctx.operand))); } @Override public Object visitSingleArgument(CluCalcParser.SingleArgumentContext ctx) { LinkedList<Expression> result = new LinkedList<Expression>(); result.add((Expression) visit(ctx.arg)); return result; } @Override public Object visitMultipleArgument(CluCalcParser.MultipleArgumentContext ctx) { LinkedList<Expression> result = new LinkedList<Expression>(); result.add((Expression) visit(ctx.arg)); result.addAll((LinkedList<Expression>) visit(ctx.nextarg)); return result; } @Override public Object visitFunction(CluCalcParser.FunctionContext ctx) { LinkedList<Expression> args = (ctx.args != null) ? (LinkedList<Expression>) visit(ctx.args) : new LinkedList<Expression>(); return graphBuilder.processFunction(ctx.name.getText(), args); } private LinkedList<SequentialNode> macroNodes; @Override public Object visitMACRO(CluCalcParser.MACROContext ctx) { if (inMacro) { throw new ParserError("A macro may only be defined in global scope."); } graphBuilder.beginNewScope(); inMacro = true; macroNodes = new LinkedList<>(); graphBuilder.addMacroName(ctx.id.getText()); if (ctx.body != null) visit(ctx.body); Expression e = null; if (ctx.e != null) e = (Expression) visit(ctx.e); graphBuilder.handleMacroDefinition(ctx.id.getText(), macroNodes, e); graphBuilder.endNewScope(); inMacro = false; return null; } // Expressions @Override public Object visitAddition(CluCalcParser.AdditionContext ctx) { Expression l = (Expression) visit(ctx.left); Expression r = (Expression) visit(ctx.right); return new Addition(l,r); } @Override public Object visitSubtraction(CluCalcParser.SubtractionContext ctx) { return new Subtraction((Expression) visit(ctx.left), (Expression) visit(ctx.right)); } @Override public Object visitMultiplication(CluCalcParser.MultiplicationContext ctx) { return new Multiplication((Expression) visit(ctx.left), (Expression) visit(ctx.right)); } @Override public Object visitDivision(CluCalcParser.DivisionContext ctx) { return new Division((Expression) visit(ctx.left), (Expression) visit(ctx.right)); } @Override public Object visitOuterProduct(CluCalcParser.OuterProductContext ctx) { return new OuterProduct((Expression) visit(ctx.left), (Expression) visit(ctx.right)); } @Override public Object visitInnerProduct(CluCalcParser.InnerProductContext ctx) { return new InnerProduct((Expression) visit(ctx.left), (Expression) visit(ctx.right)); } @Override public Object visitNegation(CluCalcParser.NegationContext ctx) { return new Negation((Expression) visit(ctx.operand)); } @Override public Object visitReverse(CluCalcParser.ReverseContext ctx) { return new Reverse((Expression) visit(ctx.operand)); } @Override public Object visitBracket(CluCalcParser.BracketContext ctx) { return (Expression) visit(ctx.e); } @Override public Object visitNegationBracket(CluCalcParser.NegationBracketContext ctx) { return new Negation((Expression) visit(ctx.operand)); } } /* statement returns [ArrayList<SequentialNode> nodes] @init { $nodes = new ArrayList<SequentialNode>(); } // Print something to the console | IPNS { graphBuilder.handleNullSpace(NullSpace.IPNS); } | OPNS { graphBuilder.handleNullSpace(NullSpace.OPNS); } // Displayed assignment (ignore the display part) | ^(COLON assignment) { $nodes.add(graphBuilder.handleAssignment($assignment.variable, $assignment.value)); ExpressionStatement ex = graphBuilder.processExpressionStatement($assignment.variable); $nodes.add(ex); graphBuilder.addVisualizerExpression(ex); } | ^(COLON id=variableOrConstant) { ExpressionStatement ex = graphBuilder.processExpressionStatement($id.result); $nodes.add(ex); graphBuilder.addVisualizerExpression(ex); } // Stand-alone assignment | assignment { $nodes.add(graphBuilder.handleAssignment($assignment.variable, $assignment.value)); } | macro | pragma | slider | ^(COLOR arguments) { $nodes.add(graphBuilder.handleColor($arguments.args)); } | ^(COLOR name=(BLACK | BLUE | CYAN | GREEN | MAGENTA | ORANGE | RED | WHITE | YELLOW)) { $nodes.add(graphBuilder.handleColor($name.text)); } | ^(BGCOLOR arguments) { graphBuilder.handleBGColor($arguments.args); } // Some single-line expression (without assignment), e.g. macro call | expression { Expression e = $expression.result; if (e != null) { // null e.g. for procedure calls like DefVarsN3() $nodes.add(graphBuilder.processExpressionStatement(e)); } } ; macro @init { if (inMacro) { throw new ParserError("A macro may only be defined in global scope."); } graphBuilder.beginNewScope(); inMacro = true; } @after { graphBuilder.endNewScope(); inMacro = false; } : ^(MACRO id=IDENTIFIER { graphBuilder.addMacroName($id.text); } lst=statement_list e=return_value?) { graphBuilder.handleMacroDefinition($id.text, $lst.args, $e.result); } ; return_value returns [Expression result] : ^(RETURN exp=expression) { $result = $exp.result; } ; pragma : PRAGMA RANGE_LITERAL min=float_literal LESS_OR_EQUAL varname=IDENTIFIER LESS_OR_EQUAL max=float_literal { graphBuilder.addPragmaMinMaxValues($varname.text, min, max);} ; assignment returns [Variable variable, Expression value] : ^(EQUALS l=variable r=expression) { $variable = $l.result; $value = $r.result; } ; variable returns [Variable result] : variableOrConstant { if ( !($variableOrConstant.result instanceof Variable) ) { throw new RecognitionException(input); } $result = (Variable)$variableOrConstant.result; } ; if_statement returns [IfThenElseNode node] @init { inIfBlock++; } @after { inIfBlock--; } : ^(IF condition=expression then_part=statement else_part=else_statement?) { $node = graphBuilder.handleIfStatement($condition.result, $then_part.nodes, $else_part.nodes); } ; else_statement returns [ArrayList<SequentialNode> nodes] @init { graphBuilder.beginNewScope(); $nodes = new ArrayList<SequentialNode>(); } @after { graphBuilder.endNewScope(); } : ^(ELSE block) { $nodes = $block.nodes; } | ^(ELSEIF if_statement) { $if_statement.node.setElseIf(true); $nodes.add($if_statement.node); } ; loop returns [LoopNode node] : ^(LOOP stmt=statement number=DECIMAL_LITERAL?) { $node = graphBuilder.handleLoop($stmt.nodes, $number.text); } ; block returns [ArrayList<SequentialNode> nodes] @init { graphBuilder.beginNewScope(); $nodes = new ArrayList<SequentialNode>(); } @after { graphBuilder.endNewScope(); } : ^(BLOCK stmts=statement_list) { $nodes.addAll($stmts.args); } ; statement_list returns [ArrayList<SequentialNode> args] @init { $args = new ArrayList<SequentialNode>(); } : (arg=statement { $args.addAll($arg.nodes); })* ; slider : ^(SLIDER var=variable args=slider_args) { graphBuilder.handleSlider($var.result, $args.label, $args.min, $args.max, $args.step, $args.init); } ; fragment slider_args returns [String label, double min, double max, double step, double init] : id=STRING_LITERAL COMMA mi=constant COMMA ma=constant COMMA st=constant COMMA in=constant { $label = $id.text.replaceAll("\"", ""); $min = $mi.value; $max = $ma.value; $step = $st.value; $init = $in.value; } ; fragment constant returns [double value] : decimal_literal { $value = Double.parseDouble($decimal_literal.result); } | float_literal { $value = Double.parseDouble($float_literal.result); } ; arguments returns [ArrayList<Expression> args] @init { $args = new ArrayList<Expression>(); } : (arg=expression { $args.add($arg.result); })* ; float_literal returns [String result] : sign=MINUS? val=FLOATING_POINT_LITERAL {$result = new String((sign!=null?$sign.text:"") + $val.text);} ; decimal_literal returns [String result] : sign=MINUS? val=DECIMAL_LITERAL {$result = new String((sign!=null?$sign.text:"") + $val.text);} ; */