/*
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;
}
}