=================================================================== CPW Part 16 (B): Equality and Relational Expressions in the Grammar [TOC] =================================================================== For adapting the implementation of ``loadExpr()`` it might be convenient to have two internal functions: - Function ``makeCondJmp()`` to translate values of type _enum ExprKind_ to values of type _enum GenOp_. - For equality or relational expression nodes function ``condJmpExpr()`` can be used to first generate assembly code that compares the values of the nodes and after that a conditional jump instruction. Like in ``genCondJmp()`` it should be possible to generate a conditional jumps that takes place if the condition is either true or false. This leads to the following structure: ---- CODE (type=c) ------------------------------------------------------------- static enum GenOp makeCondJmp(enum ExprKind kind) { /* ... */ } static void condJmpExpr(const struct Expr *expr, GenReg dest, const char *trueLabel, const char *falseLabel) { /* ... */ } void loadExpr(const struct Expr *expr, GenReg dest) { /* ... */ } -------------------------------------------------------------------------------- If you want the challenge then stop reading here ;-) More About: ``loadExpr()`` ========================== The switch statement now also has to handle the new expression kinds (``EK_EQUAL``, ``EK_NOT_EQUAL``, etc.). For all the same code can be used. We need two labels. For example, one to mark the instruction for loading 1 into the destination register, and another for marking the end of the generated assembly block. With ``condJmpExpr()`` code for comparing the values of the child nodes can be generated and also the proper conditional jump instruction. So we basically the new cases in the switch simply can use this code block: ---- CODE (type=c, fold) ------------------------------------------------------- { const char *loadOne = genGetLabel(); const char *done = genGetLabel(); condJmpExpr(expr, dest, loadOne, 0); genLoadUInt(0, dest); genJmp(done); genLabelDef(loadOne); genLoadUInt(1, dest); genLabelDef(done); } -------------------------------------------------------------------------------- More About: ``condJmpExpr()`` ============================= For now this function will only deal with nodes where the expression kind is ``EK_EQUAL``, ``EK_NOT_EQUAL``, ..., ``EK_LESS_EQUAL``. The left child gets loaded into the destination register. If the right child is constant code for the comparison can be generated by ``genOp2i`` with ``GEN_CMP_I``. Otherwise code needs to be generated to load the value into a temporary register. Then ``genOp2r`` with ``GEN_CMP_R`` can be used to generate code for the comparison. After comparing the values code for the conditional jump can be generated: ---- CODE (type=c, fold) ------------------------------------------------------- { const struct Expr *left = expr->binary.left; const struct Expr *right = expr->binary.right; loadExpr(left, dest); if (isConstExpr(right)) { uint64_t rVal = right->primary.literal.uint; genOp2i(GEN_CMP_I, rVal, dest); } else { GenReg tmp = genGetReg(); loadExpr(right, tmp); genOp2r(GEN_CMP_R, tmp, dest); genUngetReg(tmp); } genCondJmp(makeCondJmp(expr->kind), trueLabel, falseLabel); } -------------------------------------------------------------------------------- Printing Expression Trees ========================= Of course ``printExprNode()`` has to handle all new expression kinds.