asmTron/compiler_beta.py
2020-05-29 00:41:13 +02:00

659 lines
24 KiB
Python

import asm
def padBin(number,bit=8):
return asm.padBin(asm.toBin(number),bit=bit)
def toDec(binNumber):
return asm.toDec(binNumber)
doc = """
0000 NOP
0001 LDA memory > A
0010 ADD A + memspace
0011 SUB A - memspace
0100 STA A > memory
0101 OUT A > OUT
0110 JMP Jump to adress
0111 LDI par > A
1000 JIF Jump if greater
1001 JIE Jump if equal
1010 LDP memory[A] > A
1011 INP IN > A
1100 JMA Jump to A
1101 --- not implemented
1110 STP memory[par] > memory[A]
1111 HLT Halt
"""
def compile(cmd,par,memAddr):
# Every function creates unknown vars, even if it makes no sense in it case,
# because if the function sits inside a user-defined function vars may be
# defined later
#try:
if cmd=="newVar": # creates new var and allocates memory-adress for it
print("Creating var '"+par[0].upper()+"' at memory-address "+padBin(len(varRec)+(2**8)/2))
varRec[par[0].upper()] = len(varRec)+(2**8)/2
print("[i] newVar is obsolete in this version of tronScript")
elif cmd=="newArray": # creates new array and allocates memory-adress for it
print("Creating array '"+par[0].upper()+"' at memory-space "+padBin(len(varRec)+(2**8)/2)+" - "+padBin(len(varRec)+int(par[1])+(2**8)/2))
for i in range(int(par[1])):
varRec["array_"+par[0].upper()+"["+i+"]"] = len(varRec)+(2**8)/2
elif cmd=="jumpMark": # creates a jumpMark and saves current adress in the DB for later use by the jump-name-replacement
print("Creating jumpMark '"+par[0].upper()+"' at memory-address "+padBin(memAddr))
jumpMark[par[0].upper()] = memAddr
elif cmd=="jump": # creates dummy jump code for later replacement
# we have to do it this way, beacause a jumpMark may be defined after the jump-call
return [
# will be replaced after script-compilation
"Jump_"+par[0].upper()
]
elif cmd=="getVarAddress": # stores the memory-adress of a var into another
# maybe needed, if user want to access vars with
# custom asssembly code
try:
t = varRec[par[0].upper()]
except:
print("Creating var '"+par[0].upper()+"' at memory-address "+padBin(len(varRec)+(2**8)/2))
varRec[par[0].upper()] = len(varRec)+(2**8)/2
try:
t = varRec[par[1].upper()]
except:
print("Creating var '"+par[1].upper()+"' at memory-address "+padBin(len(varRec)+(2**8)/2))
varRec[par[1].upper()] = len(varRec)+(2**8)/2
return [
## load the Var-Adress into A Register and save it into specified var
# LDI
toDec("0111"+padBin(varRec[par[0].upper()])),
# STA variable to store the current pointer in
toDec("0100"+padBin(varRec[par[1].upper()])),
]
elif cmd=="getArrayAddress": # like getVarAdress, but for arrays
# arrayName Index storeVar
try:
t = varRec["array_"+par[0].upper()+"["+par[1]+"]"]
except:
print("Undefined Array")
exit()
try:
_ = int(par[1])
except:
print("Expected array-index (integer)")
exit()
return [
## load the Var-Adress into A Register and save it into specified var
# LDI
toDec("0111"+padBin(varRec["array_"+par[0].upper()+"["+par[1]+"]"])),
# STA variable to store the current pointer in
toDec("0100"+padBin(varRec[par[2].upper()])),
]
elif cmd=="exec": # execute a user defined function
try:
t = varRec[par[0].upper()]
except:
print("Creating function-jumpback-var '"+par[0].upper()+"_JUMPBACK' at memory-address "+padBin(len(varRec)+(2**8)/2))
varRec[par[0].upper()+"_JUMPBACK"] = len(varRec)+(2**8)/2
return [
## remember current pointer, so you can jump back here after function execution is done
# LDI
toDec("0111"+padBin(pointer)),
# STA variable to store the current pointer in
toDec("0100"+padBin(varRec[par[0].upper()+"_JUMPBACK"])),
# will be replaced after script-compilation
"Exec_"+par[0].upper()# jumpback function-call-var
]
elif cmd=="setVar": # gives a var a defined value
try:
t = varRec[par[0].upper()]
except:
print("Creating var '"+par[0].upper()+"' at memory-address "+padBin(len(varRec)+(2**8)/2))
varRec[par[0].upper()] = len(varRec)+(2**8)/2
if par[1][0]=="b":
par[1] = toDec(par[1][1:])
return [
## loads desired value into the A register and then stores it at the variables memory adress
# LDI value
toDec("0111" + padBin(int(par[1]))),
# STA var Name
toDec("0100" + padBin(varRec[par[0].upper()]))
]
elif cmd=="copyVar": # gives a var the value of another var
try:
t = varRec[par[0].upper()]
except:
print("Creating var '"+par[0].upper()+"' at memory-address "+padBin(len(varRec)+(2**8)/2))
varRec[par[0].upper()] = len(varRec)+(2**8)/2
try:
t = varRec[par[1].upper()]
except:
print("Creating var '"+par[1].upper()+"' at memory-address "+padBin(len(varRec)+(2**8)/2))
varRec[par[1].upper()] = len(varRec)+(2**8)/2
return [
## load memory-space of var 1 into register A and the store it into memory-space of var 2
# LDA var 1
toDec("0001" + padBin(varRec[par[0].upper()])),
# STA var 2
toDec("0100" + padBin(varRec[par[1].upper()]))
]
elif cmd=="setArrayIndex": # defines the value of an array (par0) index (par1) to be (par2)
try:
t = varRec["array_"+par[0].upper()+"["+par[1]+"]"]
except:
print("Undefined array")
exit()
try:
_=int(par[1])
except:
print("Expected array-index (integer)")
exit()
if par[2][0]=="b":
par[2] = toDec(par[2][1:])
return [
## loads desired value into the A register and then stores it at the variables memory adress
# LDI value
toDec("0111" + padBin(int(par[2]))),
# STA var Name
toDec("0100" + padBin(varRec["array_"+par[0].upper()+"["+par[1]+"]"]))
]
elif cmd=="getArrayIndex": # puts the value of an array (par0) index (par1) into var (par2)
try:
t = varRec["array_"+par[0].upper()+"["+par[1]+"]"]
except:
print("Undefined Array")
exit()
try:
t = varRec[par[2].upper()]
except:
print("Creating var '"+par[2].upper()+"' at memory-address "+padBin(len(varRec)+(2**8)/2))
varRec[par[2].upper()] = len(varRec)+(2**8)/2
try:
_=int(par[1])
except:
print("Expected array-index (integer)")
exit()
return [
## load memory-space of var 1 into register A and the store it into memory-space of var 2
# LDA var 1
toDec("0001" + padBin(varRec["array_"+par[0].upper()+"["+par[1]+"]"])),
# STA var 2
toDec("0100" + padBin(varRec[par[2].upper()]))
]
elif cmd=="write": # writes to the console
try:
t = varRec[par[0].upper()]
except:
print("Creating var '"+par[0].upper()+"' at memory-address "+padBin(len(varRec)+(2**8)/2))
varRec[par[0].upper()] = len(varRec)+(2**8)/2
return [
## load the variable into register A, then print it
# LDA var Name
toDec("0001" + padBin(varRec[par[0].upper()])),
# OUT null
toDec("0101" + "00000000")
]
elif cmd=="read": # reads from the console
try:
t = varRec[par[0].upper()]
except:
print("Creating var '"+par[0].upper()+"' at memory-address "+padBin(len(varRec)+(2**8)/2))
varRec[par[0].upper()] = len(varRec)+(2**8)/2
return [
## input > register A; register A > var
# INP null
toDec("1011" + "00000000"),
# STA var Name
toDec("0100" + padBin(varRec[par[0].upper()]))
]
elif cmd=="add": # adds to numbers and stores the answer in another
try:
t = varRec[par[0].upper()]
except:
print("Creating var '"+par[0].upper()+"' at memory-address "+padBin(len(varRec)+(2**8)/2))
varRec[par[0].upper()] = len(varRec)+(2**8)/2
try:
t = varRec[par[1].upper()]
except:
print("Creating var '"+par[1].upper()+"' at memory-address "+padBin(len(varRec)+(2**8)/2))
varRec[par[1].upper()] = len(varRec)+(2**8)/2
try:
t = varRec[par[2].upper()]
except:
print("Creating var '"+par[2].upper()+"' at memory-address "+padBin(len(varRec)+(2**8)/2))
varRec[par[2].upper()] = len(varRec)+(2**8)/2
return [
## load var 1 into register A; add var 2, store in var 3
# LDA var Name in1
toDec("0001" + padBin(varRec[par[0].upper()])),
# ADD var Name in2
toDec("0010" + padBin(varRec[par[1].upper()])),
# STA var Name out
toDec("0100" + padBin(varRec[par[2].upper()]))
]
elif cmd=="subtract": # in1 - in2 = out
try:
t = varRec[par[0].upper()]
except:
print("Creating var '"+par[0].upper()+"' at memory-address "+padBin(len(varRec)+(2**8)/2))
varRec[par[0].upper()] = len(varRec)+(2**8)/2
try:
t = varRec[par[1].upper()]
except:
print("Creating var '"+par[1].upper()+"' at memory-address "+padBin(len(varRec)+(2**8)/2))
varRec[par[1].upper()] = len(varRec)+(2**8)/2
try:
t = varRec[par[2].upper()]
except:
print("Creating var '"+par[2].upper()+"' at memory-address "+padBin(len(varRec)+(2**8)/2))
varRec[par[2].upper()] = len(varRec)+(2**8)/2
return [
## laod var 1 into register A; subtract var 2; store in var 3
# LDA var Name in1
toDec("0001" + padBin(varRec[par[0]])),
# SUB var Name in2
toDec("0011" + padBin(varRec[par[1]])),
# STA var Name out
toDec("0100" + padBin(varRec[par[2]]))
]
elif cmd=="if": # if clause
#cmd p0 p1 p2 p3 p4:
#if VAR ?? VAR cmd pars
try:
t = varRec[par[0].upper()]
except:
print("Creating var '"+par[0].upper()+"' at memory-address "+padBin(len(varRec)+(2**8)/2))
varRec[par[0].upper()] = len(varRec)+(2**8)/2
try:
t = varRec[par[2].upper()]
except:
print("Creating var '"+par[2].upper()+"' at memory-address "+padBin(len(varRec)+(2**8)/2))
varRec[par[2].upper()] = len(varRec)+(2**8)/2
comp1=par[0].upper()
comp2=par[2].upper()
comp=par[1]
shellcode=compile(par[3],par[4:],memAddr+4)
if not shellcode:
return ["Error","I had problems getting the internal shellcode. Sorry :("]
if shellcode[0]=="Error":
return ["Error","Internal shellcode compilation thew an Error:\n"+shellcode[1]]
## binary code that magicaly works:
if comp=="==":
ret = [
# LDI konst
toDec("0111" + "10000000"),
# STA temp
toDec("0100" + "11111111"),
# LDA comp1
toDec("0001" + padBin(varRec[comp1])),
# ADD konst
toDec("0010" + "11111111"),
# SUB comp2
toDec("0011" + padBin(varRec[comp2])),
# JIE
toDec("1001" + padBin(memAddr+7)),
# JMP
toDec("0110" + padBin(memAddr+7+len(shellcode)))
]
elif comp=="!=":
ret = [
# LDI konst
toDec("0111" + "10000000"),
# STA temp
toDec("0100" + "11111111"),
# LDA comp1
toDec("0001" + padBin(varRec[comp1])),
# ADD konst
toDec("0010" + "11111111"),
# SUB comp2
toDec("0011" + padBin(varRec[comp2])),
# JIE
toDec("1001" + padBin(memAddr+6+len(shellcode)))
]
elif comp==">=":
ret = [
# LDI konst
toDec("0111" + "10000000"),
# STA temp
toDec("0100" + "11111111"),
# LDA comp1
toDec("0001" + padBin(varRec[comp1])),
# ADD konst
toDec("0010" + "11111111"),
# SUB comp2
toDec("0011" + padBin(varRec[comp2])),
# JIF
toDec("1000" + padBin(memAddr+6+len(shellcode)))
]
elif comp==">":
ret = [
# LDI konst
toDec("0111" + "01111111"),
# STA temp
toDec("0100" + "11111111"),
# LDA comp1
toDec("0001" + padBin(varRec[comp1])),
# ADD konst
toDec("0010" + "11111111"),
# SUB comp2
toDec("0011" + padBin(varRec[comp2])),
# JIF
toDec("1000" + padBin(memAddr+6+len(shellcode)))
]
elif comp=="<=":
ret = [
# LDI konst
toDec("0111" + "10000000"),
# STA temp
toDec("0100" + "11111111"),
# LDA comp2
toDec("0001" + padBin(varRec[comp2])),
# ADD konst
toDec("0010" + "11111111"),
# SUB comp1
toDec("0011" + padBin(varRec[comp1])),
# JIF
toDec("1000" + padBin(memAddr+6+len(shellcode)))
]
elif comp=="<":
ret = [
# LDI konst
toDec("0111" + "01111111"),
# STA temp
toDec("0100" + "11111111"),
# LDA comp2
toDec("0001" + padBin(varRec[comp2])),
# ADD konst
toDec("0010" + "11111111"),
# SUB comp1
toDec("0011" + padBin(varRec[comp1])),
# JIF
toDec("1000" + padBin(memAddr+6+len(shellcode)))
]
for s in shellcode:
ret.append(s)
return ret
elif cmd=="for": # for loop: "for [goal] [counter] [step] [cmd] [pars]"
# == for [counter] in range(0,[goal],[step]):
# [cmd]([pars])
try:
t = varRec[par[0].upper()]
except:
print("Creating var '"+par[0].upper()+"' at memory-address "+padBin(len(varRec)+(2**8)/2))
varRec[par[0].upper()] = len(varRec)+(2**8)/2
try:
t = varRec[par[1].upper()]
except:
print("Creating var '"+par[1].upper()+"' at memory-address "+padBin(len(varRec)+(2**8)/2))
varRec[par[1].upper()] = len(varRec)+(2**8)/2
try:
t = varRec[par[2].upper()]
except:
print("Creating var '"+par[2].upper()+"' at memory-address "+padBin(len(varRec)+(2**8)/2))
varRec[par[2].upper()] = len(varRec)+(2**8)/2
goal = par[0].upper()
clock = par[1].upper()
step = par[2].upper()
shellcode=compile(par[3],par[4:],memAddr+12)
ret = [
# LDI konst
toDec("0111" + "00000000"),
# STA temp
toDec("0100" + padBin(varRec[clock])),
# LDI konst <-- jump back to
toDec("0111" + "10000000"),
# STA temp
toDec("0100" + "11111111"),
# LDA clock
toDec("0001" + padBin(varRec[clock])),
# ADD konst
toDec("0010" + "11111111"),
# SUB goal
toDec("0011" + padBin(varRec[goal])),
# JIE
toDec("1001" + padBin(memAddr+12+len(shellcode)+1)),
# LDA clock
toDec("0001" + padBin(varRec[goal])),
# ADD step
toDec("0010" + padBin(varRec[step])),
# STA clock
toDec("0100" + padBin(varRec[goal]))
]
for s in shellcode:
ret.append(s)
# JMP
ret.append(toDec("0110" + padBin(memAddr+2)))
return ret
elif cmd=="asm" or cmd[0]==":": # compiles assembler to machine-code
if cmd=="asm":
opcode = par[0]
param = par[1]
else:
opcode = cmd[1:]
param = par[0]
if param[:2]=="b#":
param = toDec(param[2:])
elif param[:2]=="d#":
param = param[2:]
elif param[:2]=="v#":
try:
t = varRec[param[2:].upper()]
except:
print("Creating var '"+param[2:].upper()+"' at memory-address "+padBin(len(varRec)+(2**8)/2))
varRec[param[2:].upper()] = len(varRec)+(2**8)/2
param = varRec[param[2:].upper()]
elif param in ["-","none"]:
param = toDec("00000000")
elif param in ["~","all"]:
param = toDec("11111111")
else:
return ["Error","Invalid param supplied to asm-command (no valid prefix found)"]
for a in range(len(asm.asmMap)):
if asm.asmMap[a]==opcode:
print("Found matching opcode")
return [toDec(padBin(a,bit=4)+padBin(param))]
elif cmd=="shellcode": # insertes raw shellcode into the programm
return [toDec("".join(par))]
elif cmd=="push":
try:
t = varRec[par[0].upper()]
except:
print("Creating var '"+par[0].upper()+"' at memory-address "+padBin(len(varRec)+(2**8)/2))
varRec[par[0].upper()] = len(varRec)+(2**8)/2
ret = [
### value to temp
# LDA value
toDec("0001" + padBin(varRec[par[0]])),
# STA temp
toDec("0100" + padBin(varRec["temp"])),
### increment stackpointer
# LDI konst
toDec("0111" + "00000001"), # we are going to use a overflow to subtract (2's-complement)
# ADD stack_pointer
toDec("0010" + padBin(varRec["stack_pointer"])),
# STA stack_pointer
toDec("0100" + padBin(varRec["stack_pointer"])),
### A > write as new element
# STP temp
toDec("1110" + padBin(varRec["temp"]))
]
return ret
elif cmd=="pop":
try:
t = varRec[par[0].upper()]
except:
print("Creating var '"+par[0].upper()+"' at memory-address "+padBin(len(varRec)+(2**8)/2))
varRec[par[0].upper()] = len(varRec)+(2**8)/2
ret = [
### read the last element > A
# LDI stack-base
toDec("0111" + "11111111"),
# SUB stack_pointer
toDec("0011" + padBin(varRec["stack_pointer"])),
# LDP konst
toDec("1010" + "00000000"),
# STA stack_pointer
toDec("0100" + padBin(varRec[par[0]])),
### decrement stackpointer
# LDI konst
toDec("0111" + "11111111"), # we are going to use a overflow to subtract (2's-complement)
# ADD stack_pointer
toDec("0010" + padBin(varRec["stack_pointer"])),
# STA stack_pointer
toDec("0100" + padBin(varRec["stack_pointer"]))
]
return ret
elif cmd=="nop": # nothing...
return [toDec("0000" + "00000000")]
elif cmd=="halt": # halts execution of programm
return [toDec("1111" + "11111111")]
else:
return ["Error","Unimplemented Function: "+str(cmd)]
#except Exception as e:
# return ["Error","Unknown Error: "+str(e)]
bits = 12
varRec = {"temp": (2**8)/2, "stack_pointer": (2**8)/2 + 1 } # to store VarName -> memory-address
jumpMark = {} # to store jumpMarkName -> jump-address
if __name__ == "__main__":
print("[tronScript-Compiler by CyberCodeDragon]")
print("! Unstable Beta-Version with stack")
memory = []
for i in range(2**bits): #expand memory
memory.append(0)
pointer = 0
funcTable = [] # [[funcName,funcCode],...]
for f in asm.os.listdir("tronScript"): #display all found scripts
if f[-5:]==".tron":
print("> "+"tronScript/"+f)
filePath = raw_input("file to compile> ")
inFile = filePath.split("\\")
inFile = inFile[len(inFile)-1]
tmp = inFile.split(".")
ext = tmp[len(tmp)-1]
name = inFile.split("."+ext)[0]
print("[*] Reading "+inFile)
with open(filePath) as f:
code = f.read().replace(" ","") #read file and remove tabs
c = code.split("\n") #c = lines of code
#detect functions
for l in range(len(c)): #for every line of code
elems = c[l].split(" ") #elems = [cmd,pa1,par2,...,parN]
if elems[0]=="function":
funcName = elems[1]
funcCode = code.split("function "+funcName+" {")[1].split("}")[0].split("\n") #get the function Code
funcName = funcName.upper()
print("detected function '"+funcName+"' in line "+str(l)+":\n"+"\n".join(funcCode))
for i in range(len(funcCode)+0):
c[l+i]="#function-code" #replace function with a comment -> dont mess up later parsing
funcTable.append([funcName,funcCode])
try: #create jumpback-var if not existing (does probably not exist)
t = varRec[funcName+"_JUMPBACK"]
except:
print("Creating function-jumpback-var '"+funcName+"_JUMPBACK' at memory-address "+padBin(len(varRec)+(2**8)/2))
varRec[funcName+"_JUMPBACK"] = len(varRec)+(2**8)/2
#parse code
for l in range(len(c)): #for every line in code
if c[l] not in ["","\n"]: #if lines is not empty
print("Parsing line "+str(l)+": "+c[l])
cmd = c[l].split(" ")[0]
if not cmd[0]=="#": #dont parse comments
if cmd in ["halt","nop"]: #cmds without params
par = []
else:
par = c[l].split(cmd+" ")[1].split(" ")
r = compile(cmd,par,pointer) #compile
if r:
if r[0]=="Error": #print error
print("Error compiling line "+str(l)+" {"+c[l]+"}: \n"+str(r[1]))
exit()
for ret in r:
veryVerbose = False
if veryVerbose:
try:
print("Compiled to: "+padBin(ret,bit=12))
except:
print("Compiled to: "+str(ret))
memory[pointer] = ret #write code to memory
pointer+=1
try:
if padBin(memory[pointer-1],bit=12)[:4]!="1111": #if the last command is not a HLT command
print("Appending HLT-Command")
# HLT
memory[pointer] = toDec("1111"+"11111111")
print("HLT at "+padBin(pointer)+": "+padBin(memory[pointer],bit=12))
pointer+=1
except: #looks like the last command was a placeholder: not a HLT command
print("Appending HLT-Command")
# HLT
memory[pointer] = toDec("1111"+"11111111")
print("HLT at "+padBin(pointer)+": "+padBin(memory[pointer],bit=12))
pointer+=1
#replace jump-names
for m in range(len(memory)):
try:
if memory[m][:5]=="Jump_": #if at memory-adress is just a jump-dummy
print("Inserting Jump-Adress at "+padBin(m,bit=12))
memory[m]=toDec("0110"+padBin(jumpMark[memory[m][5:]])) #replace with real jump adress
except:
t=1
#append function-shellcode
funcMapper = {} #map funcName to funcCode
for f in range(len(funcTable)):
print("Appending shellcode for function "+str(funcTable[f][0])+" at adress "+padBin(pointer))
funcMapper[funcTable[f][0]] = pointer #remember where you put dat function
for l in range(len(funcTable[f][1])):
if funcTable[f][1][l] not in ["","halt","nop"]:
ret=compile(funcTable[f][1][l].split(" ")[0],funcTable[f][1][l].split(" ")[1:],pointer)
try:
if ret[0]=="Error":
print("An Error occured, when compiling function shellcode for function '"+funcTable[f][0]+"':\n"+str(e))
else:
for r in range(len(ret)):
memory[pointer]=ret[r] #append compiled function memory
pointer+=1
except:
t=1
## jump back after function execution
# LDI konst=3
memory[pointer] = toDec("0111" + "00000011")
pointer+=1
# ADD jumpBackVar
memory[pointer] = toDec("0010" + padBin(varRec[funcTable[f][0]+"_JUMPBACK"]))
pointer+=1
# JMA null
memory[pointer] = toDec("1100" + "00000000")
pointer+=1
print("FuncMapper: "+str(funcMapper))
print("Var Assignment:")
varAss = str(varRec)[1:][:-1].split(", ")
print("#VAR-NAME# #ADDRESS#")
for va in range(len(varAss)): #print all vars with their memory-location
print(varAss[va].split("'")[1]+": "+" "*(12-len(varAss[va].split("'")[1]))+padBin(int(varAss[va].split("': ")[1])))
#replace func-names
for m in range(len(memory)):
try:
if memory[m][:5]=="Exec_": #if there is just a function-call-dummy
print("Inserting Exec-Call-Adress at "+padBin(m,bit=12))
memory[m]=toDec("0110"+padBin(funcMapper[memory[m][5:]])) #replace it with a jump to the function
except Exception as e:
if str(e) != "'int' object has no attribute '__getitem__'":
print "Error while replacing func-name: "+str(e)+"\n (I don't know why, sorry)"
try:
print("Removing old "+name+".asmTron")
os.remove(name+".asmTron")
except:
t=1
print("Saving as "+name+".asmTron")
with open(name+".asmTron", 'wb') as f:
t=asm.pickle.dumps([12,memory])
t=asm.zlib.compress(t)
f.write(t)
print("Done.")