package processor; import java.util.Stack; import processor.Memory.Visibility; import processor.StackFrame.FrameType; public class PseudoCodeProcessor { public static enum CodeStatus { UNFINISHED, BREAKPOINT, FINISHED } private String currentDebugOutput; private Memory mem; private PseudoCodeNode programPointer; private Stack controlStack; private boolean skip = false; public PseudoCodeProcessor( PseudoCodeNode start ) { mem = new Memory(); mem.addFrame( new StackFrame( FrameType.FUNCTION ) ); programPointer = start; currentDebugOutput = ""; controlStack = new Stack<>(); } private CodeStatus selectNextNode( PseudoCodeNode next, PseudoCodeNode last ) { programPointer = next; last.setSelected( false ); switch( next.setSelected( true ) ) { case CONTINUE: skip = false; return CodeStatus.UNFINISHED; case SKIP: return forwardStepOverUntilNotSkip(); case STOP: return CodeStatus.BREAKPOINT; } return CodeStatus.UNFINISHED; } public CodeStatus forwardStep() { if( programPointer == null ) return CodeStatus.FINISHED; StackFrame before = mem.removeFrame(); mem.addFrame( before ); ControlFlow cf = null; if( mem.isDefined( "_call" + programPointer.getId(), Visibility.LOCAL ) ) { String name = "_call" + programPointer.getId(); mem.undeclare( name, Visibility.LOCAL ); cf = programPointer.emptyForwardStep( mem ); cf.setBackwardAction( (Memory m) -> { mem.declare( name, true, Visibility.LOCAL ); }); } else cf = programPointer.forwardStep( mem ); controlStack.push( cf ); currentDebugOutput = programPointer.getDebugOutput( mem ); switch( cf.getStatus() ) { case ControlFlow.STEP_INTO: if( mem.isDefined( "_returnTo" + programPointer.getId(), Visibility.GLOBAL ) ) { String name = "_returnTo" + programPointer.getId(); mem.declare( name, mem.read( name, Visibility.GLOBAL ), Visibility.LOCAL ); mem.undeclare( name, Visibility.GLOBAL ); cf.setBackwardAction( (Memory m) -> { mem.declare( name, mem.read( name, Visibility.LOCAL ), Visibility.GLOBAL ); mem.undeclare( name, Visibility.LOCAL ); }); } if( programPointer.getChildCount() == 0 ) throw new IllegalStateException( "A Codeline without sublines tried to make a STEP_INTO." ); else return selectNextNode( (PseudoCodeNode)programPointer.getFirstChild(), programPointer ); case ControlFlow.STEP_OVER: if( programPointer.getParent() == null ) return CodeStatus.FINISHED; if( before.isDefined( "_returnTo" + programPointer.getId() ) ) { String name = "_returnTo" + programPointer.getId(); PseudoCodeNode nextPC = before.get( name ); before.undeclare( name ); cf.setBackwardAction( (Memory m) -> { before.declare( name, nextPC ); }); return selectNextNode( nextPC, programPointer ); } PseudoCodeNode nextPC = (PseudoCodeNode) ((PseudoCodeNode)programPointer.getParent()).getChildAfter( programPointer ); if( nextPC == null ) return selectNextNode( (PseudoCodeNode)programPointer.getParent(), programPointer ); else return selectNextNode( nextPC, programPointer ); case ControlFlow.CALL: PseudoCodeNode f = cf.getFunction(); String name = "_call" + programPointer.getId(); mem.declare( name, true, Visibility.LOCAL ); mem.declare( "_returnTo" + f.getId(), cf.getJumpBack(), Visibility.GLOBAL ); cf.setBackwardAction( (Memory m) -> { m.undeclare( "_returnTo" + f.getId(), Visibility.GLOBAL ); m.undeclare( name, Visibility.LOCAL ); }); return selectNextNode( f, programPointer ); } throw new IllegalStateException( "Unknown ControlFlow action" ); } private CodeStatus forwardStepOverUntilNotSkip() { skip = true; if( programPointer == null ) return CodeStatus.FINISHED; int stackSize = mem.getSize(); CodeStatus status = CodeStatus.UNFINISHED; do { status = forwardStep(); } while( mem.getSize() > stackSize && status == CodeStatus.UNFINISHED && skip ); return status; } public CodeStatus forwardStepOver() { if( programPointer == null ) return CodeStatus.FINISHED; int stackSize = mem.getSize(); CodeStatus status = CodeStatus.UNFINISHED; do { status = forwardStep(); } while( mem.getSize() > stackSize && status == CodeStatus.UNFINISHED ); return status; } public CodeStatus forwardStepOut() { if( programPointer == null ) return CodeStatus.FINISHED; int stackSize = mem.getSize(); CodeStatus status = CodeStatus.UNFINISHED; do { status = forwardStep(); } while( mem.getSize() >= stackSize && status == CodeStatus.UNFINISHED ); return status; } private CodeStatus selectBeforeNode( PseudoCodeNode next, PseudoCodeNode last ) { programPointer = next; last.setSelected( false ); switch( next.setSelected( true ) ) { case CONTINUE: skip = false; return CodeStatus.UNFINISHED; case SKIP: return backwardStepOverUntilNotSkip(); case STOP: return CodeStatus.BREAKPOINT; } return CodeStatus.UNFINISHED; } public CodeStatus backwardStep() { if( programPointer == null || controlStack.isEmpty() ) return CodeStatus.FINISHED; ControlFlow cf = controlStack.pop(); PseudoCodeNode nextPC = cf.getJumpBack(); cf.backward( mem ); nextPC.backwardStep( mem ); currentDebugOutput = nextPC.getDebugOutput( mem ); return selectBeforeNode( nextPC, programPointer ); } public CodeStatus backwardStepOverUntilNotSkip() { skip = true; if( programPointer == null ) return CodeStatus.FINISHED; int stackSize = mem.getSize(); CodeStatus status = CodeStatus.UNFINISHED; do { status = backwardStep(); } while( mem.getSize() > stackSize && status == CodeStatus.UNFINISHED && skip ); return status; } public CodeStatus backwardStepOver() { if( programPointer == null ) return CodeStatus.FINISHED; int stackSize = mem.getSize(); CodeStatus status = CodeStatus.UNFINISHED; do { status = backwardStep(); } while( mem.getSize() > stackSize && status == CodeStatus.UNFINISHED ); return status; } public CodeStatus backwardStepOut() { if( programPointer == null ) return CodeStatus.FINISHED; int stackSize = mem.getSize(); CodeStatus status = CodeStatus.UNFINISHED; do { status = backwardStep(); } while( mem.getSize() >= stackSize && status == CodeStatus.UNFINISHED ); return status; } public Memory getMemory() { return mem; } public String getDebugOutput() { return currentDebugOutput; } }