Files
glisp/src/byterun/assemble.c
2026-01-22 21:08:02 -08:00

211 lines
5.4 KiB
C

#include "assemble.h"
#include "base.h"
#include "memory.h"
#include <assert.h>
#include <ctype.h>
#include <stdbool.h>
#include <strings.h>
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;
}