XIDEK
|
dci: Direct Compilation Interpreters
IntroductionThe baseline "Direct Compilation" interpreters, found in cll\base\dci.syn and pll\base\dci.syn compile the statements in a script into bytecode as they parse the script, without creating an intermediate representation of the script. This approach is facilitated by the CodeFragment class which provides methods for creating small fragments of code and then combining them into larger fragments, and finally into one fragment which corresponds to the entire script.The interpreter interface function, interpret() is implemented by creating an instance of the ScriptMethod class. The class constructor invokes the parser to compile the script into bytecode. The apply() function of ScriptMethod is then used to execute the bytecode. ScriptMethod also has a list() function to create a listing of the bytecode. A call to the list() function has been provided in the interpret function, but has been commented out for testing purposes. In what follows, we describe first the features of the CLL version of the dxi.syn syntax file and how it differs from the cll.syn file. Then we describe the differences required for the PLL version.
C PrologueIntroductionThe C Prologue is the initial piece of embedded C/C++ code in a syntax file. AnaGram copies it to the parser file before writing any generated code, so it is the appropriate place to include definitions and declarations needed by the parser. In particular, any data type that is used as a token type must be defined in the C prologue, either explicitly or by means of an include file.
Include FileThe bcidefs.h header file contains definitions of the ScriptMethod and CodeFragment classes.
Configuration SectionConfiguration parameters that are common to all of the parsers in the kit are discussed in the descriptions of the CLL and PLL syntaxes. The following additional configuration parameters are set in the CLL version of dci.syn:
Parser Control Block ExtensionsIn order to support reentrancy, it is convenient to declare local data used by the parser in the parser control block. It is also convenient to declare functions used by the parser as members of the parser control block, though this is not, strictly speaking, necessary.
Added Fields
Local FunctionsThe following functions are declared to be member functions of the parser control block. The actual implementations of these functions are found in the embedded C portion of the syntax file.
Reduction ProceduresThe useful work of any parser is carried out by the reduction procedures which indicate what is to be done when a grammar rule is matched. In the case of dci(), there are two types of reduction procedures: The first type creates a fragment of code, encapsulated in a CodeFragment object, from scratch. These procedures invoke one of the three code() functions to create a single bytecode instruction, consisting of an opcode and possibly an operand. The second type of reduction procedure, presented with one or more CodeFragment objects and a desired operation, stitches them together by inserting or appending the appropriate instructions. In all these cases, the reduction procedure should be reasonably self-explanatory.
Embedded CMacro Definitions
Parser Control Block Member FunctionsThe following member functions of the parser control block, dci_pcb_struct, are declared in the extensions to the parser control block.
ScriptMethod::ScriptMethod(const char *text, AgDictionary<AgString> &d);The constructor for the ScriptMethod is implemented in two stages. In the first stage, a parser control block is created, and the dci parser is invoked to compile bytecode. A try-catch block is used to handle errors that occur during compilation. Then the return value of the parse, a CodeFragment object, is retrieved and the bytecode extracted and stored in the ScriptMethod object. Finally, the constants are extracted from the parser control block and stored in the constantList array.
The External Interface: interpret()The external interface for the interpreter begins by constructing a ScriptMethod object. The constructor actually parses the script and compiles the byte code. interpret() then invokes the ScriptMethod::apply() function to execute the bytecode. A call to the ScriptMethod::list() function, commented out for regression testing, may be used to create a listing of the generated bytecode.
PLL DifferencesThe differences between the PLL syntax and the PLL version of the dci syntax are essentially identical to those described above for CLL. Because the PLL language does not implement break and continue statements, the loopDepth counter and the checkLoop() function are not needed. |
Table of Contents | | | Parsifal Software Home Page |
---|
Interpreter Development Kit
Copyright © 1997-2002, Parsifal Software.
All Rights Reserved.