From 64d282b77633338ac3ff9fe924fe86bfab1012e6 Mon Sep 17 00:00:00 2001 From: Bad Diode Date: Thu, 23 Dec 2021 12:07:42 +0100 Subject: Add `not` and `and` builtins for ir compilation --- src/ir.h | 87 +++++++++++++++++++++++++++++++++++++++++++++++++++++------- src/parser.c | 15 ++++++++--- 2 files changed, 89 insertions(+), 13 deletions(-) diff --git a/src/ir.h b/src/ir.h index 845bf63..bb15596 100644 --- a/src/ir.h +++ b/src/ir.h @@ -15,11 +15,16 @@ typedef enum Op { OP_MUL, OP_DIV, OP_MOD, + // Logic ops. + OP_NOT, // Stack ops. // - Requires an Object to push into the stack. OP_PUSH, // - Discards the last value in the stack. OP_DROP, + // A label for memory access. + // - The argument should be a unique value. + OP_LABEL, // Jump/conditional ops. // - Take a label as argument. // - For conditional jumps, the last value in the stack is used. @@ -43,8 +48,10 @@ static const char* ops_str[] = { [OP_MUL] = "OP_MUL", [OP_DIV] = "OP_DIV", [OP_MOD] = "OP_MOD", + [OP_NOT] = "OP_NOT", [OP_PUSH] = "OP_PUSH", [OP_DROP] = "OP_DROP", + [OP_LABEL] = "OP_LABEL", [OP_JUMP] = "OP_JUMP", [OP_JUMP_IF_FALSE] = "OP_JUMP_IF_FALSE", [OP_PRINT] = "OP_PRINT", @@ -54,7 +61,17 @@ static const char* ops_str[] = { typedef struct Instruction { Op op; - Object *argument; + + // Op arguments. + union { + // OP_PUSH + Object *argument; + + // OP_LABEL + // OP_JUMP + // OP_JUMP_IF_FALSE + size_t label_id; + }; // Original line/column for debugging purposes. size_t line; @@ -75,9 +92,21 @@ typedef struct Procedure { typedef struct ProgramIr { Procedure **procedures; - Object **constants; + size_t labels; } ProgramIr; +#define INST_SIMPLE(PROC, OP, LINE, COL) \ + do { \ + Instruction inst = (Instruction){(OP), NULL, (LINE), (COL)}; \ + array_push((PROC)->instructions, inst); \ + } while(false); + +#define INST_ARG(PROC, OP, ARG, LINE, COL) \ + do { \ + Instruction inst = (Instruction){(OP), (ARG), (LINE), (COL)}; \ + array_push((PROC)->instructions, inst); \ + } while(false); + void print_instruction(Instruction *instruction) { printf("%4ld:%-4ld ", instruction->line, instruction->col); @@ -87,6 +116,11 @@ print_instruction(Instruction *instruction) { printf("%-16s -> ", ops_str[op]); OBJ_PRINT(instruction->argument); } break; + case OP_JUMP: + case OP_JUMP_IF_FALSE: + case OP_LABEL: { + printf("%-16s -> %zu\n", ops_str[op], instruction->label_id); + } break; default: { printf("%s\n", ops_str[op]); } break; @@ -122,22 +156,50 @@ compile_arithmetic(ProgramIr *program, Procedure *proc, Op op, while (args != NULL) { compile_object(program, proc, args->head); args = args->tail; - Instruction inst = (Instruction){op, NULL, line, col}; - array_push(proc->instructions, inst); + INST_SIMPLE(proc, op, line, col); } } void compile_print(ProgramIr *program, Procedure *proc, size_t line, size_t col, Object *args) { - Instruction inst = (Instruction){OP_PRINT, NULL, line, col}; while (args != NULL) { compile_object(program, proc, args->head); args = args->tail; - array_push(proc->instructions, inst); + INST_SIMPLE(proc, OP_PRINT, line, col); } } +void +compile_not(ProgramIr *program, Procedure *proc, + size_t line, size_t col, Object *args) { + compile_object(program, proc, args->head); + INST_SIMPLE(proc, OP_NOT, line, col); +} + +void +compile_and(ProgramIr *program, Procedure *proc, + size_t line, size_t col, Object *args) { + // Generate labels. + size_t label_false = program->labels++; + size_t label_exit = program->labels++; + while (args != NULL) { + compile_object(program, proc, args->head); + args = args->tail; + INST_ARG(proc, OP_JUMP_IF_FALSE, label_false, 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_ARG(proc, OP_PUSH, &obj_false, line, col); + INST_ARG(proc, OP_LABEL, label_exit, line, col); +} + +void +compile_or(ProgramIr *program, Procedure *proc, + size_t line, size_t col, Object *args) { +} + void compile_proc_call(ProgramIr *program, Procedure *proc, Object *obj) { size_t line = obj->line; @@ -162,6 +224,15 @@ compile_proc_call(ProgramIr *program, Procedure *proc, Object *obj) { case BUILTIN_PRINT: { compile_print(program, proc, line, col, obj->tail); } break; + case BUILTIN_NOT: { + compile_not(program, proc, line, col, obj->tail); + } break; + case BUILTIN_AND: { + compile_and(program, proc, line, col, obj->tail); + } break; + case BUILTIN_OR: { + compile_or(program, proc, line, col, obj->tail); + } break; default: { assert(false && "builtin not implemented"); } break; @@ -179,8 +250,7 @@ compile_object(ProgramIr *program, Procedure *proc, Object *obj) { case OBJ_TYPE_FALSE: case OBJ_TYPE_STRING: case OBJ_TYPE_FIXNUM: { - Instruction inst = (Instruction){OP_PUSH, obj, obj->line, obj->col}; - array_push(proc->instructions, inst); + INST_ARG(proc, OP_PUSH, obj, obj->line, obj->col); } break; case OBJ_TYPE_PAIR: { compile_proc_call(program, proc, obj); } break; // case OBJ_TYPE_IF: { compile_if(obj); } break; @@ -200,7 +270,6 @@ ProgramIr compile(Program program) { ProgramIr program_ir = {0}; array_init(program_ir.procedures, 0); - array_init(program_ir.constants, 0); Procedure *main = proc_alloc(&program_ir, STRING("main")); for (size_t i = 0; i < array_size(program.roots); i++) { diff --git a/src/parser.c b/src/parser.c index ce0c395..29a0444 100644 --- a/src/parser.c +++ b/src/parser.c @@ -5,6 +5,7 @@ static Object **objects = NULL; static Root *roots = NULL; static Environment **environments = NULL; +// Builtin procedures. static Object builtins[] = { { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_ADD, .builtin_text = STRING("+") }, { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_SUB, .builtin_text = STRING("-") }, @@ -29,6 +30,11 @@ static Object builtins[] = { { .type = OBJ_TYPE_BUILTIN, .builtin = BUILTIN_CDR, .builtin_text = STRING("cdr") }, }; +// Static singleton objects. +static Object obj_nil = { .type = OBJ_TYPE_NIL }; +static Object obj_true = { .type = OBJ_TYPE_TRUE }; +static Object obj_false = { .type = OBJ_TYPE_FALSE }; + Token peek_token(const Parser *parser) { if (parser->current >= array_size(parser->tokens)) { @@ -80,9 +86,10 @@ parse_fixnum(Token tok) { Object * parse_bool(Token tok) { - ObjectType type = tok.type == TOKEN_TRUE ? OBJ_TYPE_TRUE : OBJ_TYPE_FALSE; - Object *ret = object_alloc(tok, type); - return ret; + if (tok.type == TOKEN_TRUE) { + return &obj_true; + } + return &obj_false; } Object * @@ -444,7 +451,7 @@ parse_tree(Parser *parser, Errors *errors) { return parse_symbol(tok); } break; case TOKEN_NIL: { - return object_alloc(tok, OBJ_TYPE_NIL); + return &obj_nil; } break; default: { break; -- cgit v1.2.1