add compile t est
This commit is contained in:
parent
e044a7b457
commit
c0770d8ece
2
Makefile
2
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
|
||||
|
|
|
@ -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]),
|
||||
|
|
60
asm/ffi.py
60
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)))
|
||||
|
|
44
asm/test.py
44
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()
|
||||
|
|
73
creole.c
73
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)
|
||||
|
|
4
creole.h
4
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 */
|
||||
|
|
Loading…
Reference in New Issue