#ifndef INTERPRET_H #define INTERPRET_H #include #include /* Used for stacks */ #include "value.h" /* Stack values */ #include "nt.h" /* Name table */ #include "icode.h" /* Intermediate code */ #include "lextypes.h" /* Types of lexemes */ #include "lt.h" /* Label table */ #include "stfunc.h" class StackException { public: const char* reason; StackException(): reason("") {} StackException(const char* cause): reason(cause) {} const char* what() const { return reason; } }; class OutOfRangeException { public: const char* reason; OutOfRangeException(): reason("") {} OutOfRangeException(const char* cause): reason(cause) {} const char* what() const { return reason; } }; class ExecStack: public std::vector { public: void push(const Value& v) { push_back(v); } void pop() { if (empty()) throw StackException("Value stack empty"); pop_back(); } void pop(Value& v) { if (empty()) throw StackException("Value stack empty"); v = back(); pop_back(); } Value& top() { if (empty()) throw StackException("Value stack empty"); return back(); } const Value& top() const { if (empty()) throw StackException("Value stack empty"); return back(); } void print() const; // for debug }; typedef IProgram::const_iterator ICommandPtr; class AddressStack: public std::deque { public: void push(ICommandPtr a) { push_back(a); } void pop() { if (empty()) throw StackException("Address stack empty"); pop_back(); } void pop(ICommandPtr& a) { if (empty()) throw StackException("Address stack empty"); a = back(); pop_back(); } ICommandPtr& top() { if (empty()) throw StackException("Address stack empty"); return back(); } const ICommandPtr& top() const { if (empty()) throw StackException("Address stack empty"); return back(); } }; class NameTableStack: public std::deque { public: void push(const NameTable& a) { push_back(a); } NameTable& emplace() { emplace_back(); return back(); } void pop() { if (empty()) throw StackException("Name table stack empty"); pop_back(); } /*... void pop(NameTable& a) { if (empty()) throw StackException("Name table stack empty"); a = back(); pop_back(); } ...*/ NameTable& top() { if (empty()) throw StackException("Stack empty"); return back(); } const NameTable& top() const { if (empty()) throw StackException("Stack empty"); return back(); } void print() const; // for debugging }; class ICodeInterpretator { public: ExecStack stack; AddressStack addressStack; NameTableStack nameTableStack; //... const ICommand* currentCommand; const IProgram* program; IProgram::const_iterator currentCommand; public: ICodeInterpretator(): program(0), currentCommand() {} void initialize(const IProgram* icode); void execute(int& lastLineNumber); // line number used // in case of exception void executeCommand(); void printStackTop() const; bool defineFunctionAddress( const Value& f, IProgram::const_iterator& functionAddress ) const; // Values & name tables Value& getValue(const string& name); Value& getNonlocalValue(const string& name); Value& readValue(Value& v); // Read l-value or normal value Value& readNonlocalValue(Value& v); void scan(Value& v); // Set either local or global variable void setValue(const string& name, Value& v); // Set local variable void setLocalValue(const string& name, Value& v); void setValue(const Value& lvalue, Value& v); void setLocalValue(const Value& lvalue, Value& v); void setLocalReference(const Value& lvalue, Value& v); // Write either v or standard function to lvalue void assignValue(Value& lvalue, Value& v); // Fing a name either in local table or in enclosing tables NameDef* findName(const string& name) const; // Fing a nonlocal name in enclosing tables NameDef* findNonlocalName(const string& name) const; // Add a name to the local table NameDef* addName(const string& name); }; #endif