import re
import yaml
def gen_tags(tags):
stmts = []
for tag, i in zip(tags, range(len(tags))):
stmts.append('TAG_%-12s = %d' % (tag.upper(), 2**i))
return '\n'.join(stmts)
def gen_actions(instructions):
def gen_action(insn):
func = "def op_%s(ctx):\n" % insn['name']
env = {
'insn_len' : 1 + len(insn['operands'])
}
code = insn['code']
if not 'ctrl_flow' in insn['tags']:
code += 'ctx.ip += $(insn_len)\n'
code = process_tmpl(code, env)
code = re.sub(re.compile('^', re.MULTILINE), ' ', code)
return func + code
return '\n'.join([gen_action(insn)
for insn in instructions])
def gen_action_table(instructions):
return 'INSN_ACTION = [\n' + \
',\n'.join([' op_' + insn['name']
for insn in instructions]) + \
'\n]\n'
def gen_tags_table(instructions):
def gen_tag(insn):
if len(insn['tags']) == 0:
return '0'
else:
return ' | '.join(['TAG_%s' % tag.upper()
for tag in insn['tags']])
return 'INSN_TAGS = [\n' + \
',\n'.join([' ' + gen_tag(insn)
for insn in instructions]) + \
'\n]\n'
def gen_insn_table(instructions):
def gen_insn(i, insn):
return "Instruction(" + str(i) + ",\n" + \
",\n".join([" " + insn[key].__repr__()
for key in ['name', 'tags', 'desc', 'operands',
'stack_before', 'stack_after', 'code']]) + \
")"
insns = zip(range(len(instructions)), instructions)
return "INSTRUCTIONS = [\n" + \
",\n".join([gen_insn(i, insn)
for i, insn in insns]) + \
"]\n\nINSN_MAP = {\n" + \
",\n".join([' ' + insn['name'].__repr__() + ' : INSTRUCTIONS[%d]' % i
for i, insn in insns]) + \
"\n}\n"
def process_tmpl(tmpl, env):
"""\
Process template. Special variables like $(key) in the template
will be replaced by the value found in env (env['key']).
"""
PATTERN = re.compile(r"\$\(([^)]+)\)")
return re.sub(PATTERN, lambda m: str(env[m.group(1)]), tmpl)
TMPL_INSNS = """\
# Don't edit this file. This is generated by iset_gen.py
from .ctx import Context
from .call_cc import Continuation
from .proc import Procedure
from .prim import Primitive
from .types.pair import Pair
from .errors import WrongArgType
$(tags)
$(actions)
$(action_table)
$(tags_table)
def has_tag(opcode, tag):
return INSN_TAGS[opcode] & tag == tag
def get_param(ctx, n):
return ctx.bytecode[ctx.ip+n]
def run(ctx):
while ctx.ip < len(ctx.bytecode):
opcode = ctx.bytecode[ctx.ip]
nctx = INSN_ACTION[opcode](ctx)
if has_tag(opcode, TAG_CTX_SWITCH):
ctx = nctx
return ctx.pop()
def make_call(ctx, argc, tail=False):
proc = ctx.pop()
if tail:
parent = ctx.parent
else:
parent = ctx
if isinstance(proc, Procedure):
proc.check_arity(argc)
nctx = Context(proc, proc.env.dup(), parent)
for i in range(proc.fixed_argc):
nctx.env.assign_local(i, ctx.top(idx=argc-i))
if proc.fixed_argc != proc.argc:
rest = None
for i in range(argc-proc.fixed_argc):
rest = Pair(ctx.top(idx=i+1), rest)
nctx.env.assign_local(proc.fixed_argc, rest)
ctx.pop_n(argc)
elif isinstance(proc, Primitive):
proc.check_arity(argc)
args = range(argc)
for i in range(argc):
args[i] = ctx.top(idx=argc-i)
ctx.pop_n(argc)
nctx = parent
nctx.push(proc.call(ctx.vm, *args))
elif isinstance(proc, Continuation):
if argc > 1:
raise WrongArgNumber("Continuation only accept 1 argument")
nctx = proc.ctx.clone()
if argc == 1:
nctx.push(ctx.pop())
else:
nctx.push(None)
nctx.parent = ctx.parent
else:
raise WrongArgType("Not a skime callable: %s" % proc)
return nctx
"""
TMPL_ISET = """\
# Don't edit this file. This is generated by iset_gen.py
class Instruction(object):
__slots__ = ('opcode',
'name',
'tags',
'desc',
'operands',
'stack_before',
'stack_after',
'code')
def __init__(self, opcode, name, tags, desc, operands,
stack_before, stack_after, code):
self.opcode = opcode
self.name = name
self.tags = tags
self.desc = desc
self.operands = operands
self.stack_before = stack_before
self.stack_after = stack_after
self.code = code
def length_get(self):
return len(self.operands)+1
def length_set(self):
raise AttributeError, 'length attribute is read only'
length = property(length_get, length_set, 'length of the instruction')
$(instruction_table)
"""
if __name__ == '__main__':
iset = yaml.load(open("iset.yml").read())
env = {
'tags' : gen_tags(iset['tags']),
'actions' : gen_actions(iset['instructions']),
'instruction_table' : gen_insn_table(iset['instructions']),
'action_table' : gen_action_table(iset['instructions']),
'tags_table' : gen_tags_table(iset['instructions'])
}
py = open("iset.py", "w")
py.write(process_tmpl(TMPL_ISET, env))
py.close()
py = open("insns.py", "w")
py.write(process_tmpl(TMPL_INSNS, env))
py.close()