Skip to content

Instantly share code, notes, and snippets.

@king1600
Last active May 26, 2018 03:37
Show Gist options
  • Save king1600/bc36baa82ba0fe2d5a45f4a817aa9690 to your computer and use it in GitHub Desktop.
Save king1600/bc36baa82ba0fe2d5a45f4a817aa9690 to your computer and use it in GitHub Desktop.
Python kasm v5
import string
from collections import deque
class Token:
__slots__ = ('op','args','lineno','text','next')
def __init__(self, **kwargs):
self.op = self.args = self.lineno = self.text = self.next = None
self.set(**kwargs)
def set(self, **kwargs):
for attr in self.__slots__:
if attr in kwargs:
setattr(self, attr, kwargs[attr])
class Scope:
__slots__ = ('name','last','symbols')
def __init__(self, last=None, name=None):
self.name = name
self.last = last
self.symbols = {}
def set(self, symbol, value):
self.symbols[symbol] = value
def get(self, symbol):
if symbol in self.symbols:
return self.symbols[symbol];
if self.last is not None:
return self.last.get(symbol)
return None
VARS = string.ascii_letters + '_'
INSTRUCTIONS = ('set','mov','exit',
'add','sub','div','mul','out',
'func','ret','call','push','pop',
'cmp','ne','lt','gt','lte','gte',
'jmp','jcp','ccal','name')
class KasmContext:
def __init__(self, stdout=print, max_cmd=-1):
self.stdout = stdout
self.cmd_inc = 0
self.depth = 0
self.stack = deque()
self.calls = deque()
self.max_cmd = max_cmd
self.g_scope = Scope(name='global')
self.scope = self.g_scope
self.max_recursion = 4096
self.reg = self.rxx = self.carry = False
def eval(self, code):
token = self.lex(code)
while token is not None:
token = self.interpret(token)
def set(self, var, item):
if var == 'reg':
self.reg = item
elif var == 'rxx':
self.rxx = item
elif var == 'clr':
self.carry = var
elif self.scope.get(var) is not None:
self.scope.set(var, item)
else:
raise Exception("Cannot set {0} to {1}".format(var, item))
def get(self, var):
if var == 'reg':
return self.reg
elif var == 'rxx':
return self.rxx
elif var == 'null':
return 0
elif var == 'clr':
return self.carry
elif var == 'pop':
return self.stack.pop()
if var[0] in VARS:
value = self.scope.get(var)
if value == None:
raise Exception('"{0}" does not exist in scope'.format(var))
return value
else:
return eval(var, {})
def lex(self, code):
token, first, line, lines = None, None, '', code.split('\n')
for i in range(len(lines)):
try:
line = lines[i].lstrip().rstrip()
line = line.split(';')[0]
if line.isspace() or len(line) < 1:
continue
parts = line.split(' ')
if token is not None:
token.next = Token(lineno=i + 1, text=line, next=None)
token = token.next
else:
token = Token(lineno=i + 1, text=line, next=None)
first = token
token.op = parts[0].lower()
token.args = (l.rstrip().lstrip() for l in ' '.join(parts[1:]).split(','))
token.args = tuple(filter(lambda x: len(x) > 0, token.args))
if token.op not in INSTRUCTIONS:
raise Exception("Invalid instruction")
except Exception as err:
raise Exception('Error on line:{0} "{1}"> {2}'.format(i, lines[i], err))
return first
def interpret(self, t):
if t == None:
return None
if self.depth > 0:
if t.op == 'ret':
self.depth -= 1
return t.next
next_token = t.next
old_carry = self.carry
self.cmd_inc += 1
if self.max_cmd > 0 and self.cmd_inc > self.max_cmd:
raise Exception("Maximum instructions issued")
if t.op == 'set':
self.scope.set(t.args[0], self.get(t.args[1]))
elif t.op == 'name':
self.scope.set(t.args[0], t)
elif t.op == 'mov':
self.set(t.args[0], self.get(t.args[1]))
elif t.op == 'exit':
return None
elif t.op == 'add':
self.set(t.args[0], self.get(t.args[0]) + self.get(t.args[1]))
elif t.op == 'sub':
self.set(t.args[0], self.get(t.args[0]) - self.get(t.args[1]))
elif t.op == 'mul':
self.set(t.args[0], self.get(t.args[0]) * self.get(t.args[1]))
elif t.op == 'div':
self.set(t.args[0], self.get(t.args[0]) / self.get(t.args[1]))
elif t.op == 'out':
self.stdout(' '.join([str(self.get(arg)) for arg in t.args]))
elif t.op == 'func':
self.scope.set(t.args[0], t)
self.depth += 1
elif t.op == 'ret':
self.rxx = self.get(t.args[0])
if len(self.calls) > 0:
if self.scope.last is not None:
self.scope = self.scope.last
next_token = self.calls.pop().next
elif t.op == 'call':
self.calls.append(t)
func = self.scope.get(t.args[0])
self.scope = Scope(last=self.scope, name=func.args[0])
next_token = func.next
elif t.op == 'push':
for arg in t.args:
self.stack.append(self.get(arg))
elif t.op == 'pop':
self.set(t.args[0], self.stack.pop())
elif t.op == 'cmp':
self.carry = 1 if self.get(t.args[0]) == self.get(t.args[1]) else 0
elif t.op == 'ne':
self.carry = 1 if self.get(t.args[0]) != self.get(t.args[1]) else 0
elif t.op == 'lt':
self.carry = 1 if self.get(t.args[0]) < self.get(t.args[1]) else 0
elif t.op == 'gt':
self.carry = 1 if self.get(t.args[0]) > self.get(t.args[1]) else 0
elif t.op == 'lte':
self.carry = 1 if self.get(t.args[0]) <= self.get(t.args[1]) else 0
elif t.op == 'gte':
self.carry = 1 if self.get(t.args[0]) >= self.get(t.args[1]) else 0
elif t.op == 'jmp':
return self.interpret(self.scope.get(t.args[0]).next)
elif t.op == 'jcp':
if self.carry:
next_token = self.scope.get(t.args[0]).next
elif t.op == 'ccal':
if self.carry:
self.calls.append(t)
func = self.scope.get(t.args[0])
self.scope = Scope(last=self.scope, name=func.args[0])
next_token = func.next
if self.carry and old_carry:
self.carry = 0
return next_token
################# Example: #######################3
kasm = KasmContext()
kasm.eval("""
set i, 0 ; create variable i
name for_loop ; define a point for looping
out i ; output the variable i
add i, 1 ; i += 1
lt i, 10 ; check if i < 10 (less than)
jcp for_loop ; if check success, jump back up to for_loop
exit ; if not success, exit program (not needed tho)
""")
@Luminous-dev
Copy link

Nice

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment