Some work
This commit is contained in:
210
src/byterun/assemble.c
Normal file
210
src/byterun/assemble.c
Normal file
@ -0,0 +1,210 @@
|
||||
#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;
|
||||
}
|
||||
Reference in New Issue
Block a user