diff options
| author | 2023-02-18 05:55:04 +0000 | |
|---|---|---|
| committer | 2023-02-18 05:55:04 +0000 | |
| commit | 83c568c8dd060a8fb324aee33cdb030809dedbf3 (patch) | |
| tree | 3a0331b5352041d57eda345581754d448e9585e7 /creole.c | |
| parent | add version defines (diff) | |
add data, remove labels and make jumps absolute
Diffstat (limited to 'creole.c')
| -rw-r--r-- | creole.c | 298 |
1 files changed, 132 insertions, 166 deletions
@@ -30,7 +30,6 @@ enum creole_arg_type { TYPE_IMM, TYPE_REG, TYPE_VAL, - TYPE_LAB, CREOLE_ARG_TYPE_LEN }; @@ -40,7 +39,7 @@ enum creole_arg_type { */ #define defop(s, n, a1, a2, a3) {n, {a1, a2, a3}} static const struct { - unsigned arglen; + int arglen; enum creole_arg_type argtype[CREOLE_MAX_ARG]; } opcode_info[CREOLE_OPCODE_LEN] = { defop(NOOP, 0, TYPE_NONE, TYPE_NONE, TYPE_NONE), @@ -50,11 +49,11 @@ static const struct { defop(MUL, 3, TYPE_REG, TYPE_VAL, TYPE_VAL), defop(DIV, 3, TYPE_REG, TYPE_VAL, TYPE_VAL), defop(SYS, 1, TYPE_VAL, TYPE_NONE, TYPE_NONE), - defop(CLB, 1, TYPE_LAB, TYPE_NONE, TYPE_NONE), - defop(JL, 3, TYPE_LAB, TYPE_VAL, TYPE_VAL), - defop(JLE, 3, TYPE_LAB, TYPE_VAL, TYPE_VAL), - defop(JE, 3, TYPE_LAB, TYPE_VAL, TYPE_VAL), - defop(JNE, 3, TYPE_LAB, TYPE_VAL, TYPE_VAL) + defop(JL, 3, TYPE_IMM, TYPE_VAL, TYPE_VAL), + defop(JLE, 3, TYPE_IMM, TYPE_VAL, TYPE_VAL), + defop(JE, 3, TYPE_IMM, TYPE_VAL, TYPE_VAL), + defop(JNE, 3, TYPE_IMM, TYPE_VAL, TYPE_VAL), + defop(DB, 1, TYPE_IMM, TYPE_NONE, TYPE_NONE) }; /************************************************************************* @@ -330,52 +329,22 @@ int creole_encode(creole_word i, unsigned encode_to, unsigned high_bits, * one single byte of all zeros. *************************************************************************/ -enum creole_compiler_ret -creole_parse_line(struct creole_ins *ins, struct creole_reader *r) -{ - struct word w = {0}; - unsigned arg = 0; - - if (!decode_seq(r, &w)) - return CREOLE_OPCODE_READ_ERROR; - - ins->opcode = w.word; - if (w.word >= CREOLE_OPCODE_LEN || w.len != 1) { - return CREOLE_OPCODE_MALFORMED; - } - - for (arg = 0; arg < opcode_info[ins->opcode].arglen; arg++) { - if (!decode_seq(r, &w)) - return CREOLE_ARG_READ_ERROR; - if (w.len == 1) - return CREOLE_ARG_MALFORMED; - ins->w[arg] = w.word; - ins->w_flags[arg] = w.high_bits; - } - - if (!decode_seq(r, &w)) - return CREOLE_LAST_READ_ERROR; - if (w.word != 0 || w.len != 1) - return CREOLE_LAST_MALFORMED; - return CREOLE_COMPILE_OK; -} - -/************************************************************************** - * High level compiling interface - *************************************************************************/ +struct ins { + unsigned char *start; + unsigned char *datapt; + enum creole_opcode opcode; + creole_word w[CREOLE_MAX_ARG]; + creole_word w_flags[CREOLE_MAX_ARG]; +}; static int valid_register(struct creole_env *env, int reg) { return reg < env->reglen; } -static int valid_label(struct creole_env *env, int reg) -{ - return reg < env->lablen; -} - -static int typecheck(struct creole_env *env, int val, - enum creole_word_flag fl, enum creole_arg_type typ) +static int typecheck_arg(struct creole_env *env, int val, + enum creole_word_flag fl, + enum creole_arg_type typ) { switch (typ) { case TYPE_IMM: return fl == CREOLE_IMMEDIATE; @@ -383,13 +352,11 @@ static int typecheck(struct creole_env *env, int val, && valid_register(env, val); case TYPE_VAL: return fl == CREOLE_IMMEDIATE || fl == CREOLE_REGISTER; - case TYPE_LAB: return fl == CREOLE_IMMEDIATE - && valid_label(env, val); default: return 0; } } -static enum creole_word_flag get_type_from_high_bit(unsigned high_bits) +static enum creole_word_flag arg_get_type(unsigned high_bits) { if (high_bits & 1) { return CREOLE_REGISTER; @@ -398,89 +365,94 @@ static enum creole_word_flag get_type_from_high_bit(unsigned high_bits) } } -static enum creole_compiler_ret typecheck_ins(struct creole_env *env, - struct creole_ins *ins) +static enum creole_compiler_ret +parse_line(struct creole_env *env, struct ins *ins, struct creole_reader *r) { - unsigned i; + struct word w = {0}; + int i; + + ins->start = r->p; + if (!decode_seq(r, &w)) + return CREOLE_OPCODE_READ_ERROR; + ins->opcode = w.word; + if (w.word >= CREOLE_OPCODE_LEN || w.len != 1) { + return CREOLE_OPCODE_MALFORMED; + } + + if (opcode_info[ins->opcode].arglen >= CREOLE_MAX_ARG) + return CREOLE_OPCODE_MALFORMED; for (i = 0; i < opcode_info[ins->opcode].arglen; i++) { - if (!typecheck(env, ins->w[i], - get_type_from_high_bit(ins->w_flags[i]), - opcode_info[ins->opcode].argtype[i])) + if (!decode_seq(r, &w)) + return CREOLE_ARG_READ_ERROR; + if (w.len == 1) + return CREOLE_ARG_MALFORMED; + ins->w[i] = w.word; + ins->w_flags[i] = w.high_bits; + + if (!typecheck_arg(env, ins->w[i], + arg_get_type(ins->w_flags[i]), + opcode_info[ins->opcode].argtype[i])) return CREOLE_TYPE_ERROR; } + + if (ins->opcode == CREOLE_DB) { + ins->datapt = r->p; + do { + if (!decode_seq(r, &w)) + return CREOLE_ARG_READ_ERROR; + } while (w.len != 1); + if (w.word != 0) + return CREOLE_LAST_READ_ERROR; + return CREOLE_COMPILE_OK; + } + + ins->datapt = NULL; + if (!decode_seq(r, &w)) + return CREOLE_LAST_READ_ERROR; + if (w.word != 0 || w.len != 1) + return CREOLE_LAST_MALFORMED; return CREOLE_COMPILE_OK; } -static void clear_ins(struct creole_ins *i) -{ - const struct creole_ins blank = {0}; - *i = blank; -} +/************************************************************************** + * High level compiling interface + *************************************************************************/ -/**** - * Get rid of instructions that can be written out at compile time. - ***/ -static enum creole_compiler_ret -handle_compiletime_immediate(struct creole_env *env, - struct creole_ins *cur_ins) +static void +add_to_env(struct creole_env *env, struct ins *ins) { - switch (cur_ins->opcode) { - case CREOLE_CLB: - if (cur_ins->w[0] >= env->lablen) - return CREOLE_LABEL_OVERFLOW; - env->lab[cur_ins->w[0]] = env->prgptr; - /* Delete instruction because it is a compile time - * instruction. Place next instruction in its place. */ - clear_ins(cur_ins); - return CREOLE_COMPILE_CLEARED_INSTRUCTION; - case CREOLE_NOOP: - clear_ins(cur_ins); - return CREOLE_COMPILE_CLEARED_INSTRUCTION; + switch (ins->opcode) { + case CREOLE_DB: + env->dats[ins->w[0]] = ins->datapt; + break; default: - return typecheck_ins(env, cur_ins); + ; } } -/* TODO: The compile step can be completely removed in favor of directly - * executing the bytecode, disassembling it with creole_parse_line() - * at every instance. This will also make the implementation simpler. - */ - enum creole_compiler_ret -creole_compile(struct creole_env *env, struct creole_reader *r) +creole_compile(struct creole_env *env) { - struct creole_ins *cur_ins = env->prg; + struct ins ins = {0}; int rcode; - while (env->prgptr < env->prglen) { - rcode = creole_parse_line(cur_ins, r); - if (rcode != CREOLE_COMPILE_OK) - return rcode; + env->r_current = env->r_start; - rcode = handle_compiletime_immediate(env, cur_ins); - switch (rcode) { - case CREOLE_COMPILE_CLEARED_INSTRUCTION: - break; - case CREOLE_COMPILE_OK: - cur_ins++; - env->prgptr++; - break; - default: + while (!read_eof(&env->r_current)) { + rcode = parse_line(env, &ins, &env->r_current); + if (rcode != CREOLE_COMPILE_OK) return rcode; - } - - if (read_eof(r)) - break; + add_to_env(env, &ins); } - if (env->prgptr == env->prglen && !read_eof(r)) - return CREOLE_PROGRAM_OVERFLOW; - env->prgend = env->prgptr; - env->prgptr = 0; return CREOLE_COMPILE_OK; } +/************************************************************************** + * Running and interaction interface + *************************************************************************/ + enum creole_run_ret creole_reg_write(struct creole_env *env, unsigned reg, creole_word w) { @@ -501,11 +473,11 @@ enum creole_run_ret creole_reg_read(struct creole_env *env, unsigned reg, } static enum creole_run_ret read_val(struct creole_env *env, - struct creole_ins *ins, + struct ins *ins, unsigned arg, creole_word *w) { - if (get_type_from_high_bit(ins->w_flags[arg]) == CREOLE_REGISTER) { + if (arg_get_type(ins->w_flags[arg]) == CREOLE_REGISTER) { return creole_reg_read(env, ins->w[arg], w); } else { *w = ins->w[arg]; @@ -530,14 +502,6 @@ enum creole_run_ret creole_pop(struct creole_env *env, creole_word *w) return CREOLE_STEP_CONTINUE; } -static enum creole_run_ret -check_label(struct creole_env *env, creole_word label) -{ - return label < env->lablen - ? CREOLE_STEP_CONTINUE - : CREOLE_RUN_LABEL_OVERFLOW; -} - enum argument_signed { ALL_UNSIGNED = 0, /* 0b00 */ FIRST_SIGNED = 2, /* 0b10 */ @@ -556,8 +520,18 @@ static enum argument_signed check_sign_bits(unsigned flags1, unsigned flags2) return rcode; \ } while(0) +int creole_jump(struct creole_env *env, creole_word off) +{ + /* When env->r_start.left == off, this is the end of the program. */ + if (env->r_start.left < off) + return 0; + env->r_current.p = env->r_start.p + off; + env->r_current.left = env->r_start.left - off; + return 1; +} + #define chk_sign_op(OPER) do { \ - switch (check_sign_bits(ins->w_flags[1], ins->w_flags[2])) { \ + switch (check_sign_bits(ins.w_flags[1], ins.w_flags[2])) { \ case ALL_UNSIGNED: \ a1 = a1 OPER a2; \ break; \ @@ -577,90 +551,82 @@ static enum argument_signed check_sign_bits(unsigned flags1, unsigned flags2) enum creole_run_ret creole_step(struct creole_env *env, creole_word *sc) { - struct creole_ins *ins = env->prg + env->prgptr; - creole_word a1, a2; + struct ins ins = {0}; + creole_word a0, a1, a2; int rcode = CREOLE_STEP_CONTINUE; - int increase_pointer = 1; - if (env->prgptr == env->prgend) + if (env->r_current.left == 0) return CREOLE_STEP_STOP; - switch (ins->opcode) { + if (parse_line(env, &ins, &env->r_current) != CREOLE_COMPILE_OK) + return CREOLE_RUN_DECODE_ERROR; + + switch (ins.opcode) { case CREOLE_PUSH: - check(read_val(env, ins, 0, &a1)); + check(read_val(env, &ins, 0, &a1)); check(creole_push(env, a1)); break; case CREOLE_POP: check(creole_pop(env, &a1)); - check(creole_reg_write(env, ins->w[0], a1)); + check(creole_reg_write(env, ins.w[0], a1)); break; case CREOLE_ADD: - check(read_val(env, ins, 1, &a1)); - check(read_val(env, ins, 2, &a2)); - check(creole_reg_write(env, ins->w[0], a1 + a2)); + check(read_val(env, &ins, 1, &a1)); + check(read_val(env, &ins, 2, &a2)); + check(creole_reg_write(env, ins.w[0], a1 + a2)); break; case CREOLE_MUL: - check(read_val(env, ins, 1, &a1)); - check(read_val(env, ins, 2, &a2)); - check(creole_reg_write(env, ins->w[0], a1 * a2)); + check(read_val(env, &ins, 1, &a1)); + check(read_val(env, &ins, 2, &a2)); + check(creole_reg_write(env, ins.w[0], a1 * a2)); break; case CREOLE_DIV: - check(read_val(env, ins, 1, &a1)); - check(read_val(env, ins, 2, &a2)); + check(read_val(env, &ins, 1, &a1)); + check(read_val(env, &ins, 2, &a2)); if (a2 == 0) { return CREOLE_DIV_BY_ZERO; } chk_sign_op(/); - check(creole_reg_write(env, ins->w[0], a1)); + check(creole_reg_write(env, ins.w[0], a1)); break; case CREOLE_SYS: - check(read_val(env, ins, 0, sc)); + check(read_val(env, &ins, 0, sc)); rcode = CREOLE_STEP_SYSCALL; break; case CREOLE_JL: - check(read_val(env, ins, 1, &a1)); - check(read_val(env, ins, 2, &a2)); - check(check_label(env, ins->w[0])); + check(read_val(env, &ins, 0, &a0)); + check(read_val(env, &ins, 1, &a1)); + check(read_val(env, &ins, 2, &a2)); chk_sign_op(<); - if (a1) { - env->prgptr = env->lab[ins->w[0]]; - increase_pointer = 0; - } + if (a1 && !creole_jump(env, a0)) + return CREOLE_JUMP_OVERFLOW; break; case CREOLE_JLE: - check(read_val(env, ins, 1, &a1)); - check(read_val(env, ins, 2, &a2)); - check(check_label(env, ins->w[0])); + check(read_val(env, &ins, 0, &a0)); + check(read_val(env, &ins, 1, &a1)); + check(read_val(env, &ins, 2, &a2)); chk_sign_op(<=); - if (a1) { - env->prgptr = env->lab[ins->w[0]]; - increase_pointer = 0; - } + if (a1 && !creole_jump(env, a0)) + return CREOLE_JUMP_OVERFLOW; break; case CREOLE_JE: - check(read_val(env, ins, 1, &a1)); - check(read_val(env, ins, 2, &a2)); - check(check_label(env, ins->w[0])); - if (a1 == a2) { - env->prgptr = env->lab[ins->w[0]]; - increase_pointer = 0; - } + check(read_val(env, &ins, 0, &a0)); + check(read_val(env, &ins, 1, &a1)); + check(read_val(env, &ins, 2, &a2)); + if (a1 == a2 && !creole_jump(env, a0)) + return CREOLE_JUMP_OVERFLOW; break; case CREOLE_JNE: - check(read_val(env, ins, 1, &a1)); - check(read_val(env, ins, 2, &a2)); - check(check_label(env, ins->w[0])); - if (a1 != a2) { - env->prgptr = env->lab[ins->w[0]]; - increase_pointer = 0; - } + check(read_val(env, &ins, 0, &a0)); + check(read_val(env, &ins, 1, &a1)); + check(read_val(env, &ins, 2, &a2)); + if (a1 != a2 && !creole_jump(env, a0)) + return CREOLE_JUMP_OVERFLOW; break; default: rcode = CREOLE_STEP_UNKNOWN_OPCODE; } - if (increase_pointer) - env->prgptr++; return rcode; } |
