--- /dev/null
+//===-- Execution.cpp - Implement code to simulate the program ------------===//
+//
+// This file contains the actual instruction interpreter.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Interpreter.h"
+#include "ExecutionAnnotations.h"
+#include "llvm/iOther.h"
+#include "llvm/iTerminators.h"
+#include "llvm/Type.h"
+#include "llvm/ConstPoolVals.h"
+#include "llvm/Assembly/Writer.h"
+
+static unsigned getOperandSlot(Value *V) {
+ SlotNumber *SN = (SlotNumber*)V->getAnnotation(SlotNumberAID);
+ assert(SN && "Operand does not have a slot number annotation!");
+ return SN->SlotNum;
+}
+
+#define GET_CONST_VAL(TY, CLASS) \
+ case Type::TY##TyID: Result.TY##Val = ((CLASS*)CPV)->getValue(); break
+
+static GenericValue getOperandValue(Value *V, ExecutionContext &SF) {
+ if (ConstPoolVal *CPV = V->castConstant()) {
+ GenericValue Result;
+ switch (CPV->getType()->getPrimitiveID()) {
+ GET_CONST_VAL(Bool , ConstPoolBool);
+ GET_CONST_VAL(UByte , ConstPoolUInt);
+ GET_CONST_VAL(SByte , ConstPoolSInt);
+ GET_CONST_VAL(UShort , ConstPoolUInt);
+ GET_CONST_VAL(Short , ConstPoolSInt);
+ GET_CONST_VAL(UInt , ConstPoolUInt);
+ GET_CONST_VAL(Int , ConstPoolSInt);
+ GET_CONST_VAL(Float , ConstPoolFP);
+ GET_CONST_VAL(Double , ConstPoolFP);
+ default:
+ cout << "ERROR: Constant unimp for type: " << CPV->getType() << endl;
+ }
+ return Result;
+ } else {
+ unsigned TyP = V->getType()->getUniqueID(); // TypePlane for value
+ return SF.Values[TyP][getOperandSlot(V)];
+ }
+}
+
+static void SetValue(Value *V, GenericValue Val, ExecutionContext &SF) {
+ unsigned TyP = V->getType()->getUniqueID(); // TypePlane for value
+ SF.Values[TyP][getOperandSlot(V)] = Val;
+}
+
+
+
+//===----------------------------------------------------------------------===//
+// Binary Instruction Implementations
+//===----------------------------------------------------------------------===//
+
+#define IMPLEMENT_BINARY_OPERATOR(OP, TY) \
+ case Type::TY##TyID: Dest.TY##Val = Src1.TY##Val OP Src2.TY##Val; break
+
+static GenericValue executeAddInst(GenericValue Src1, GenericValue Src2,
+ const Type *Ty, ExecutionContext &SF) {
+ GenericValue Dest;
+ switch (Ty->getPrimitiveID()) {
+ IMPLEMENT_BINARY_OPERATOR(+, UByte);
+ IMPLEMENT_BINARY_OPERATOR(+, SByte);
+ IMPLEMENT_BINARY_OPERATOR(+, UShort);
+ IMPLEMENT_BINARY_OPERATOR(+, Short);
+ IMPLEMENT_BINARY_OPERATOR(+, UInt);
+ IMPLEMENT_BINARY_OPERATOR(+, Int);
+ IMPLEMENT_BINARY_OPERATOR(+, Float);
+ IMPLEMENT_BINARY_OPERATOR(+, Double);
+ case Type::ULongTyID:
+ case Type::LongTyID:
+ default:
+ cout << "Unhandled type for Add instruction: " << Ty << endl;
+ }
+ return Dest;
+}
+
+static GenericValue executeSubInst(GenericValue Src1, GenericValue Src2,
+ const Type *Ty, ExecutionContext &SF) {
+ GenericValue Dest;
+ switch (Ty->getPrimitiveID()) {
+ IMPLEMENT_BINARY_OPERATOR(-, UByte);
+ IMPLEMENT_BINARY_OPERATOR(-, SByte);
+ IMPLEMENT_BINARY_OPERATOR(-, UShort);
+ IMPLEMENT_BINARY_OPERATOR(-, Short);
+ IMPLEMENT_BINARY_OPERATOR(-, UInt);
+ IMPLEMENT_BINARY_OPERATOR(-, Int);
+ IMPLEMENT_BINARY_OPERATOR(-, Float);
+ IMPLEMENT_BINARY_OPERATOR(-, Double);
+ case Type::ULongTyID:
+ case Type::LongTyID:
+ default:
+ cout << "Unhandled type for Sub instruction: " << Ty << endl;
+ }
+ return Dest;
+}
+
+#define IMPLEMENT_SETCC(OP, TY) \
+ case Type::TY##TyID: Dest.BoolVal = Src1.TY##Val OP Src2.TY##Val; break
+
+
+static GenericValue executeSetEQInst(GenericValue Src1, GenericValue Src2,
+ const Type *Ty, ExecutionContext &SF) {
+ GenericValue Dest;
+ switch (Ty->getPrimitiveID()) {
+ IMPLEMENT_SETCC(==, UByte);
+ IMPLEMENT_SETCC(==, SByte);
+ IMPLEMENT_SETCC(==, UShort);
+ IMPLEMENT_SETCC(==, Short);
+ IMPLEMENT_SETCC(==, UInt);
+ IMPLEMENT_SETCC(==, Int);
+ IMPLEMENT_SETCC(==, Float);
+ IMPLEMENT_SETCC(==, Double);
+ case Type::ULongTyID:
+ case Type::LongTyID:
+ default:
+ cout << "Unhandled type for SetEQ instruction: " << Ty << endl;
+ }
+ return Dest;
+}
+
+static GenericValue executeSetNEInst(GenericValue Src1, GenericValue Src2,
+ const Type *Ty, ExecutionContext &SF) {
+ GenericValue Dest;
+ switch (Ty->getPrimitiveID()) {
+ IMPLEMENT_SETCC(!=, UByte);
+ IMPLEMENT_SETCC(!=, SByte);
+ IMPLEMENT_SETCC(!=, UShort);
+ IMPLEMENT_SETCC(!=, Short);
+ IMPLEMENT_SETCC(!=, UInt);
+ IMPLEMENT_SETCC(!=, Int);
+ IMPLEMENT_SETCC(!=, Float);
+ IMPLEMENT_SETCC(!=, Double);
+ case Type::ULongTyID:
+ case Type::LongTyID:
+ default:
+ cout << "Unhandled type for SetNE instruction: " << Ty << endl;
+ }
+ return Dest;
+}
+
+static GenericValue executeSetLEInst(GenericValue Src1, GenericValue Src2,
+ const Type *Ty, ExecutionContext &SF) {
+ GenericValue Dest;
+ switch (Ty->getPrimitiveID()) {
+ IMPLEMENT_SETCC(<=, UByte);
+ IMPLEMENT_SETCC(<=, SByte);
+ IMPLEMENT_SETCC(<=, UShort);
+ IMPLEMENT_SETCC(<=, Short);
+ IMPLEMENT_SETCC(<=, UInt);
+ IMPLEMENT_SETCC(<=, Int);
+ IMPLEMENT_SETCC(<=, Float);
+ IMPLEMENT_SETCC(<=, Double);
+ case Type::ULongTyID:
+ case Type::LongTyID:
+ default:
+ cout << "Unhandled type for SetLE instruction: " << Ty << endl;
+ }
+ return Dest;
+}
+
+static GenericValue executeSetGEInst(GenericValue Src1, GenericValue Src2,
+ const Type *Ty, ExecutionContext &SF) {
+ GenericValue Dest;
+ switch (Ty->getPrimitiveID()) {
+ IMPLEMENT_SETCC(>=, UByte);
+ IMPLEMENT_SETCC(>=, SByte);
+ IMPLEMENT_SETCC(>=, UShort);
+ IMPLEMENT_SETCC(>=, Short);
+ IMPLEMENT_SETCC(>=, UInt);
+ IMPLEMENT_SETCC(>=, Int);
+ IMPLEMENT_SETCC(>=, Float);
+ IMPLEMENT_SETCC(>=, Double);
+ case Type::ULongTyID:
+ case Type::LongTyID:
+ default:
+ cout << "Unhandled type for SetGE instruction: " << Ty << endl;
+ }
+ return Dest;
+}
+
+static GenericValue executeSetLTInst(GenericValue Src1, GenericValue Src2,
+ const Type *Ty, ExecutionContext &SF) {
+ GenericValue Dest;
+ switch (Ty->getPrimitiveID()) {
+ IMPLEMENT_SETCC(<, UByte);
+ IMPLEMENT_SETCC(<, SByte);
+ IMPLEMENT_SETCC(<, UShort);
+ IMPLEMENT_SETCC(<, Short);
+ IMPLEMENT_SETCC(<, UInt);
+ IMPLEMENT_SETCC(<, Int);
+ IMPLEMENT_SETCC(<, Float);
+ IMPLEMENT_SETCC(<, Double);
+ case Type::ULongTyID:
+ case Type::LongTyID:
+ default:
+ cout << "Unhandled type for SetLT instruction: " << Ty << endl;
+ }
+ return Dest;
+}
+
+static GenericValue executeSetGTInst(GenericValue Src1, GenericValue Src2,
+ const Type *Ty, ExecutionContext &SF) {
+ GenericValue Dest;
+ switch (Ty->getPrimitiveID()) {
+ IMPLEMENT_SETCC(>, UByte);
+ IMPLEMENT_SETCC(>, SByte);
+ IMPLEMENT_SETCC(>, UShort);
+ IMPLEMENT_SETCC(>, Short);
+ IMPLEMENT_SETCC(>, UInt);
+ IMPLEMENT_SETCC(>, Int);
+ IMPLEMENT_SETCC(>, Float);
+ IMPLEMENT_SETCC(>, Double);
+ case Type::ULongTyID:
+ case Type::LongTyID:
+ default:
+ cout << "Unhandled type for SetGT instruction: " << Ty << endl;
+ }
+ return Dest;
+}
+
+static void executeBinaryInst(BinaryOperator *I, ExecutionContext &SF) {
+ const Type *Ty = I->getOperand(0)->getType();
+ GenericValue Src1 = getOperandValue(I->getOperand(0), SF);
+ GenericValue Src2 = getOperandValue(I->getOperand(1), SF);
+ GenericValue R; // Result
+
+ switch (I->getOpcode()) {
+ case Instruction::Add: R = executeAddInst(Src1, Src2, Ty, SF); break;
+ case Instruction::Sub: R = executeSubInst(Src1, Src2, Ty, SF); break;
+ case Instruction::SetEQ: R = executeSetEQInst(Src1, Src2, Ty, SF); break;
+ case Instruction::SetNE: R = executeSetNEInst(Src1, Src2, Ty, SF); break;
+ case Instruction::SetLE: R = executeSetLEInst(Src1, Src2, Ty, SF); break;
+ case Instruction::SetGE: R = executeSetGEInst(Src1, Src2, Ty, SF); break;
+ case Instruction::SetLT: R = executeSetLTInst(Src1, Src2, Ty, SF); break;
+ case Instruction::SetGT: R = executeSetGTInst(Src1, Src2, Ty, SF); break;
+ default:
+ cout << "Don't know how to handle this binary operator!\n-->" << I;
+ }
+
+ SetValue(I, R, SF);
+}
+
+
+//===----------------------------------------------------------------------===//
+// Terminator Instruction Implementations
+//===----------------------------------------------------------------------===//
+
+void Interpreter::executeRetInst(ReturnInst *I, ExecutionContext &SF) {
+ const Type *RetTy = 0;
+ GenericValue Result;
+
+ // Save away the return value... (if we are not 'ret void')
+ if (I->getNumOperands()) {
+ RetTy = I->getReturnValue()->getType();
+ Result = getOperandValue(I->getReturnValue(), SF);
+ }
+
+ // Save previously executing meth
+ const Method *M = ECStack.back().CurMethod;
+
+ // Pop the current stack frame... this invalidates SF
+ ECStack.pop_back();
+
+ if (ECStack.empty()) { // Finished main. Put result into exit code...
+ if (RetTy) { // Nonvoid return type?
+ cout << "Method " << M->getType() << " \"" << M->getName()
+ << "\" returned ";
+ printValue(RetTy, Result);
+ cout << endl;
+
+ if (RetTy->isIntegral())
+ ExitCode = Result.SByteVal; // Capture the exit code of the program
+ } else {
+ ExitCode = 0;
+ }
+ return;
+ }
+
+ // If we have a previous stack frame, and we have a previous call, fill in
+ // the return value...
+ //
+ ExecutionContext &NewSF = ECStack.back();
+ if (NewSF.Caller) {
+ if (NewSF.Caller->getType() != Type::VoidTy) // Save result...
+ SetValue(NewSF.Caller, Result, NewSF);
+
+ NewSF.Caller = 0; // We returned from the call...
+ }
+}
+
+void Interpreter::executeBrInst(BranchInst *I, ExecutionContext &SF) {
+ SF.PrevBB = SF.CurBB; // Update PrevBB so that PHI nodes work...
+ BasicBlock *Dest;
+
+ Dest = I->getSuccessor(0); // Uncond branches have a fixed dest...
+ if (!I->isUnconditional()) {
+ if (getOperandValue(I->getCondition(), SF).BoolVal == 0) // If false cond...
+ Dest = I->getSuccessor(1);
+ }
+ SF.CurBB = Dest; // Update CurBB to branch destination
+ SF.CurInst = SF.CurBB->begin(); // Update new instruction ptr...
+}
+
+//===----------------------------------------------------------------------===//
+// Miscellaneous Instruction Implementations
+//===----------------------------------------------------------------------===//
+
+void Interpreter::executeCallInst(CallInst *I, ExecutionContext &SF) {
+ ECStack.back().Caller = I;
+ callMethod(I->getCalledMethod(), &ECStack.back());
+}
+
+static void executePHINode(PHINode *I, ExecutionContext &SF) {
+ BasicBlock *PrevBB = SF.PrevBB;
+ Value *IncomingValue = 0;
+
+ // Search for the value corresponding to this previous bb...
+ for (unsigned i = I->getNumIncomingValues(); i > 0;) {
+ if (I->getIncomingBlock(--i) == PrevBB) {
+ IncomingValue = I->getIncomingValue(i);
+ break;
+ }
+ }
+ assert(IncomingValue && "No PHI node predecessor for current PrevBB!");
+
+ // Found the value, set as the result...
+ SetValue(I, getOperandValue(IncomingValue, SF), SF);
+}
+
+
+
+
+
+//===----------------------------------------------------------------------===//
+// Dispatch and Execution Code
+//===----------------------------------------------------------------------===//
+
+MethodInfo::MethodInfo(Method *M) : Annotation(MethodInfoAID) {
+ // Assign slot numbers to the method arguments...
+ const Method::ArgumentListType &ArgList = M->getArgumentList();
+ for (Method::ArgumentListType::const_iterator AI = ArgList.begin(),
+ AE = ArgList.end(); AI != AE; ++AI) {
+ MethodArgument *MA = *AI;
+ MA->addAnnotation(new SlotNumber(getValueSlot(MA)));
+ }
+
+ // Iterate over all of the instructions...
+ unsigned InstNum = 0;
+ for (Method::inst_iterator MI = M->inst_begin(), ME = M->inst_end();
+ MI != ME; ++MI) {
+ Instruction *I = *MI; // For each instruction...
+ I->addAnnotation(new InstNumber(++InstNum, getValueSlot(I))); // Add Annote
+ }
+}
+
+unsigned MethodInfo::getValueSlot(const Value *V) {
+ unsigned Plane = V->getType()->getUniqueID();
+ if (Plane >= NumPlaneElements.size())
+ NumPlaneElements.resize(Plane+1, 0);
+ return NumPlaneElements[Plane]++;
+}
+
+
+void Interpreter::initializeExecutionEngine() {
+ AnnotationManager::registerAnnotationFactory(MethodInfoAID, CreateMethodInfo);
+}
+
+
+
+//===----------------------------------------------------------------------===//
+// callMethod - Execute the specified method...
+//
+void Interpreter::callMethod(Method *M, ExecutionContext *CallingSF = 0) {
+ if (M->isExternal()) {
+ // Handle builtin methods
+ cout << "Error: Method '" << M->getName() << "' is external!\n";
+ return;
+ }
+
+ // Process the method, assigning instruction numbers to the instructions in
+ // the method. Also calculate the number of values for each type slot active.
+ //
+ MethodInfo *MethInfo = (MethodInfo*)M->getOrCreateAnnotation(MethodInfoAID);
+
+ ECStack.push_back(ExecutionContext()); // Make a new stack frame...
+ ExecutionContext &StackFrame = ECStack.back(); // Fill it in...
+ StackFrame.CurMethod = M;
+ StackFrame.CurBB = M->front();
+ StackFrame.CurInst = StackFrame.CurBB->begin();
+ StackFrame.MethInfo = MethInfo;
+
+ // Initialize the values to nothing...
+ StackFrame.Values.resize(MethInfo->NumPlaneElements.size());
+ for (unsigned i = 0; i < MethInfo->NumPlaneElements.size(); ++i)
+ StackFrame.Values[i].resize(MethInfo->NumPlaneElements[i]);
+
+ StackFrame.PrevBB = 0; // No previous BB for PHI nodes...
+
+ // Run through the method arguments and initialize their values...
+ if (CallingSF) {
+ CallInst *Call = CallingSF->Caller;
+ assert(Call && "Caller improperly initialized!");
+
+ unsigned i = 0;
+ for (Method::ArgumentListType::iterator MI = M->getArgumentList().begin(),
+ ME = M->getArgumentList().end(); MI != ME; ++MI, ++i) {
+ Value *V = Call->getOperand(i+1);
+ MethodArgument *MA = *MI;
+
+ SetValue(MA, getOperandValue(V, *CallingSF), StackFrame);
+ }
+ }
+}
+
+// executeInstruction - Interpret a single instruction, increment the "PC", and
+// return true if the next instruction is a breakpoint...
+//
+bool Interpreter::executeInstruction() {
+ assert(!ECStack.empty() && "No program running, cannot execute inst!");
+
+ ExecutionContext &SF = ECStack.back(); // Current stack frame
+ Instruction *I = *SF.CurInst++; // Increment before execute
+
+ if (I->isBinaryOp()) {
+ executeBinaryInst((BinaryOperator*)I, SF);
+ } else {
+ switch (I->getOpcode()) {
+ case Instruction::Ret: executeRetInst ((ReturnInst*)I, SF); break;
+ case Instruction::Br: executeBrInst ((BranchInst*)I, SF); break;
+ case Instruction::Call: executeCallInst ((CallInst*) I, SF); break;
+ case Instruction::PHINode: executePHINode ((PHINode*) I, SF); break;
+ default:
+ cout << "Don't know how to execute this instruction!\n-->" << I;
+ }
+ }
+
+ // Reset the current frame location to the top of stack
+ CurFrame = ECStack.size()-1;
+
+ if (CurFrame == -1) return false; // No breakpoint if no code
+
+ // Return true if there is a breakpoint annotation on the instruction...
+ return (*ECStack[CurFrame].CurInst)->getAnnotation(BreakpointAID) != 0;
+}
+
+void Interpreter::stepInstruction() { // Do the 'step' command
+ if (ECStack.empty()) {
+ cout << "Error: no program running, cannot step!\n";
+ return;
+ }
+
+ // Run an instruction...
+ executeInstruction();
+
+ // Print the next instruction to execute...
+ printCurrentInstruction();
+}
+
+// --- UI Stuff...
+
+
+
+void Interpreter::nextInstruction() { // Do the 'next' command
+ if (ECStack.empty()) {
+ cout << "Error: no program running, cannot 'next'!\n";
+ return;
+ }
+
+ // If this is a call instruction, step over the call instruction...
+ // TODO: ICALL, CALL WITH, ...
+ if ((*ECStack.back().CurInst)->getOpcode() == Instruction::Call) {
+ // Step into the function...
+ if (executeInstruction()) {
+ // Hit a breakpoint, print current instruction, then return to user...
+ cout << "Breakpoint hit!\n";
+ printCurrentInstruction();
+ return;
+ }
+
+ // Finish executing the function...
+ finish();
+ } else {
+ // Normal instruction, just step...
+ stepInstruction();
+ }
+}
+
+void Interpreter::run() {
+ if (ECStack.empty()) {
+ cout << "Error: no program running, cannot run!\n";
+ return;
+ }
+
+ bool HitBreakpoint = false;
+ while (!ECStack.empty() && !HitBreakpoint) {
+ // Run an instruction...
+ HitBreakpoint = executeInstruction();
+ }
+
+ if (HitBreakpoint) {
+ cout << "Breakpoint hit!\n";
+ }
+
+ // Print the next instruction to execute...
+ printCurrentInstruction();
+}
+
+void Interpreter::finish() {
+ if (ECStack.empty()) {
+ cout << "Error: no program running, cannot run!\n";
+ return;
+ }
+
+ unsigned StackSize = ECStack.size();
+ bool HitBreakpoint = false;
+ while (ECStack.size() >= StackSize && !HitBreakpoint) {
+ // Run an instruction...
+ HitBreakpoint = executeInstruction();
+ }
+
+ if (HitBreakpoint) {
+ cout << "Breakpoint hit!\n";
+ }
+
+ // Print the next instruction to execute...
+ printCurrentInstruction();
+}
+
+
+
+// printCurrentInstruction - Print out the instruction that the virtual PC is
+// at, or fail silently if no program is running.
+//
+void Interpreter::printCurrentInstruction() {
+ if (!ECStack.empty()) {
+ Instruction *I = *ECStack.back().CurInst;
+ InstNumber *IN = (InstNumber*)I->getAnnotation(SlotNumberAID);
+ assert(IN && "Instruction has no numbering annotation!");
+ cout << "#" << IN->InstNum << I;
+ }
+}
+
+void Interpreter::printValue(const Type *Ty, GenericValue V) {
+ cout << Ty << " ";
+
+ switch (Ty->getPrimitiveID()) {
+ case Type::BoolTyID: cout << (V.BoolVal?"true":"false"); break;
+ case Type::SByteTyID: cout << V.SByteVal; break;
+ case Type::UByteTyID: cout << V.UByteVal; break;
+ case Type::ShortTyID: cout << V.ShortVal; break;
+ case Type::UShortTyID: cout << V.UShortVal; break;
+ case Type::IntTyID: cout << V.IntVal; break;
+ case Type::UIntTyID: cout << V.UIntVal; break;
+ case Type::FloatTyID: cout << V.FloatVal; break;
+ case Type::DoubleTyID: cout << V.DoubleVal; break;
+ default:
+ cout << "- Don't know how to print value of this type!";
+ break;
+ }
+}
+
+void Interpreter::printValue(const string &Name) {
+ Value *PickedVal = ChooseOneOption(Name, LookupMatchingNames(Name));
+ if (!PickedVal) return;
+
+ if (const Method *M = PickedVal->castMethod()) {
+ cout << M; // Print the method
+ } else { // Otherwise there should be an annotation for the slot#
+ printValue(PickedVal->getType(),
+ getOperandValue(PickedVal, ECStack[CurFrame]));
+ cout << endl;
+ }
+
+}
+
+void Interpreter::list() {
+ if (ECStack.empty())
+ cout << "Error: No program executing!\n";
+ else
+ cout << ECStack[CurFrame].CurMethod; // Just print the method out...
+}
+
+void Interpreter::printStackTrace() {
+ if (ECStack.empty()) cout << "No program executing!\n";
+
+ for (unsigned i = 0; i < ECStack.size(); ++i) {
+ cout << (((int)i == CurFrame) ? '>' : '-');
+ cout << "#" << i << ". " << ECStack[i].CurMethod->getType() << " \""
+ << ECStack[i].CurMethod->getName() << "\"(";
+ // TODO: Print Args
+ cout << ")" << endl;
+ cout << *ECStack[i].CurInst;
+ }
+}
--- /dev/null
+//===-- UserInput.cpp - Interpreter Input Loop support --------------------===//
+//
+// This file implements the interpreter Input I/O loop.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Interpreter.h"
+#include "llvm/Assembly/Writer.h"
+#include <algorithm>
+
+enum CommandID {
+ Quit, Help, // Basics
+ Print, List, StackTrace, Up, Down, // Inspection
+ Next, Step, Run, Finish, Call, // Control flow changes
+ Break, Watch, // Debugging
+ Load, Flush
+};
+
+// CommandTable - Build a lookup table for the commands available to the user...
+static struct CommandTableElement {
+ const char *Name;
+ enum CommandID CID;
+
+ inline bool operator<(const CommandTableElement &E) const {
+ return string(Name) < string(E.Name);
+ }
+ inline bool operator==(const string &S) const {
+ return string(Name) == S;
+ }
+} CommandTable[] = {
+ { "quit" , Quit }, { "q", Quit }, { "", Quit }, // Empty str = eof
+ { "help" , Help }, { "h", Help },
+
+ { "print" , Print }, { "p", Print },
+ { "list" , List },
+ { "backtrace", StackTrace }, { "bt", StackTrace }, { "where", StackTrace },
+ { "up" , Up },
+ { "down" , Down },
+
+ { "next" , Next }, { "n", Next },
+ { "step" , Step }, { "s", Step },
+ { "run" , Run },
+ { "finish" , Finish },
+ { "call" , Call },
+
+ { "break" , Break }, { "b", Break },
+ { "watch" , Watch },
+
+ { "load" , Load },
+ { "flush" , Flush },
+};
+static CommandTableElement *CommandTableEnd =
+ CommandTable+sizeof(CommandTable)/sizeof(CommandTable[0]);
+
+
+//===----------------------------------------------------------------------===//
+// handleUserInput - Enter the input loop for the interpreter. This function
+// returns when the user quits the interpreter.
+//
+void Interpreter::handleUserInput() {
+ bool UserQuit = false;
+
+ // Sort the table...
+ sort(CommandTable, CommandTableEnd);
+
+ // Print the instruction that we are stopped at...
+ printCurrentInstruction();
+
+ do {
+ string Command;
+ cout << "lli> " << flush;
+ cin >> Command;
+
+ CommandTableElement *E = find(CommandTable, CommandTableEnd, Command);
+
+ if (E == CommandTableEnd) {
+ cout << "Error: '" << Command << "' not recognized!\n";
+ continue;
+ }
+
+ switch (E->CID) {
+ case Quit: UserQuit = true; break;
+ case Print:
+ cin >> Command;
+ printValue(Command);
+ break;
+ case List: list(); break;
+ case StackTrace: printStackTrace(); break;
+ case Up:
+ if (CurFrame > 0) --CurFrame;
+ else cout << "Error: Already at root of stack!\n";
+ break;
+ case Down:
+ if ((unsigned)CurFrame < ECStack.size()-1) ++CurFrame;
+ else cout << "Error: Already at bottom of stack!\n";
+ break;
+ case Next: nextInstruction(); break;
+ case Step: stepInstruction(); break;
+ case Run: run(); break;
+ case Finish: finish(); break;
+ case Call:
+ cin >> Command;
+ callMethod(Command); // Enter the specified method
+ finish(); // Run until it's complete
+ break;
+
+ default:
+ cout << "Command '" << Command << "' unimplemented!\n";
+ break;
+ }
+
+ } while (!UserQuit);
+}
+
+
+//===----------------------------------------------------------------------===//
+// setBreakpoint - Enable a breakpoint at the specified location
+//
+void Interpreter::setBreakpoint(const string &Name) {
+ Value *PickedVal = ChooseOneOption(Name, LookupMatchingNames(Name));
+ // TODO: Set a breakpoint on PickedVal
+}
+
+//===----------------------------------------------------------------------===//
+// callMethod - Enter the specified method...
+//
+bool Interpreter::callMethod(const string &Name) {
+ vector<Value*> Options = LookupMatchingNames(Name);
+
+ for (unsigned i = 0; i < Options.size(); ++i) { // Remove nonmethod matches...
+ if (!Options[i]->isMethod()) {
+ Options.erase(Options.begin()+i);
+ --i;
+ }
+ }
+
+ Value *PickedMeth = ChooseOneOption(Name, Options);
+ if (PickedMeth == 0)
+ return true;
+
+ callMethod(PickedMeth->castMethodAsserting()); // Start executing it...
+
+ // Reset the current frame location to the top of stack
+ CurFrame = ECStack.size()-1;
+
+ return false;
+}