From d22ba5b4f2758e5700d7cc32e3d20a75f1f3c9df Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Thu, 23 Dec 2021 13:18:46 +0100 Subject: Add compilation of numerical comparison ops for ir --- src/ir.h | 69 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/src/ir.h b/src/ir.h index c1cdae4..514a3ac 100644 --- a/src/ir.h +++ b/src/ir.h @@ -22,6 +22,13 @@ typedef enum Op { OP_PUSH, // - Discards the last value in the stack. OP_DROP, + // - Duplicates the last value in the stack. + OP_DUP, + // - Rotates the last three elements in the stack. + // - Right: [ a b c -> c a b ] + // - Left: [ a b c -> b c a] + OP_ROT_RIGHT, + OP_ROT_LEFT, // A label for memory access. // - The argument should be a unique value. OP_LABEL, @@ -31,6 +38,15 @@ typedef enum Op { OP_JUMP, OP_JUMP_IF_TRUE, OP_JUMP_IF_FALSE, + // - These require numerical objects on the stack. + // - Consume two items in the stack. + // - Jumps to the given label as argument when appropriate. + OP_JUMP_IF_EQ, + OP_JUMP_IF_NEQ, + OP_JUMP_IF_GT, + OP_JUMP_IF_LT, + OP_JUMP_IF_GE, + OP_JUMP_IF_LE, // Primitive complex commands. // - Prints the last object in the stack. OP_PRINT, @@ -52,10 +68,19 @@ static const char* ops_str[] = { [OP_NOT] = "OP_NOT", [OP_PUSH] = "OP_PUSH", [OP_DROP] = "OP_DROP", + [OP_DUP] = "OP_DUP", + [OP_ROT_RIGHT] = "OP_ROT_RIGHT", + [OP_ROT_LEFT] = "OP_ROT_LEFT", [OP_LABEL] = "OP_LABEL", [OP_JUMP] = "OP_JUMP", [OP_JUMP_IF_TRUE] = "OP_JUMP_IF_TRUE", [OP_JUMP_IF_FALSE] = "OP_JUMP_IF_FALSE", + [OP_JUMP_IF_EQ] = "OP_JUMP_IF_EQ", + [OP_JUMP_IF_NEQ] = "OP_JUMP_IF_NEQ", + [OP_JUMP_IF_GT] = "OP_JUMP_IF_GT", + [OP_JUMP_IF_LT] = "OP_JUMP_IF_LT", + [OP_JUMP_IF_GE] = "OP_JUMP_IF_GE", + [OP_JUMP_IF_LE] = "OP_JUMP_IF_LE", [OP_PRINT] = "OP_PRINT", [OP_CALL] = "OP_CALL", [OP_RETURN] = "OP_RETURN", @@ -121,6 +146,12 @@ print_instruction(Instruction *instruction) { case OP_JUMP: case OP_JUMP_IF_TRUE: case OP_JUMP_IF_FALSE: + case OP_JUMP_IF_EQ: + case OP_JUMP_IF_NEQ: + case OP_JUMP_IF_GT: + case OP_JUMP_IF_LT: + case OP_JUMP_IF_GE: + case OP_JUMP_IF_LE: case OP_LABEL: { printf("%-16s -> %zu\n", ops_str[op], instruction->label_id); } break; @@ -163,6 +194,29 @@ compile_arithmetic(ProgramIr *program, Procedure *proc, Op op, } } +void +compile_numeric_cmp(ProgramIr *program, Procedure *proc, Op op, + size_t line, size_t col, Object *args) { + size_t label_false = program->labels++; + size_t label_exit = program->labels++; + compile_object(program, proc, args->head); + args = args->tail; + while (args != NULL) { + compile_object(program, proc, args->head); + args = args->tail; + INST_SIMPLE(proc, OP_DUP, line, col); + INST_SIMPLE(proc, OP_ROT_RIGHT, line, col); + INST_ARG(proc, op, label_false, line, col); + } + INST_SIMPLE(proc, OP_DROP, line, col); + INST_ARG(proc, OP_PUSH, &obj_true, line, col); + INST_ARG(proc, OP_JUMP, label_exit, line, col); + INST_ARG(proc, OP_LABEL, label_false, line, col); + INST_SIMPLE(proc, OP_DROP, line, col); + INST_ARG(proc, OP_PUSH, &obj_false, line, col); + INST_ARG(proc, OP_LABEL, label_exit, line, col); +} + void compile_print(ProgramIr *program, Procedure *proc, size_t line, size_t col, Object *args) { @@ -247,6 +301,21 @@ compile_proc_call(ProgramIr *program, Procedure *proc, Object *obj) { case BUILTIN_OR: { compile_or(program, proc, line, col, obj->tail); } break; + case BUILTIN_EQ: { + compile_numeric_cmp(program, proc, OP_JUMP_IF_NEQ, line, col, obj->tail); + } break; + case BUILTIN_GT: { + compile_numeric_cmp(program, proc, OP_JUMP_IF_LE, line, col, obj->tail); + } break; + case BUILTIN_LT: { + compile_numeric_cmp(program, proc, OP_JUMP_IF_GE, line, col, obj->tail); + } break; + case BUILTIN_GE: { + compile_numeric_cmp(program, proc, OP_JUMP_IF_LT, line, col, obj->tail); + } break; + case BUILTIN_LE: { + compile_numeric_cmp(program, proc, OP_JUMP_IF_GT, line, col, obj->tail); + } break; default: { assert(false && "builtin not implemented"); } break; -- cgit v1.2.1