add compile t est

This commit is contained in:
Peter McGoron 2023-02-09 16:16:41 +00:00
parent e044a7b457
commit c0770d8ece
6 changed files with 134 additions and 51 deletions

View File

@ -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

View File

@ -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]),

View File

@ -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)))

View File

@ -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()

View File

@ -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)

View File

@ -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 */