diff --git a/Makefile b/Makefile index 343c3a4..80cbb1f 100644 --- a/Makefile +++ b/Makefile @@ -2,6 +2,8 @@ asm/libcreole.so: creole.c creole.h $(CC) -Wall -fPIC -c creole.c -o c_test/creole.o $(CC) -shared -o asm/libcreole.so c_test/creole.o +test_asm: asm/libcreole.so + cd asm && python3 test.py c_test/encode_decode: c_test/encode_decode.c creole.c creole.h $(CC) c_test/encode_decode.c -Wall -pedantic -std=c89 -g -fopenmp -o c_test/encode_decode c_test/creole: c_test/creole.c creole.c creole.h greatest.h diff --git a/asm/creole.py b/asm/creole.py index c1045c5..1ed25e8 100644 --- a/asm/creole.py +++ b/asm/creole.py @@ -73,7 +73,7 @@ class Instruction: instructions = { "nop" : Instruction(0, []), -"push" : Instruction(1, [ArgType.REG]), +"push" : Instruction(1, [ArgType.VAL]), "pop" : Instruction(2, [ArgType.REG]), "add" : Instruction(3, [ArgType.VAL, ArgType.VAL, ArgType.VAL]), "mul" : Instruction(4, [ArgType.VAL, ArgType.VAL, ArgType.VAL]), diff --git a/asm/ffi.py b/asm/ffi.py index 7468996..cb30ce9 100644 --- a/asm/ffi.py +++ b/asm/ffi.py @@ -3,7 +3,7 @@ from enum import Enum dll = CDLL("./libcreole.so") class CompileRet(Enum): - COMPILE_OK = 0 + OK = 0 OPCODE_READ_ERROR = 1 OPCODE_MALFORMED = 2 ARG_READ_ERROR = 3 @@ -12,6 +12,7 @@ class CompileRet(Enum): LAST_MALFORMED = 6 LABEL_OVERFLOW = 7 TYPE_ERROR = 8 + CLEARED_INSTRUCTION = 9 class CIns(Structure): _fields_ = [("opcode", c_int), @@ -25,17 +26,64 @@ def make_uchar_buf(s): buf = (c_ubyte * len(s))() buf[:] = s[:] return buf +def make_reader(s): + buf = make_uchar_buf(s) + return CReader(buf, len(s)) + +class CEnv(Structure): + _fields_ = [ + ("reg", POINTER(c_uint)), + ("reglen", c_size_t), + ("lab", POINTER(c_size_t)), + ("lablen", c_size_t), + ("stk", POINTER(c_uint)), + ("stkptr", c_size_t), + ("stklen", c_size_t), + ("prg", POINTER(CIns)), + ("prgptr", c_size_t), + ("prgend", c_size_t), + ("prglen", c_size_t) + ] + +class ExecutionEnvironment: + def __init__(self, reglen=32, lablen=32, stklen=4096, prglen=4096): + cenv = CEnv() + cenv.reglen = reglen + cenv.reg = (c_uint * reglen)() + + cenv.lablen = lablen + cenv.lab = (c_size_t * lablen)() + + cenv.stklen = stklen + cenv.stk = (c_uint * stklen)() + cenv.stkptr = 0 + + cenv.prglen = prglen + cenv.prg = (CIns * prglen)() + cenv.prgptr = 0 + cenv.prgend = 0 + + self.cenv = cenv + + def restart(self): + self.cenv.stkptr = 0 + self.cenv.prgptr = 0 + self.cenv.prgend = 0 + + def load(self, prog): + rd = make_reader(prog) + self.restart() + ret = dll.creole_compile(byref(self.cenv), byref(rd)) + return CompileRet(ret) class CParseLineException(Exception): pass def parse_line(line): - buf = make_uchar_buf(line) - - rd = CReader(buf, len(line)) + rd = make_reader(line) ins = CIns() ret = dll.creole_parse_line(byref(ins), byref(rd)) - if ret != 0: - raise CParseLineException(ret) + if ret != CompileRet.OK.value: + raise CParseLineException(CompileRet(ret).name) return (ins.opcode, list(zip(ins.w_flags, ins.w))) diff --git a/asm/test.py b/asm/test.py index b9d6520..06a878f 100644 --- a/asm/test.py +++ b/asm/test.py @@ -7,25 +7,25 @@ class PushTest(unittest.TestCase): p = Program() p.parse_asm_line("push r5") b = p() - self.assertEqual(b, b'\x01\xC2\x80\x00') + self.assertEqual(b, b'\x01\xC2\x85\x00') ins = ffi.parse_line(b) self.assertEqual(ins[0], instructions["push"].opcode) self.assertEqual(ins[1][0], (1,5)) - def test_parse_push_catch_typecheck_push_imm(self): + def test_parse_push_imm(self): p = Program() - with self.assertRaises(TypecheckException) as cm: - p.parse_asm_line("push 0") - self.assertEqual(cm.exception.argtype, ArgType.REG) - self.assertEqual(cm.exception.sarg, '0') - self.assertEqual(cm.exception.i, 0) - self.assertEqual(cm.exception.opcode, 1) + p.parse_asm_line("push 5") + b = p() + self.assertEqual(b, b'\x01\xC0\x85\x00') + ins = ffi.parse_line(b) + self.assertEqual(ins[0], instructions["push"].opcode) + self.assertEqual(ins[1][0], (0,5)) def test_parse_push_catch_typecheck_push_lab(self): p = Program() with self.assertRaises(TypecheckException) as cm: p.parse_asm_line("push l0") - self.assertEqual(cm.exception.argtype, ArgType.REG) + self.assertEqual(cm.exception.argtype, ArgType.VAL) self.assertEqual(cm.exception.sarg, 'l0') self.assertEqual(cm.exception.i, 0) self.assertEqual(cm.exception.opcode, 1) @@ -52,6 +52,32 @@ class PushTest(unittest.TestCase): b = p() self.assertEqual(b, b'\x01\xFC\x87\xbf\xbf\xbf\xbf\x00') + def test_compile_push(self): + p = Program() + p.parse_asm_line("PUSH r0") + p.parse_asm_line("PUSH r6") + b = p() + + ex = ffi.ExecutionEnvironment() + self.assertEqual(ex.load(b), ffi.CompileRet.OK) + self.assertEqual(ex.cenv.prgend, 2) + + self.assertEqual(ex.cenv.prg[0].opcode, 1) + self.assertEqual(ex.cenv.prg[0].w_flags[0], 1) + self.assertEqual(ex.cenv.prg[0].w_flags[1], 0) + self.assertEqual(ex.cenv.prg[0].w_flags[2], 0) + self.assertEqual(ex.cenv.prg[0].w[0], 0) + self.assertEqual(ex.cenv.prg[0].w[1], 0) + self.assertEqual(ex.cenv.prg[0].w[2], 0) + + self.assertEqual(ex.cenv.prg[1].opcode, 1) + self.assertEqual(ex.cenv.prg[1].w_flags[0], 1) + self.assertEqual(ex.cenv.prg[1].w_flags[1], 0) + self.assertEqual(ex.cenv.prg[1].w_flags[2], 0) + self.assertEqual(ex.cenv.prg[1].w[0], 6) + self.assertEqual(ex.cenv.prg[1].w[1], 0) + self.assertEqual(ex.cenv.prg[1].w[2], 0) + class ProgramTest(unittest.TestCase): def test_two(self): p = Program() diff --git a/creole.c b/creole.c index d2a06cb..78beaa0 100644 --- a/creole.c +++ b/creole.c @@ -342,27 +342,17 @@ creole_parse_line(struct creole_ins *ins, struct creole_reader *r) return CREOLE_COMPILE_OK; } -#if 0 - /************************************************************************** * High level compiling interface *************************************************************************/ -static void clear_instruction(struct creole_env *env, - struct creole_ins *ins) -{ - memset(ins, 0, sizeof(ins)); - env->prgptr--; -} - static int typecheck(enum creole_word_flag fl, enum creole_arg_type typ) { switch (typ) { - case TYPE_NONE: return 0; case TYPE_IMM: return fl == CREOLE_IMMEDIATE; case TYPE_REG: return fl == CREOLE_REGISTER; case TYPE_VAL: return fl == CREOLE_IMMEDIATE - | fl == CREOLE_REGISTER; + || fl == CREOLE_REGISTER; case TYPE_LAB: return fl == CREOLE_IMMEDIATE; default: return 0; } @@ -373,65 +363,78 @@ static enum creole_compiler_ret typecheck_ins(struct creole_env *env, { unsigned i; - for (i = 0; i < opcode_info[env->opcode].arglen; i++) { - if (!typecheck(ins->w[i], - opcode_info[env->opcode].argtype[i])) + for (i = 0; i < opcode_info[ins->opcode].arglen; i++) { + if (!typecheck(ins->w_flags[i], + opcode_info[ins->opcode].argtype[i])) return CREOLE_TYPE_ERROR; } return CREOLE_COMPILE_OK; } +static void clear_ins(struct creole_ins *i) +{ + i->opcode = 0; + i->w[0] = i->w[1] = i->w[2] = i->w_flags[0] = + i->w_flags[1] = i->w_flags[2] = 0; +} + static enum creole_compiler_ret handle_compiletime_immediate(struct creole_env *env, - struct creole_ins *ins) + struct creole_ins *cur_ins) { - switch (ins->opcode) { + switch (cur_ins->opcode) { case CREOLE_CLB: - if (ins->w[0] >= ins->lablen) + if (cur_ins->w[0] >= env->lablen) return CREOLE_LABEL_OVERFLOW; - ins->lab[ins->w[0]] = env->prgptr; + env->lab[cur_ins->w[0]] = env->prgptr; /* Delete instruction because it is a compile time * instruction. Place next instruction in its place. */ - clear_instruction(env, ins); - return CREOLE_COMPILE_OK; + clear_ins(cur_ins); + return CREOLE_COMPILE_CLEARED_INSTRUCTION; case CREOLE_NOOP: - clear_instruction(env, ins); - return CREOLE_COMPILE_OK; + clear_ins(cur_ins); + return CREOLE_COMPILE_CLEARED_INSTRUCTION; default: - return typecheck_ins(env, ins); + return typecheck_ins(env, cur_ins); } } -int creole_compile(struct creole_env *env, struct creole_reader *r) +enum creole_compiler_ret +creole_compile(struct creole_env *env, struct creole_reader *r) { struct creole_ins *cur_ins = env->prg; int rcode; while (env->prgptr < env->prglen) { - if (!creole_parse_line(cur_ins, r)) - return CREOLE_PARSE_ERROR; - /* Increase prgptr here. If the instruction is a compile - * time instruction, then this will be decremented since - * the instruction will not be executed. - */ - env->prgptr++; - - rcode = handle_compiletime_immediate(env, cur_ins); + rcode = creole_parse_line(cur_ins, r); if (rcode != CREOLE_COMPILE_OK) return rcode; + 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: + return rcode; + } + if (read_eof(r)) break; - cur_ins += 1; } - if (env->prgptr == env->prglen && *line) + if (env->prgptr == env->prglen && !read_eof(r)) return CREOLE_PROGRAM_OVERFLOW; env->prgend = env->prgptr; env->prgptr = 0; return CREOLE_COMPILE_OK; } +#if 0 + static creole_word read_word(struct creole_ins *ins, int i) { if (env->w_flags[i] == CREOLE_REGISTER) diff --git a/creole.h b/creole.h index da6b662..827fe82 100644 --- a/creole.h +++ b/creole.h @@ -42,6 +42,8 @@ enum creole_compiler_ret { CREOLE_LAST_MALFORMED, CREOLE_LABEL_OVERFLOW, CREOLE_TYPE_ERROR, + CREOLE_COMPILE_CLEARED_INSTRUCTION, + CREOLE_PROGRAM_OVERFLOW, CREOLE_COMPILE_RET_LEN }; @@ -74,5 +76,7 @@ int creole_encode(creole_word i, unsigned encode_to, unsigned high_bits, unsigned char buf[7]); enum creole_compiler_ret creole_parse_line(struct creole_ins *ins, struct creole_reader *r); +enum creole_compiler_ret +creole_compile(struct creole_env *env, struct creole_reader *r); #endif /* CREOLE_H */