#include "assemble.h" #include "base.h" #include "memory.h" #include #include #include #include BytecodeOpcode bytecode_opcode_by_name(const char *name, size_t length) { struct Bucket { size_t name_len; const char *name; BytecodeOpcode opcode; struct Bucket *next; }; static struct Bucket *TABLE[26] = {NULL}; static bool did_init = false; if (!did_init) { #define PUT(mname) \ { \ struct Bucket *n = lisp_malloc(sizeof(struct Bucket)); \ n->name_len = sizeof(#mname) - 1; \ n->name = #mname; \ n->opcode = BO_##mname; \ size_t hash = tolower(#mname[0]) - 'a'; \ n->next = TABLE[hash]; \ TABLE[hash] = n; \ } PUT(NIL); PUT(CONS); PUT(CAR); PUT(CDR); PUT(NULL); PUT(POP); PUT(COPY); PUT(LOAD); PUT(EQ); PUT(FUNCALL); PUT(PRINT); #undef PUT did_init = true; } if (!length) { return BO_INVALID; } size_t hash = tolower(name[0]) - 'a'; assert(0 <= hash && hash <= 25); for (struct Bucket *cur = TABLE[hash]; cur; cur = cur->next) { if (cur->name_len == length && strcasecmp(cur->name, name) == 0) { return cur->opcode; } } return BO_INVALID; } const char *bytecode_opcode_name(BytecodeOpcode opcode, size_t *length) { #define DEF(name) \ case BO_##name: \ if (length) { \ *length = sizeof(#name) - 1; \ } \ return #name switch (opcode) { DEF(NIL); DEF(CONS); DEF(CAR); DEF(CDR); DEF(NULL); DEF(POP); DEF(COPY); DEF(LOAD); DEF(EQ); DEF(FUNCALL); DEF(PRINT); case BO_INVALID: return NULL; default: abort(); } #undef DEF } BytecodeConstType bytecode_const_type_by_name(const char *name, size_t length) { #define CHECK(type) \ if (strcasecmp(name, #type)) { \ return BYTECODE_CONST_##type; \ } CHECK(FIXNUM); CHECK(FLOAT); CHECK(CONS); CHECK(STRING); CHECK(SYMBOL); CHECK(VECTOR); CHECK(FUNCTION); CHECK(LIST); return BYTECODE_CONST_INVALID; #undef CHECK } const char *bytecode_const_name(BytecodeConstType type, size_t *length) { #define DEF(name) \ case BYTECODE_CONST_##name: \ if (length) { \ *length = sizeof(#name) - 1; \ } \ return #name; switch (type) { DEF(FIXNUM); DEF(FLOAT); DEF(CONS); DEF(STRING); DEF(SYMBOL); DEF(VECTOR); DEF(FUNCTION); DEF(LIST); case BO_INVALID: return NULL; default: abort(); } } enum AssembleMode { MODE_NONE, MODE_CONSTANTS, MODE_TEXT }; typedef struct { BytecodeConstType type; union { fixnum_t fixnum; lisp_float_t lisp_float; struct { intptr_t car; intptr_t cdr; } cons; struct { size_t length; const char *bytes; } string; struct { size_t length; const char *bytes; } symbol; struct { size_t length; intptr_t elements; } vector; struct { // TODO implement int dummy; } function; struct { size_t length; intptr_t elements; } list; }; } AssembleConstant; struct AssembleState { enum AssembleMode mode; size_t line_no; size_t num_constants; AssembleConstant *constants; size_t num_instructions; }; static bool is_blank_string(const char *data, size_t len) { for (size_t i = 0; i < len; ++i) { if (data[i] != ' ' && data[i] != '\t') { return false; } } return true; } static BytecodeAssembleStatus process_line_none_mode(struct AssembleState *restrict state, const size_t line_len, const char line[line_len], BytecodeAssembleError *restrict error) {} BytecodeAssembleStatus bytecode_assemble(const size_t src_length, const char src[src_length], size_t *restrict out_length, char **restrict out, BytecodeAssembleError *restrict error) { StringStream stream; string_stream_init(&stream); struct AssembleState state = { .mode = MODE_NONE, .line_no = 1, .num_constants = 0, .constants = NULL, .num_instructions = 0, }; const char *line = NULL; size_t line_len; while (strgetline(src, src_length, &line, &line_len)) { switch (state.mode) { case MODE_NONE: process_line_none_mode(&state, line_len, line, error); break; case MODE_CONSTANTS: case MODE_TEXT: break; } ++state.line_no; } string_stream_steal(&stream, out, out_length); return BYTECODE_ASSEMBLE_OK; }