{ CHAPTER 11 Code Generator Overview The code generator transforms the set of code-generation interface calls made during program analyis into a code-byte stream for direct execution on the P-machine. This transformation is achieved by simulating all operations defined at interface level on a compile-time evaluation stack, and delaying actual code genera- tion until the context of an expression or reference is fully known. Such a 'delayed' code-generation strategy is both useful for a wide variety of target machine architectures, and necessary for the implementation of the more complex runtime checks. The P-machine itself is described separately within its own free- standing definition, but aspects relevant to the code generation process are included in Chapter 2 as a set of constant definitions describing machine parameters (prefixed MC), and the P-machine instruction set. Overall, the code generator can be summarised as follows. Chapter 12 defines the representations of all data types, and pro- vides a high-level interface to the generator procedures for type-specific intialisation, finalisation, and value inspection. Chapter 13 contains procedures for storage management and runtime address assignment, and provides high-level support for block ini- tialisation and finalisation. Chapter 14 provides utilities for the evaluation of target machine object values corresponding to literal constants, and for the lim- ited manipulation of these values that the analyser requires. In addition, certain useful global object values are initialised here. Chapter 15 contains the low-level facilities necessary to format and generate the CodeFile containing the executable object pro- gram. Chapters 16 and 17 implement the compile-time stack model of the target machine and simulate all refererence and binary operations defined in the code-generation interface. Throughout the simula- tion, a tree representation of each exprsssion is built, in which the internal nodes define operations, and the left and right sub- trees define the operands. Each leaf node is either a reference to a stored operand, or a self-defining constant operand contain- ing an embedded object value. Component references and expressions are stored on the compile- time stack until the context of code-generation is identified as: (a) a Boolean expression evaluation; (b) the start or end of a case-statement, for-statement, or with-statement; (c) a procedure or function call; (d) an assignment statement. For example, within the context of the assignment statement v := a+b+c ; the compile-time evaluation stack contains: .---------. TOS-1 !_________!-------------. | | v .-----. | v | !_____! .---------. TOS !_________!----------------------. | | | v .-----. | + | !_____! | | v .-------------------. | | | | v v .-----. .-----. | + | | c | !_____! !_____! | | v .-----------------. | | | | v v .-----. .-----. | a | | b | !_____! !_____! Chapter 18 contains the procedures for generating equivalent P- code instruction sequences from the reference and expression trees built on the evaluation stack. Thus, expression evaluation code is generated by simple traversal of the expression tree in which the left and right subtrees are evaluated as operands, followed by the appropriate P-machine operation P-code. Reference evaluation is equivalent to traversal of a degenerate tree and results in the generation of appropriate store-access code. Chapter 18 also con- tains low-level support for all P-code emission, and for the gen- eration and fix-up of jump instructions. Chapters 19 to 23 provide for code-generation of higher-level con- structs such as assignment statements, with-statements, standard procedures, case-statements, for-statements, and procedure/function calls. Chapter 24 provides support for program parameter passing. Chapters 25 and 26 respectively provide for low-level support for undefined variable detection, and the generation of internal type-specific procedures for generalised variable initialisation and value inspection. Chapter 27 contains procedures necessary to generate the code and data maps that constitute the compiler's interface to the Postmor- tem Generator. Chapter 28 controls the phased initialisation of all data- structures and global variables used by the generator. The following procedures are utilities used throughout the code generator. PredictedError is used to report runtime errors predicted at compile-time; MCSetBit, MCGetBit, and MCSetByte pro- vide bit and byte access on the host compiling machine. } procedure MCSetBit ( var Word : MCWordForm ; BitIndex : MCBitIndex ) ; begin { recast(word,asbits) } { if IndexedFromLeft} { then} Word.WBits[MCMaxBitNum-BitIndex] := 1 { else} { Word.WBits[BitIndex] := 1} end { mcsetbit } ; procedure MCGetBit ( Word : MCWordForm ; BitIndex : MCBitIndex ; var ResultBit : MCBit ) ; begin { recast(word,asbits) } { if IndexedFromLeft} { then} ResultBit := Word.WBits[MCMaxBitNum-BitIndex] { else} { ResultBit := Word.WBits[BitIndex]} end { mcgetbit } ; procedure MCSetByte ( var Word : MCWordForm ; ByteIndex : MCByteIndex ; DataByte : MCByte ) ; begin { recast(word,asbytes) } if IndexedFromLeft then Word.WBytes[MCMaxByteNum-ByteIndex] := DataByte else Word.WBytes[ByteIndex] := DataByte end { mcsetbyte } ; procedure PredictedError(Code: Scalar); begin Error(Code + PredictedBase, StartOfSymbol) end; {