|
|
|
@ -0,0 +1,166 @@
|
|
|
|
|
#!/usr/bin/env python3
|
|
|
|
|
|
|
|
|
|
from rply import LexerGenerator, ParserGenerator, Token
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_lexer = LexerGenerator()
|
|
|
|
|
_lexer.add("OPCODE2", r"SET|ADD|SUB|MUL|MLI|DIV|MOD|MDI|AND|BOR|XOR|SHR|ASR|SHL|IFB|IFC|IFE|IFN|IFG|IFA|IFL|IFU|ADX|SBX|STI|STD")
|
|
|
|
|
_lexer.add("OPCODE1", r"JSR|INT|IAG|IAS|RFI|IAQ|HWN|HWQ|HWI")
|
|
|
|
|
_lexer.add("OPCODE0", r"HLT")
|
|
|
|
|
_lexer.add("GREG", r"A|B|C|X|Y|Z|I|J")
|
|
|
|
|
_lexer.add("SREG", r"SP|PC|EX")
|
|
|
|
|
_lexer.add("STACK", r"PUSH|POP|PEEK|PICK")
|
|
|
|
|
_lexer.add("COMMA", r",")
|
|
|
|
|
_lexer.add("COLON", r":")
|
|
|
|
|
_lexer.add("OPENSB", r"\[")
|
|
|
|
|
_lexer.add("CLOSESB", r"\]")
|
|
|
|
|
|
|
|
|
|
_lexer.add("OPENRB", r"\(")
|
|
|
|
|
_lexer.add("CLOSERB", r"\)")
|
|
|
|
|
_lexer.add("NUMBER", r"0x[0-9a-fA-F]+|[0-9]+")
|
|
|
|
|
_lexer.add("SYMBOL", r"[a-zA-Z._@][a-zA-Z._@0-9]*")
|
|
|
|
|
_lexer.add("PLUS", r"\+")
|
|
|
|
|
_lexer.add("MINUS", r"-")
|
|
|
|
|
_lexer.add("STAR", r"\*")
|
|
|
|
|
_lexer.add("SLASH", r"/")
|
|
|
|
|
_lexer.add("EOL", r"(([;#][^\n]*)?(\r?\n))+")
|
|
|
|
|
_lexer.ignore(r"[ \t]+")
|
|
|
|
|
#_lexer.ignore(r"\s+|([;#][^\n]*)?\n")
|
|
|
|
|
lexer = _lexer.build()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
_parser = ParserGenerator([x.name for x in lexer.rules],
|
|
|
|
|
precedence=[
|
|
|
|
|
("left", ["PLUS", "MINUS"]),
|
|
|
|
|
("left", ["STAR", "SLASH"])
|
|
|
|
|
]
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
@_parser.production("asmcode : asmline")
|
|
|
|
|
def asmcode1(p):
|
|
|
|
|
return [p[0]]
|
|
|
|
|
|
|
|
|
|
@_parser.production("asmcode : asmcode asmline")
|
|
|
|
|
def asmcode2(p):
|
|
|
|
|
return p[0]+[p[1]]
|
|
|
|
|
|
|
|
|
|
@_parser.production("asmline : SYMBOL asminst EOL")
|
|
|
|
|
def asmline_label(p):
|
|
|
|
|
return (p[0].getstr(), p[1])
|
|
|
|
|
|
|
|
|
|
@_parser.production("asmline : SYMBOL COLON asminst EOL")
|
|
|
|
|
def asmline_label_colon(p):
|
|
|
|
|
return (p[0].getstr(), p[2])
|
|
|
|
|
|
|
|
|
|
@_parser.production("asmline : asminst EOL")
|
|
|
|
|
def asmline_asminst(p):
|
|
|
|
|
return (None, p[0])
|
|
|
|
|
|
|
|
|
|
@_parser.production("asmline : SYMBOL COLON EOL")
|
|
|
|
|
@_parser.production("asmline : SYMBOL EOL")
|
|
|
|
|
def asmline_label_colon(p):
|
|
|
|
|
return (p[0].getstr(), None)
|
|
|
|
|
|
|
|
|
|
@_parser.production("asmline : EOL")
|
|
|
|
|
def asmline_empty(p):
|
|
|
|
|
return (None, None)
|
|
|
|
|
|
|
|
|
|
@_parser.production("asminst : OPCODE0")
|
|
|
|
|
def opcode0(p):
|
|
|
|
|
return (p[0], None, None)
|
|
|
|
|
|
|
|
|
|
@_parser.production("asminst : OPCODE1 am")
|
|
|
|
|
def opcode1(p):
|
|
|
|
|
return (p[0], p[1], None)
|
|
|
|
|
|
|
|
|
|
@_parser.production("asminst : OPCODE2 am COMMA am")
|
|
|
|
|
def opcode2(p):
|
|
|
|
|
return (p[0], p[1], p[3])
|
|
|
|
|
|
|
|
|
|
@_parser.production("am : OPENSB GREG PLUS expression CLOSESB")
|
|
|
|
|
@_parser.production("am : OPENSB GREG MINUS expression CLOSESB")
|
|
|
|
|
def am_ind_reg_disp(p):
|
|
|
|
|
return (p[1], p[2], p[3])
|
|
|
|
|
|
|
|
|
|
@_parser.production("am : OPENSB GREG CLOSESB")
|
|
|
|
|
@_parser.production("am : OPENSB expression CLOSESB")
|
|
|
|
|
def am_ind(p):
|
|
|
|
|
return p[1]
|
|
|
|
|
|
|
|
|
|
@_parser.production("am : expression")
|
|
|
|
|
def am_lit(p):
|
|
|
|
|
return p[0]
|
|
|
|
|
|
|
|
|
|
@_parser.production("am : GREG")
|
|
|
|
|
@_parser.production("am : SREG")
|
|
|
|
|
@_parser.production("am : STACK")
|
|
|
|
|
def am_reg_stack(p):
|
|
|
|
|
return p[0]
|
|
|
|
|
|
|
|
|
|
@_parser.production("expression : OPENRB expression CLOSERB")
|
|
|
|
|
def expression_parens(p):
|
|
|
|
|
return p[1]
|
|
|
|
|
|
|
|
|
|
def do_binop(op, a, b):
|
|
|
|
|
an = int(a)
|
|
|
|
|
bn = int(b)
|
|
|
|
|
if op == "PLUS":
|
|
|
|
|
return an+bn
|
|
|
|
|
elif op == "MINUS":
|
|
|
|
|
return an-bn
|
|
|
|
|
if op == "STAR":
|
|
|
|
|
return an*bn
|
|
|
|
|
elif op == "SLASH":
|
|
|
|
|
return an/bn
|
|
|
|
|
|
|
|
|
|
@_parser.production("expression : expression binop expression")
|
|
|
|
|
def expression_binop(p):
|
|
|
|
|
a, op, b = tuple(p)
|
|
|
|
|
if a.gettokentype() == b.gettokentype() == "NUMBER":
|
|
|
|
|
result = do_binop(op.gettokentype(), a.getstr(), b.getstr())
|
|
|
|
|
return Token("NUMBER", str(result), a.getsourcepos())
|
|
|
|
|
return (op, a, b)
|
|
|
|
|
|
|
|
|
|
@_parser.production("register : GREG")
|
|
|
|
|
@_parser.production("register : SREG")
|
|
|
|
|
@_parser.production("register : STACK")
|
|
|
|
|
def expression_register(p):
|
|
|
|
|
return p[0]
|
|
|
|
|
|
|
|
|
|
@_parser.production("expression : register")
|
|
|
|
|
def expression_number(p):
|
|
|
|
|
return p[0]
|
|
|
|
|
|
|
|
|
|
@_parser.production("expression : NUMBER")
|
|
|
|
|
def expression_number(p):
|
|
|
|
|
return p[0]
|
|
|
|
|
|
|
|
|
|
@_parser.production("binop : PLUS")
|
|
|
|
|
@_parser.production("binop : MINUS")
|
|
|
|
|
@_parser.production("binop : STAR")
|
|
|
|
|
@_parser.production("binop : SLASH")
|
|
|
|
|
def expression_parens(p):
|
|
|
|
|
return p[0]
|
|
|
|
|
|
|
|
|
|
parser = _parser.build()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def assemble(filename):
|
|
|
|
|
with open(filename, "r") as f:
|
|
|
|
|
text = f.read()
|
|
|
|
|
tokens = list(lexer.lex(text))
|
|
|
|
|
#print(tokens)
|
|
|
|
|
#print(parser.parse(iter(tokens)))
|
|
|
|
|
for instr in parser.parse(iter(tokens)):
|
|
|
|
|
print(instr)
|
|
|
|
|
#for token in lexer.lex(text):
|
|
|
|
|
# print(token.source_pos, token)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if __name__ == '__main__':
|
|
|
|
|
import sys
|
|
|
|
|
|
|
|
|
|
for f in sys.argv[1:]:
|
|
|
|
|
assemble(f)
|
|
|
|
|
|
|
|
|
|
# vim:et:sw=4:ts=4:sts=4:
|