#ifndef BCIDEFS_H #define BCIDEFS_H /* bcidefs.h XIDEK: Extensible Script Language Development Kit Bytecode Interpreter Definitions Copyright (c) 1996-2002 Parsifal Software. All Rights Reserved. This file implements . a simple bytecode interpreter which uses an arithmetic stack for intermediate results. . A CodeFragment class which assists in creating bytecode For further information about this program or the AnaGram parser generator, please contact: Parsifal Software http://www.parsifalsoft.com info@parsifalsoft.com +1-800-879-2577, Voice/Fax +1-508-358-2564 P.O. Box 219 Wayland, MA 01778 USA */ #include "opcodes.h" #include "agarray.h" #ifdef USE_STD #include #include using namespace std; #else #include #include #endif class Constant : public Value { public: Constant() : Value() {} Constant(int x) : Value(x) {} Constant(long x) : Value(x) {} Constant(double x) : Value(x) {} Constant(const AgString &s) : Value(s) {} Constant(const Value &v) : Value(v) {} Constant(const Constant &c) : Value(c) {} int operator == (const Constant &c) const { return type == c.type && Value::operator == (c); } int hash(int startValue) const { return Value::hash(startValue*3 + type);} }; inline int agABTHash(const Constant &v, int startValue = 0) {return v.hash(startValue);} /* Type for a single virtual machine instruction. This limits the script to handling 128 variable names, 128 constants and limits the length of loops and other constructs that require branch instructions. For larger scripts, change this to typedef signed short Bytecode; */ typedef signed char Bytecode; // The ScriptMethod class encapsulates the bytecode interpreter class ScriptMethod { public: AgDictionary &dictionary; // contains variable names AgArray bytecode; // contains code AgArray constantList; // contains constants ScriptMethod(const char *text, AgDictionary &d); // Copy Constructor ScriptMethod(const ScriptMethod &m); // Destructor ~ScriptMethod() {} // Executes script on specified data set Value apply(Dataset &) const; // write bytecode listing to file const ScriptMethod &list(ostream &f) const; }; /* A CodeFragment object contains a sequence of bytecodes. The idea is that CodeFragments can be stuck together to produce longer CodeFragments. This makes it possible to build up complex constructs from simpler sequences. The append function allows a single opcode, with or without an operand, to be appended to a CodeFragment. The concat function (from CONCATenate) allows another CodeFragment to be appended. The branchList lists locations in the code fragment which contain displacements for branch instructions that implement break or continue. The offset is 0 for continue, 1 for break. The patchBranches() function is called to set the continue address to the top of a code fragment, the break address to the location following the code fragment. */ class CodeFragment { AgStack bytecode; AgStack branchList; public: // Constructor CodeFragment() {} CodeFragment(const CodeFragment &f); // Destructor ~CodeFragment() {} // Return the size of the fragment int size() const {return bytecode.size();} // Extract the bytecode for use in an interpreter AgArray getBytecode(); // Append a simple instruction CodeFragment &append(Opcode op) { bytecode.push((Bytecode) op); return *this; } // Append an instruction with operand CodeFragment &append(Opcode op, int offset); // Append a continue branch CodeFragment &appendContinue(Opcode op); // Append a break branch CodeFragment &appendBreak(Opcode op); // Concatenate a fragment CodeFragment &concat(const CodeFragment &f); // Patch the break and continue statements CodeFragment &patchBranches(); // Check to see whether the CodeFragment contains a break int containsBreak(); // Generate code for an if statement static CodeFragment ifStatement ( CodeFragment &condition, CodeFragment &statement); // Generate code for an if-else statement static CodeFragment ifElse ( CodeFragment &condition, CodeFragment &onTrue, CodeFragment &onFalse); // Generate code for a while loop static CodeFragment whileLoop( CodeFragment &condition, CodeFragment &statement); // Generate code for a do-while loop static CodeFragment doLoop ( CodeFragment &statement, CodeFragment &condition); // Generate code for a repeat loop static CodeFragment repeatLoop ( CodeFragment &statementList, CodeFragment &condition); // Generate code for a for loop static CodeFragment forLoop ( CodeFragment &initializer, CodeFragment &condition, CodeFragment &increment, CodeFragment &statement); // Generate code for a simple for loop static CodeFragment simpleForLoop ( const CodeFragment &lValue, const CodeFragment &begin, const CodeFragment &increment, const CodeFragment &end, const CodeFragment &statement); }; //Global definition extern const char *opcodeText[]; #endif