211 lines
5.4 KiB
C
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;
|
|
}
|