CPW Part 13: Code Generation for Expressions

Cleanup: Renaming printSymtab

The naming printSymtab is inconsistent. Rename the function printSymTab().

Extending the Code Generation Interface

In the interface for code generation we should offer an unary minus instruction. We can provide this as a two address instruction where both operands are registers. With the instruction the first register gets inverted and the result stored in the second registers.

In the header file we define a new enum constant GEN_UNARYMINUS_R that belongs to a new group of two address instructions. We also declare a function genOp2r() for this type of instructions:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
#ifndef ABC_GEN_H
#define ABC_GEN_H

// ...

// supported instruction
enum GenOp
{
    GEN_OP2R_BEGIN,
    GEN_UNARYMINUS_R,             // new: for unary minus instruction
    GEN_OP2R_END,

    GEN_OP3R_BEGIN = GEN_OP2R_END,
    GEN_ADD_R = GEN_OP3R_BEGIN,   // addition
    GEN_SUB_R,                    // subtraction
    GEN_IMUL_R,                   // multiplication
    GEN_DIV_R,                    // division
    GEN_MOD_R,                    // modulo
    GEN_OP3R_END,

    GEN_OP3I_BEGIN = GEN_OP3R_END,
    GEN_ADD_I = GEN_OP3I_BEGIN,
    GEN_SUB_I,
    GEN_IMUL_I,
    GEN_DIV_I,
    GEN_MOD_I,
    GEN_OP3I_END,
};

// new: 2 address instructions
void genOp2r(enum GenOp op, GenReg reg0, GenReg reg1);

// ...

#endif // ABC_GEN_H

The implementation of genOp2r() uses the zero register to support the unary minus operation. For example genOp2r(GEN_UNARYMINUS_R, 8, 9) generates

1
    subq    %8, %0, %9

The implementation of loadExpr() of course should use genOp2r() where appropriate.

Extending the Expression Interface

The interface should provide a method for loading the address of an l-value expression into a register:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
#ifndef ABC_EXPR_H
#define ABC_EXPR_H

// ...

// methods
// ...
void loadExprAddr(const struct Expr *expr, GenReg dest); // l-value required
// ...

#endif // ABC_EXPR_H

The implementation can simply trigger an assertion failure if the expression is not an l-value. Such a semantic check can be done beforehand by the parser where an error message with line and column information can be generated.