============================================ CPW Part 13: Code Generation for Expressions [TOC] ============================================ ---- VIDEO ------------------------------ https://www.youtube.com/embed/SccGj53Y0T8 ----------------------------------------- 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: ---- CODE (type=c) ------------------------------------------------------------- #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 ---- CODE (type=s) ------------------------------------------------------------- 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: ---- CODE (type=c) ------------------------------------------------------------- #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.