/* PseudoCode Interpreted Language (PCIL): Part of the algoviz@vt collection of algorithm visualizations. Copyright (C) 2008 Brandon Malone, Frank Hadlock This file is part of the PseudoCode Interpreted Language. PseudoCode Interpreted Language is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. PseudoCode Interpreted Language is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with PseudoCode Interpreted Language. If not, see . */ /* * DynamicController.java * * Created on September 22, 2007, 5:55 PM * * To change this template, choose Tools | Template Manager * and open the template in the editor. */ package dynamicmvc; import java.io.BufferedReader; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; import java.util.Stack; import lex.Analyzer; import lex.SourceToken; import syntacticanalysis.Function; import syntacticanalysis.Grammar; import syntacticanalysis.PostfixToken; import syntacticanalysis.SyntaxAnalyzer; /** * * @author Compaq_Owner */ public class DynamicController { private ArrayList postfixTokens; private Stack operandStack; private ArrayList functions; // the list of function names to step over private ArrayList stepOverFunctions; private Stack askStack; private ArrayList lines; private int currentToken; private State currentState; private View view; private Stack callStack; /** Creates a new instance of DynamicController */ public DynamicController(View view, State state) { operandStack = new Stack(); currentToken = -1; currentState = state; this.view = view; askStack = new Stack(); callStack = new Stack(); } private ArrayList readLines(String pseudocodeFilePath) throws IOException { BufferedReader br = new BufferedReader(new FileReader(pseudocodeFilePath)); ArrayList lines = new ArrayList(); String line = br.readLine(); while (line != null) { lines.add(line); line = br.readLine(); } return lines; } public int currentLineIndex() { PostfixToken currentToken = postfixTokens.get(this.currentToken); return currentToken.getLineNumber(); } public ArrayList getLines() { return lines; } public void startExecution(String pseudocodeFilePath, String grammarFilePath) throws DynamicMVCException, IOException, Exception { lines = readLines(pseudocodeFilePath); View.updatePseudocode(); // lexical analysis of the source code Analyzer a = new Analyzer(); ArrayList sourceTokens = a.analyzeSourceFile(pseudocodeFilePath); // read in the grammar (and construct parse table) Grammar g = Grammar.createFromFile(grammarFilePath); // perform syntactic analysis of the tokens to generate postfix SyntaxAnalyzer s = new SyntaxAnalyzer(g); postfixTokens = s.analyze(sourceTokens); // find all of the functions defined in the source setFunctions(s.findFunctions(postfixTokens)); // initialize other variables operandStack = new Stack(); currentToken = 0; callStack = new Stack(); setStepOverFunctions(new ArrayList()); // begin interpretting the source interpret(); }public void startExecution(String pseudocodeFilePath) throws DynamicMVCException, IOException, Exception { lines = readLines(pseudocodeFilePath); View.updatePseudocode(); // lexical analysis of the source code Analyzer a = new Analyzer(); ArrayList sourceTokens = a.analyzeSourceFile(pseudocodeFilePath); // read in the grammar (and construct parse table) Grammar g = Grammar.createFromFile(); // perform syntactic analysis of the tokens to generate postfix SyntaxAnalyzer s = new SyntaxAnalyzer(g); postfixTokens = s.analyze(sourceTokens); // find all of the functions defined in the source setFunctions(s.findFunctions(postfixTokens)); // initialize other variables operandStack = new Stack(); currentToken = 0; callStack = new Stack(); setStepOverFunctions(new ArrayList()); // begin interpretting the source interpret(); } public void resumeExecution() throws DynamicMVCException { interpret(); } public void interpret() throws DynamicMVCException { while(true) { PostfixToken token = postfixTokens.get(currentToken); if(token.getLexicalValue().equals("actionSymbol")) { // figure out what to do with the action symbol int actionSymbol = Integer.parseInt(token.getSourceValue()); // also move to the next token currentToken++; switch(actionSymbol) { case 1: actionSymbol1(); break; case 2: actionSymbol2(); break; case 3: actionSymbol3(); break; case 4: actionSymbol4(); break; case 5: actionSymbol5(); break; case 6: actionSymbol6(); break; case 7: actionSymbol7(); break; case 8: actionSymbol8(); break; case 9: actionSymbol9(); break; case 10: actionSymbol10(); break; case 11: actionSymbol11(); break; case 12: actionSymbol12(); break; case 13: actionSymbol13(); break; case 14: actionSymbol14(); break; case 15: actionSymbol15(); break; case 16: actionSymbol16(); break; case 17: actionSymbol17(); break; case 18: actionSymbol18(); break; case 19: actionSymbol19(); break; case 20: actionSymbol20(); break; case 21: actionSymbol21(); break; case 22: actionSymbol22(); break; case 23: actionSymbol23(); break; case 24: if(callStack.empty()) { actionSymbol24(); return; // return because this is a pause } else { break; // continue because this is not in step mode } case 25: actionSymbol25(); break; case 26: actionSymbol26(); break; case 27: actionSymbol27(); break; case 28: actionSymbol28(); break; case 29: actionSymbol29(); break; case 30: actionSymbol30(); break; case 31: actionSymbol31(); break; case 32: actionSymbol32(); break; case 33: actionSymbol33(); return; // return because this is finish case 34: actionSymbol34(); break; case 35: actionSymbol35(); break; case 36: actionSymbol36(); break; case 37: actionSymbol37(); break; // not sure if this is correct case 38: actionSymbol38(); break; case 39: actionSymbol39(); break; case 40: boolean shouldPause = actionSymbol40(); if(callStack.empty() && shouldPause) { view.render(); return; // return because this is a pause } else { break; // continue because this is not in step mode } case 41: actionSymbol41(); break; } } else { // just push it on the operand stack operandStack.push(token); currentToken++; } } } private void actionSymbol1() { // just pop the top thing off the operand stack operandStack.pop(); } private void actionSymbol2() { // pop [input][=] off the operand stack operandStack.pop(); operandStack.pop(); } private void actionSymbol3() { //{3} – pop [typeName] and [variableName] from the stack. //Add a new variable to the input state where //the type is [typeName] and the name is [variableName]. //Also add a variable to the state with //type [typeName] and name [variableName]. PostfixToken variableName = (PostfixToken)operandStack.pop(); PostfixToken typeName = (PostfixToken)operandStack.pop(); // create a primitive variable for the input PrimitivePointer v = PrimitiveFactory.create(typeName.getSourceValue(), variableName.getSourceValue()); v.setName(variableName.getSourceValue()); // add it to the input of the state this.currentState.setInput(variableName.getSourceValue(), v); //this.currentState.setStateVariable(v); } private void actionSymbol4() { // {4} – pop [name] [as] and [typeName] off of the stack. // Add a new variable to the state where // the type is [typeName] and the name is [variableName]. PostfixToken typeName = (PostfixToken)operandStack.pop(); operandStack.pop(); PostfixToken variableName = (PostfixToken)operandStack.pop(); // create a primitive variable for the input PrimitivePointer v = PrimitiveFactory.create(typeName.getSourceValue(), variableName.getSourceValue()); this.currentState.setStateVariable(variableName.getSourceValue(), v); } private void actionSymbol5() throws DynamicMVCException { //{5} pop [expressionValue] from the stack. [expressionValue] has to be a primitive //pop [=] from the stack. //pop [variableNameValue] from the stack. this has to be a primitive PrimitivePointer expressionValue = (PrimitivePointer)operandStack.pop(); //Primitive context = (Primitive)operandStack.pop(); // state PostfixToken equals = (PostfixToken)operandStack.pop(); // = PrimitivePointer variableNameValue = (PrimitivePointer)operandStack.pop(); PrimitiveFactory.setInMemory(variableNameValue.getAddress(), expressionValue.dereference()); //variableNameValue.setAddress(expressionValue.getAddress()); } private void actionSymbol6() { // {6} – pop [if] [conditionValue] [then] [nl] from the stack. // Evaluate[conditionValue]. // Push [conditionValue] back on the postfix stack in case of an else. // MAKE SURE TO UNIQUELY IDENIFY THIS RESULT. // If it is , execute the . // Otherwise, advance to the . operandStack.pop(); // nl PostfixToken thenToken = (PostfixToken)operandStack.pop(); // then Boolean conditionValue = (Boolean)operandStack.pop(); PostfixToken ifToken = (PostfixToken)operandStack.pop(); // assume the if has the value of either the else or endIf if (conditionValue.equals(Boolean.TRUE)) { // move to the statement list } else { // move to the else or endIf // HACK FIX operandStack.push(conditionValue); currentToken = Integer.parseInt(thenToken.getSemanticValue()); // + 1; } operandStack.push(conditionValue); } private void actionSymbol7() { // {7} – pop [else] [nl] off the stack. // Pop [conditionValue] off the stack. // either way, push [conditionValue] back on the stack operandStack.pop(); // nl PostfixToken elseToken = (PostfixToken)operandStack.pop(); Boolean conditionValue = (Boolean)operandStack.pop(); // only execute if the condition was false if (conditionValue.equals(Boolean.FALSE)) { // move to the statement list } else { // move to the endIf currentToken = Integer.parseInt(elseToken.getSemanticValue()); } operandStack.push(conditionValue); } private void actionSymbol8() { // {8} – pop [nl] [conditionValue] [while] off the postfix stack. // Evaluate . Pop it off the postfix stack. // If it is , execute the . // Otherwise, advance to the line after [endWhile]. operandStack.pop(); // nl Boolean conditionValue = (Boolean)operandStack.pop(); PostfixToken whileToken = (PostfixToken)operandStack.pop(); // while if (conditionValue.equals(Boolean.TRUE)) { // execute statement list } else { // move to just past the endWhile // skip past the endWhile actionSymbol {9} //currentToken = Integer.parseInt(whileToken.getSemanticValue()) + 6; currentToken = Integer.parseInt(whileToken.getSemanticValue()) + 5; // +6 because [0] = endWhile, [1] = aS41, [2] = as9, // [3] = nl, [4] = as1, [5] = as24 (pause)??, [6] = nextInstruction } } private void actionSymbol9() { // {9} – pop [endWhile] off the stack. // After reaching [endWhile], return to the [while]. Boolean shouldPause = (Boolean)operandStack.pop(); PostfixToken endWhileToken = (PostfixToken)operandStack.pop(); // push shouldPause back operandStack.push(shouldPause); // move to the while currentToken = Integer.parseInt(endWhileToken.getSemanticValue()); } private void actionSymbol10() throws DynamicMVCException { // {10} – pop [flag] [forEach] [name] [in] [expressionValue] [nl] // Add a variable named [name] to state. // Evaluate . // (It is at the top of the postfix stack.) // If it is not a , // create a that consists only of the result. // (Pop it off the stack. // Create a if necessary. // Push back on stack.) PostfixToken nlToken = (PostfixToken)operandStack.pop(); // nl PrimitivePointer expressionValue = (PrimitivePointer)operandStack.pop(); PostfixToken inToken = (PostfixToken)operandStack.pop(); // in PostfixToken name = (PostfixToken)operandStack.pop(); PostfixToken forEachToken = (PostfixToken)operandStack.pop(); Boolean hasBeenExecuted = (Boolean)operandStack.pop(); if (!hasBeenExecuted.booleanValue()) { // evaluate [expressionValue], push a PrimitiveList on the stack PrimitivePointer list; if (expressionValue.dereference() instanceof PrimitiveList) { list = expressionValue; } else { list = PrimitiveFactory.create(PrimitiveList.pseudocodeTypeName(), ""); ((PrimitiveList)list.dereference()).add(expressionValue); } // push the for each token id operandStack.push(forEachToken); // push name operandStack.push(name); // push list operandStack.push(list); // push the current index PrimitivePointer p = PrimitiveFactory.create(PrimitiveInteger.pseudocodeTypeName(), ""); ((PrimitiveInteger)p.dereference()).setValue(0); operandStack.push(p); } } private void actionSymbol11() throws DynamicMVCException { // {11} - Execute the . After reaching [next], return to the [forEach]. Change [name] to point to the next item in the . If no more items are in the collection, move to the line after the [next]. (Need to keep up with which item is current in collection. That can somehow be a part of the state class. State class variables that are not displayed? USE THE POSTFIX STACK?) //STORE THE CURRENT INDEX ON THE POSTFIX STACK //STORE THE COLLECTION ON THE STACK. //ALTERNATIVELY //STORE “THE REST OF THE COLLECTION” ON THE STACK (an iterator). //throw new DynamicMVCException("For each is not implemented"); // pop the [next] PostfixToken nextToken = (PostfixToken)operandStack.pop(); // move back to the top this.currentToken = Integer.parseInt(nextToken.getSemanticValue()); // and push a true operandStack.push(Boolean.TRUE); // push the next token back on the stack - no need, will be hit next time around // operandStack.push(nextToken); } private void actionSymbol12() throws DynamicMVCException { // {12} – pop [augendValue] and [*/] from the stack. // Pop it [augendValue] off the stack. // Pop the [MultiplicandValue] off the stack. // (It should be the next thing on top of the stack.) // Multiply or divide the two numbers and push the result back on the stack. PrimitivePointer augendValue = (PrimitivePointer)operandStack.pop(); PostfixToken operator = (PostfixToken)operandStack.pop(); PrimitivePointer multiplicandValue = (PrimitivePointer)operandStack.pop(); // multiplicandValue operator augendValue if (operator.getSourceValue().equals("*")) { operandStack.push(((PrimitiveInteger)multiplicandValue.dereference()).multiply(augendValue)); } else if (operator.getSourceValue().equals("/")) { operandStack.push(((PrimitiveInteger)multiplicandValue.dereference()).divide(augendValue)); } else if (operator.getSourceValue().equals("%")) { operandStack.push(((PrimitiveInteger)multiplicandValue.dereference()).mod(augendValue)); } else { throw new DynamicMVCException("Invalid operator."); } } private void actionSymbol13() { // {13} – pop [expressionValue] and [+-] and [augendValue] off the stack. // Evaluate . Pop it off the stack. // Pop the off the stack. // (It should be the next thing on top of the stack.) // Add or subtract the two numbers and push the result back on the stack. PrimitivePointer expressionValue = (PrimitivePointer)operandStack.pop(); PostfixToken operator = (PostfixToken)operandStack.pop(); PrimitivePointer augendValue = (PrimitivePointer)operandStack.pop(); // augendValue operator augendValue if (operator.getSourceValue().equals("+")) { operandStack.push(((PrimitiveInteger)augendValue.dereference()).add(expressionValue)); } else if (operator.getSourceValue().equals("-")) { operandStack.push(((PrimitiveInteger)augendValue.dereference()).subtract(expressionValue)); } } private void actionSymbol14() throws DynamicMVCException { // {14} – pop [expression(1)Value] [relationalOperator] and [expression(2)Value] from the stack. PrimitivePointer expression2Value; PrimitivePointer expression1Value; if (operandStack.peek() instanceof Boolean) { Boolean b = (Boolean)operandStack.pop(); expression2Value = PrimitiveFactory.create(PrimitiveBoolean.pseudocodeTypeName(), ""); ((PrimitiveBoolean)expression2Value.dereference()).setValue(b.booleanValue()); } else { expression2Value = (PrimitivePointer)operandStack.pop(); } // HACK FIX // ->[(]{1}[)]{1}{1} // while mst.length() < (graph.vertices.length() - 1) // the above line of code can leave a spurious state on the stack // I think it is caused by the parenthesis // Altered the rule in the grammar to inculde the extra {1} // to pop the state off the stack while (!(operandStack.peek() instanceof PostfixToken)) { operandStack.pop(); } PostfixToken relationalOperator = (PostfixToken)operandStack.pop(); if (operandStack.peek() instanceof Boolean) { Boolean b = (Boolean)operandStack.pop(); expression1Value = PrimitiveFactory.create(PrimitiveBoolean.pseudocodeTypeName(), ""); ((PrimitiveBoolean)expression1Value.dereference()).setValue(b.booleanValue()); } else { expression1Value = (PrimitivePointer)operandStack.pop(); } int compareTo = expression1Value.dereference().compareTo(expression2Value.dereference()); if(relationalOperator.getSourceValue().equals(">=") || relationalOperator.getSourceValue().equals("gte")) { operandStack.push(new Boolean(compareTo >= 0)); } else if (relationalOperator.getSourceValue().equals(">") || relationalOperator.getSourceValue().equals("gt")) { operandStack.push(new Boolean(compareTo > 0)); } else if (relationalOperator.getSourceValue().equals("=")) { operandStack.push(new Boolean(compareTo == 0)); } else if (relationalOperator.getSourceValue().equals("<") || relationalOperator.getSourceValue().equals("lt")) { operandStack.push(new Boolean(compareTo < 0)); } else if (relationalOperator.getSourceValue().equals("<=") || relationalOperator.getSourceValue().equals("lte")) { operandStack.push(new Boolean(compareTo <= 0)); } else if (relationalOperator.getSourceValue().equals("!=")) { operandStack.push(new Boolean(compareTo != 0)); } } private void actionSymbol15() { //The instance name is the name of the variable in the current context. By default, the current context is the top of the call stack. //Save [name]. // //{15} - PUSH [name] ON THE POSTFIX STACK. //PUSH [true] ON THE POSTFIX STACK. THIS MEANS THAT IT IS [true] THAT THIS IS A PROPERTY; CALLING A METHOD WILL REPALCE THIS [true] WITH A [false]. // // just push true on the stack operandStack.push(Boolean.TRUE); } private void actionSymbol16() throws DynamicMVCException { //POP THE TOP THING OFF OF THE POSTFIX STACK. //IF IT IS , THEN THE LAST THING ON THE POSTFIX STACK IS THE NAME OF A PROPERTY OF THE OBJECT REFERENCE BENEATH THE NAME ON THE POSTFIX STACK. //POP THE FIRST THING OFF THE POSTFIX STACK. THIS IS THE [name] OF THE PROPERTY. //POP THE NEXT THING OFF THE POSTFIX STACK. THIS IS THE “address” (actually a reference) OF THE OBJECT. //RETRIEVE [name] FROM [reference]. //PUSH IT ON THE POSTFIX STACK. // //IF IT IS , THEN THE LAST THING ON THE POSTFIX STACK IS THE RETURN VALUE OF A METHOD CALL. LEAVE IT THERE. Boolean isProperty = (Boolean)operandStack.pop(); if (isProperty.booleanValue()) { // then this is a property of the object beneath this on the stack or else a pointer to a constant, so nothing needs to be done if (operandStack.peek() instanceof PostfixToken) { // the top thing is the name of the property PostfixToken t = (PostfixToken)operandStack.pop(); // the next thing is the context of the property PrimitivePointer context = (PrimitivePointer)operandStack.pop(); PrimitivePointer value = ((Primitive)context.dereference()).get(t.getSourceValue()); operandStack.push(value); } else { // this is a primitive pointer to a constant; // just leave it alone } } else { // top thing on stack is parameter list ArrayList arguments = (ArrayList)operandStack.pop(); // the next thing is the function name PostfixToken functionName = (PostfixToken)operandStack.pop(); // the next thing is the context PrimitivePointer context = (PrimitivePointer)operandStack.pop(); // call the method Object result = context.execute(functionName.getSourceValue(), arguments); // if the result is a function address // then push the return address (here - the current token) // and also push the arguments if (result instanceof Function) { Function f = (Function)result; operandStack.push(currentState); // create a new context currentState = new State(); View.updateState(currentState); // make sure to not hide any of the variables in the new context view.pushNewHiddenVariableContext(); // check the size of the parameter list if(arguments.size() != f.getParameterList().size()) { throw new DynamicMVCException("Invalid number of arguments to functin call."); } HashMap originalNames = new HashMap(); // add the collected arguments to the state // make sure to use the names from the function's formal parameters for(int i = 0; i < f.getParameterList().size(); i++) { PrimitivePointer parameter = arguments.get(i); Primitive formalParameter = f.getParameterList().get(i); if (parameter.dereference().getType().equals(formalParameter.getType())) { parameter.setName(formalParameter.getName()); // MAYBE HERE originalNames.put(parameter, parameter.dereference().getName()); originalNames.put(parameter, parameter.getName()); //parameter.dereference().setName(formalParameter.getName()); currentState.setStateVariable(formalParameter.getName(), parameter); currentState.setInput(formalParameter.getName(), parameter); } } operandStack.push(originalNames); operandStack.push(new Integer(this.currentToken)); currentToken = f.getAddress() + 1;// +1 to skip past a new line // push something on the call stack // if the stack is empty and this is a function into which to step // or something is already on the stack if (!callStack.empty() || stepOverFunctions.contains(f.getName())) { callStack.push(new Object()); } } else { // push the result operandStack.push(result); } } } private void actionSymbol17() throws DynamicMVCException { //THE TOP THING ON THE POSTFIX STACK SHOULD BE A (indicating that this is a property). //POP IT OFF THE STACK //THE LAST THING ON THE POSTFIX STACK IS THE NAME OF A PROPERTY OF THE OBJECT REFERENCE BENEATH THE NAME ON THE POSTFIX STACK. //POP THE FIRST THING OFF THE POSTFIX STACK. THIS IS THE [name] OF THE PROPERTY. //POP THE NEXT THING OFF THE POSTFIX STACK. THIS IS THE “address” (actually a reference) OF THE OBJECT. //RETRIEVE [name] FROM [reference]. //PUSH IT ON THE POSTFIX STACK. operandStack.pop(); // the dot Boolean prop = (Boolean)operandStack.pop(); if (prop.equals(Boolean.FALSE)) { // top thing on stack is parameter list ArrayList arguments = (ArrayList)operandStack.pop(); // the next thing is the function name PostfixToken functionName = (PostfixToken)operandStack.pop(); // the next thing is the context PrimitivePointer context = (PrimitivePointer)operandStack.pop(); // call the method Object result = context.execute(functionName.getSourceValue(), arguments); operandStack.push(result); } else { // the top thing is the name of the property or else a constant if (operandStack.peek() instanceof PostfixToken) { PostfixToken t = (PostfixToken)operandStack.pop(); // the next thing is the context of the property Primitive context = ((PrimitivePointer)operandStack.pop()).dereference(); PrimitivePointer value = context.get(t.getSourceValue()); operandStack.push(value); } else { // this is a constant // leave it alone } } } private void actionSymbol18() throws DynamicMVCException { //{18} - //COLLECT . //POP THE OFF OF THE POSTFIX STACK. //(the indicates a property (which was an incorrect "guess" by the interpretter from earlier). //since this has parameters, it is a method. will need to push a after evaluating the function.) //POP [name] OFF THE POSTFIX STACK. //POP THE NEXT THING OFF THE POSTFIX STACK. THIS IS THE “address” (actually a reference) OF THE OBJECT. //CALL THE METHOD OF THE OBJECT USING THE PARAMETER LIST. //PUSH THE RESULT ON THE POSTFIX STACK (should already be on the stack). // example // ~call~call~12~1, l: ], ~variableName~add~18~1, true, ~(~(~20~1, : 5, ~)~)~24~1 operandStack.pop(); // ) // start collecting arguments ArrayList arguments = new ArrayList(); Object t = operandStack.pop(); while(!isLeftParenthesisToken(t)) { // collect an argument PrimitivePointer argument = (PrimitivePointer)t; // add it to the list (in the beginning because of reverse order of arguments) arguments.add(0, argument); // the next thing is either a comma or a ( t = operandStack.pop(); // if it is a comma (not a left paren), remove it if (!isLeftParenthesisToken(t)) { t = operandStack.pop(); // find the next argument } } operandStack.pop(); // the true indicating a property reference operandStack.push(arguments); operandStack.push(Boolean.FALSE); // indicate this is not a property reference (so it is a method) } private boolean isLeftParenthesisToken(Object token) { if (token instanceof PostfixToken) { PostfixToken t = (PostfixToken)token; if (t.getSourceValue().equals("(")) { return true; } } return false; } private void actionSymbol19() { // no need to do anything } private void actionSymbol20() { // no need to do anything } private void actionSymbol21() throws DynamicMVCException { // {21} – pop [expressionValue] and [return] from the stack. // also pop the return address and the state // push [expressionValue] on the stack. // The return from the function call will expect the return value of the function // to be on the postfix stack. PrimitivePointer expressionValue = (PrimitivePointer)operandStack.pop(); operandStack.pop(); // return Integer returnAddress = (Integer)operandStack.pop(); HashMap originalNames = (HashMap)operandStack.pop(); State previousState = (State)operandStack.pop(); this.currentState = previousState; this.currentToken = returnAddress.intValue(); // restore the original variable names for(PrimitivePointer p : originalNames.keySet()) { String originalName = originalNames.get(p); p.setName(originalName); //p.dereference().setName(originalName); } View.updateState(this.currentState); // forget about current hidden variables view.popHiddenVariableContext(); // push the result back on the stack operandStack.push(expressionValue); // clear the top thing off of the call stack // if the callStack is already empty, // then a function was stepped into if (!callStack.empty()) { callStack.pop(); } } private void actionSymbol22() throws DynamicMVCException { // push a primitive version of the state on the stack PrimitivePointer s = currentState.getPrimitive(this.currentLineIndex(), getFunctions()); operandStack.push(s); } private void actionSymbol23() throws DynamicMVCException { // THIS COULD ALSO BE A STRING // convert the token to an Integer PostfixToken constant = (PostfixToken)operandStack.pop(); // also pop the superfluous context operandStack.pop(); PrimitivePointer p; p = getPrimitive(constant); operandStack.push(p); // also push a true to indicate that this is a "property" value // at least, that this is not a return value operandStack.push(Boolean.valueOf(true)); } private PrimitivePointer getPrimitive(PostfixToken token) { PrimitivePointer p; try { p = PrimitiveFactory.create(PrimitiveInteger.pseudocodeTypeName(), ""); ((PrimitiveInteger)p.dereference()).setValue(token.getSourceValue()); } catch (NumberFormatException ex) { if(token.getSourceValue().equals("true")) { p = PrimitiveFactory.create(PrimitiveBoolean.pseudocodeTypeName(), ""); ((PrimitiveBoolean)p.dereference()).setValue(true); } else if (token.getSourceValue().equals("false")) { p = PrimitiveFactory.create(PrimitiveBoolean.pseudocodeTypeName(), ""); ((PrimitiveBoolean)p.dereference()).setValue(false); } else { p = PrimitiveFactory.create(PrimitiveString.pseudocodeTypeName(), ""); ((PrimitiveString)p.dereference()).setValue(token.getSourceValue()); } } return p; } private void actionSymbol24() { view.render(); } private void actionSymbol25() throws DynamicMVCException { String message = ""; // [say] [(] {message} [)] operandStack.pop(); // ) if (operandStack.peek() instanceof PrimitivePointer) { PrimitivePointer p = (PrimitivePointer)operandStack.pop(); message = p.dereference().toPrimitiveString().getValue(); } else if (operandStack.peek() instanceof Primitive) { Primitive p = (Primitive)operandStack.pop(); message = p.toPrimitiveString().getValue(); } else { throw new DynamicMVCException("Unexpected value on operand stack: {" + operandStack.peek().toString() + "}."); } operandStack.pop(); // ) operandStack.pop(); // say view.showMessage(message); } private void actionSymbol26() { // read in the inputs view.readInputs(); } private void actionSymbol27() { view.showMessage("Please provide the inputs, then press 'Step'."); } private void actionSymbol28() { // pop the final return value operandStack.pop(); // pop the "call" keyword" operandStack.pop(); } private void actionSymbol29() { // THIS ALSO NEEDS TO CHECK FOR WHEN THE LOOP IS OVER // pop the index PrimitiveInteger index = (PrimitiveInteger)((PrimitivePointer)operandStack.pop()).dereference(); // pop list PrimitivePointer l = (PrimitivePointer)operandStack.pop(); PrimitiveList list = (PrimitiveList)l.dereference(); // pop name PostfixToken name = (PostfixToken)operandStack.pop(); // is the forEach loop finished? if (((PrimitiveInteger)list.length().dereference()).equals(index)) { // pop the forEach token PostfixToken forEachToken = (PostfixToken)operandStack.pop(); // remove the loop variable from the state this.currentState.removeStateVariable(name.getSourceValue()); // jump to the token after this one // skip to the pause past the action symbol after the next, the newline, and the action symbol to pop the newline currentToken = Integer.parseInt(forEachToken.getSemanticValue()) + 4; } else { // grab first thing in list PrimitivePointer p = list.get(index.getValue()); //p.dereference().setName(name.getSourceValue()); p.setName(name.getSourceValue()); // set state currentState.setStateVariable(p.getName(), p); // push name operandStack.push(name); // push rest of list operandStack.push(l); // push the next index PrimitivePointer one = PrimitiveFactory.create(PrimitiveInteger.pseudocodeTypeName(), ""); ((PrimitiveInteger)one.dereference()).setValue(1); operandStack.push(index.add(one)); } } private void actionSymbol30() { // push a false, indicating that the for each has not been executed yet operandStack.push(Boolean.FALSE); } private void actionSymbol31() { // the top symbol should either be a single true, or two falses Boolean b = (Boolean)operandStack.pop(); if (!b.booleanValue()) { operandStack.pop(); } } private void actionSymbol32() { // the top token should be a boolean // if it is true, then the expression does not need to be evaluated // so skip to the 10 token // use operandStack.size() - 4 to look before the "in", "variableName", and "forEach" (and 0-base) Boolean b = (Boolean)operandStack.get(operandStack.size() - 4); if (b.booleanValue()) { // then skip the expression PostfixToken t = postfixTokens.get(currentToken); while(!isActionSymbol10(t)) { currentToken++; t = postfixTokens.get(currentToken); } // push a dummy newline and dummy expression operandStack.push(new PrimitivePointer(-1)); operandStack.push(new PostfixToken("", "", "", -1)); } // otherwise, just stay where we are } private boolean isActionSymbol10(PostfixToken t) { if (t.getLexicalValue().equals("actionSymbol")) { if (t.getSourceValue().equals("10")) { return true; } } return false; } private void actionSymbol33() { view.render(); view.showMessage("Execution finished."); } private void actionSymbol34() { // or // pop the last expression, which should be boolean boolean b1; if (operandStack.peek() instanceof Boolean) { b1 = ((Boolean)operandStack.pop()).booleanValue(); } else { PrimitiveBoolean b = (PrimitiveBoolean)((PrimitivePointer)operandStack.pop()).dereference(); b1 = b.getValue(); } // pop the or operandStack.pop(); // pop the previous expression, which should be boolean boolean b2; if (operandStack.peek() instanceof Boolean) { b2 = ((Boolean)operandStack.pop()).booleanValue(); } else { PrimitiveBoolean b = (PrimitiveBoolean)((PrimitivePointer)operandStack.pop()).dereference(); b2 = b.getValue(); } // push the logical result Boolean result = b1 || b2; operandStack.push(result); } private void actionSymbol35() { // and // pop the last expression, which should be boolean boolean b1; if (operandStack.peek() instanceof Boolean) { b1 = ((Boolean)operandStack.pop()).booleanValue(); } else { PrimitiveBoolean b = (PrimitiveBoolean)((PrimitivePointer)operandStack.pop()).dereference(); b1 = b.getValue(); } // pop the and operandStack.pop(); // pop the previous expression, which should be boolean boolean b2; if (operandStack.peek() instanceof Boolean) { b2 = ((Boolean)operandStack.pop()).booleanValue(); } else { PrimitiveBoolean b = (PrimitiveBoolean)((PrimitivePointer)operandStack.pop()).dereference(); b2 = b.getValue(); } // push the logical result Boolean result = b1 && b2; operandStack.push(result); } private void actionSymbol36() { // pop the ending paren operandStack.pop(); // pop the value Object value = operandStack.pop(); // pop the spurious state operandStack.pop(); // push the value back operandStack.push(value); } private void actionSymbol37() { try { // the statement is finished // rather than just displaying the screen, // first ask the user to guess the new state // start the user with the saved state on the stack this.view.showAskState(currentState.getPrimitive(currentLineIndex()).deepCopy(new HashMap())); } catch (DynamicMVCException ex) { ex.printStackTrace(); } } // this is a bit of a hack public static String errorMessage = ""; public void compareState(PrimitivePointer guessState) { Primitive guess = guessState.dereference(); try { Primitive actual = this.currentState.getPrimitive(currentLineIndex(), getFunctions()).dereference(); if(actual.deepEquals(guess)) { view.showMessage("Good Job! Press step to continue."); } else { view.showMessage("Incorrect. Error: \"" + errorMessage + "\". Press step to continue"); } view.render(); } catch (DynamicMVCException ex) { ex.printStackTrace(); } // check to ensure guess and actual have all of the same values for variables } private void actionSymbol38() { try { // save the current state on the ask stack //askStack.push(this.currentState.getPrimitive(this.functions)); operandStack.pop(); // : operandStack.pop(); // ask this.view.pushAskState(currentState.getPrimitive(currentLineIndex()).deepCopy(new HashMap())); } catch (DynamicMVCException ex) { ex.printStackTrace(); } } private void actionSymbol39() { operandStack.push(Boolean.valueOf(false)); } private boolean actionSymbol40() throws DynamicMVCException { PostfixToken whileToken = (PostfixToken)operandStack.pop(); // the while Boolean shouldPause = (Boolean)operandStack.pop(); // whether or not to pause operandStack.push(whileToken); // check to see if this while statement is preceded by an ask // the postfix tokens will be of the form: // {38} - ask action symbol // {39} - first while symbol // [while] - whileToken // this is a hack // // also, don't do this the first time // the ask symbol is hit correctly in that case int potentialAskSymbolIndex = whileToken.getId() - 2; if (potentialAskSymbolIndex >= 0 && shouldPause.booleanValue()) { Object potentialAskSymbol = postfixTokens.get(potentialAskSymbolIndex); if (isActionSymbol38(potentialAskSymbol)) { this.view.renderPseudocode(); this.view.pushAskState(currentState.getPrimitive(currentLineIndex()).deepCopy(new HashMap())); // return false to ensure the while part is evaluated return false; } } return shouldPause.booleanValue(); } protected boolean isActionSymbol38(Object o) { if (o instanceof PostfixToken) { PostfixToken t = (PostfixToken)o; if (t.getLexicalValue().equals("actionSymbol")) { if (t.getSourceValue().equals("38")) { return true; } } } return false; } private void actionSymbol41() { operandStack.push(Boolean.valueOf(true)); } public ArrayList getStepOverFunctions() { return stepOverFunctions; } public void setStepOverFunctions(ArrayList stepOverFunctions) { this.stepOverFunctions = stepOverFunctions; } public ArrayList getFunctions() { return functions; } public void setFunctions(ArrayList functions) { this.functions = functions; } }