Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #tbd:
- #allow expressions with spaces
- if __name__ != "__main__": exit()
- setProgCounter0AfterSaving=True
- deletePreprocessorOutput=True
- printEvalExpressionDebug=False
- overwriteOutputFileIfBytesNotEmpty=False
- DisallowProgCounterToGoPast16Bit=False
- from sys import argv
- from os import remove as deleteFile
- from os.path import exists
- from time import time,sleep
- import subprocess
- from pprint import pprint,pformat
- def _clamp(n, mn,mx): return max(mn,min(mx,n))
- from math import floor as _floor, ceil as _ceil, sin as _sin, cos as _cos, pi as _pi
- def _l(n): return n&255 #get low byte of 16-bit number
- def _h(n): return (n>>8)&255 #get high byte of 16-bit number
- #parse and format an assembly source file
- def getSeparated(fileName):
- if not exists(fileName): return None
- file=open(fileName,"r")
- lines=file.read().split("\n")
- file.close()
- #remove comments
- lines=[line.split(";")[0] for line in lines]
- #split by assembler newline thingies (&&, usually used in macros)
- lines=sum([line.split("&&") for line in lines],[])
- #remove leading and trailing whitespace
- lines=[line.strip() for line in lines]
- #separate by commas
- lines=[line.split(",") for line in lines]
- #separate by spaces and labels
- spaceSep,spaceSepI,spaceRem=[],[],0;
- for ii in range(len(lines)):
- i=ii-spaceRem #to account for number of [""]s removed
- if lines[i] == [""]:
- del lines[i]
- spaceRem+=1
- continue
- if lines[i][0] == "":
- return None,"Line {}: Found comma or blank string at start of action".format(i+1)
- spaceSepI=[]
- for e in lines[i]:
- for s in e.strip().split(" "):
- if len(s)==0: continue #prevents 'index out of range' error
- if s[0] in [":","."] and s[-1] == ":": spaceSep.append([s])
- else: spaceSepI.append(s)
- if spaceSepI != []: spaceSep.append(spaceSepI)
- #lines=spaceSep
- #return lines,""
- if spaceSep == []: return None,"Parsing file results in empty list"
- return spaceSep,""
- def reverseSortDict(d):
- new_d={}
- for k in sorted(d,key=len,reverse=True): new_d[k]=d[k]
- return new_d
- def adjustAddress(pc):
- if pc <= 0xffff: return pc
- else: return (32768 + pc%32768)
- outputFileName="out.bin"
- progCounter=0x0000
- outputBytes=[progCounter]
- charset=[i for i in range(256)] #x->y encoding conversion; just have 1:1 mapping initially
- #(labels are limited to locations dependant on its position in code)
- labels={"nil":[0,{}]}
- currentLabel="nil" #current label for which local labels are assigned and compared
- localLabels={}
- #tbd: do charset stuff here possibly
- def evalExpression(exp,pc,relativeMode=False):
- try:
- #replace @ with current value of program counter
- evalNum=exp.replace("@",str(adjustAddress(pc)))
- #check for char literal if there's no " on either end of the expression,
- #so you can use ' in strings without getting a mismatch error
- if exp[0] != '"' and exp[-1] != '"':
- #replace char literals (like 'a')
- charLiteralTemp=""; evalNumMax=len(evalNum)-1; ci=0
- while ci<len(evalNum):
- c=evalNum[ci]
- if c == "'":
- ci+=2 #will be +3 in total this iteration
- if ci>evalNumMax or evalNum[ci] != "'":
- return None,"Mismatched char literal in expression"
- charLiteralTemp+=str(ord(evalNum[ci-1]))
- else: charLiteralTemp+=c
- ci+=1
- evalNum=charLiteralTemp
- #replace local labels with their values
- for lLabelNameR in localLabels: #first check if the local label exists at all
- lLabelName="."+lLabelNameR.split(".")[-1] #"label.local" to just ".local"
- if lLabelName in exp:
- if not lLabelName in labels[currentLabel][1]:
- return None,"local label \"{}{}\" doesn't exist".format(currentLabel,lLabelName)
- evalNum=evalNum.replace(lLabelName,str(labels[currentLabel][1][lLabelName]))
- #replace labels with their values
- for labelName in labels:
- label=labels[labelName]
- if labelName in exp: evalNum=evalNum.replace(labelName,str(label[0]))
- #do the actual eval
- evalNum=eval(evalNum)
- if type(evalNum) == bool: evalNum=int(evalNum)
- if relativeMode: evalNum-=pc #for bnz
- if printEvalExpressionDebug: print("@="+hex(pc)+': "'+exp+'" = '+str(evalNum))
- return evalNum,"No Error"
- except SyntaxError as syntaxErr:
- #hopefully this only triggers when eval() fails...
- return None,"Failed expression eval for \"{}\" ({})".format(syntaxErr.text,syntaxErr.msg)
- except Exception as uniErr:
- return None,uniErr
- #toNbitAll() does both signed and unsigned N-bit ints
- def to8bitAll(n0):
- try: n=_floor(n0+.5) #round to nearest whole
- except TypeError: return None,"to8bitAll can't accept \"{}\", which is of type \"{}\"".format(n0,type(n0))
- except Exception as err: return None,"to8bitAll error: "+err
- if n< -128: return None,"Can't convert number \"{}\" below -128 to 8 bits".format(n)
- if n> 255: return None,"Can't convert number \"{}\" above 255 to 8 bits".format(n)
- if n<0: n+=256 #two's complement representation
- return n.to_bytes(1,"little"),""
- def to16bitAll(n0):
- try: n=_floor(n0+.5) #round to nearest whole
- except TypeError: return None,"to16bitAll can't accept \"{}\", which is of type \"{}\"".format(n0,type(n0))
- except Exception as err: return None,"to16bitAll error: "+err
- if n< -32768: return None,"Can't convert number \"{}\" below -32768 to 16 bits".format(n)
- if n> 65535: return None,"Can't convert number \"{}\" above 65535 to 16 bits".format(n)
- if n<0: n+=65536 #two's complement representation
- return n.to_bytes(2,"little"),""
- def to24bitAll(n0):
- try: n=_floor(n0+.5) #round to nearest whole
- except TypeError: return None,"to24bitAll can't accept \"{}\", which is of type \"{}\"".format(n0,type(n0))
- except Exception as err: return None,"to24bitAll error: "+err
- if n< -8388608: return None,"Can't convert number \"{}\" below -8388608 to 24 bits".format(n)
- if n> 16777215: return None,"Can't convert number \"{}\" above 16777215 to 24 bits".format(n)
- if n<0: n+=16777216 #two's complement representation
- return n.to_bytes(3,"little"),""
- def to32bitAll(n0):
- try: n=_floor(n0+.5) #round to nearest whole
- except TypeError: return None,"to32bitAll can't accept \"{}\", which is of type \"{}\"".format(n0,type(n0))
- except Exception as err: return None,"to32bitAll error: "+err
- if n< -2147483648: return None,"Can't convert number \"{}\" below -2147483648 to 32 bits".format(n)
- if n> 4294967295: return None,"Can't convert number \"{}\" above 4294967295 to 32 bits".format(n)
- if n<0: n+=4294967296 #two's complement representation
- return n.to_bytes(4,"little"),""
- EWAC="Error while assembling chunk \"{}\": "
- def directive_str(s,numBytes):
- evalNumBytes=[]
- for c in s:
- o=charset[ord(c)]
- if numBytes == 1: evalNum,err= to8bitAll(o)
- elif numBytes == 2: evalNum,err=to16bitAll(o)
- elif numBytes == 3: evalNum,err=to24bitAll(o)
- elif numBytes == 4: evalNum,err=to32bitAll(o)
- if evalNum == None: return None,err
- evalNumBytes.append(evalNum)
- return evalNumBytes,""
- def directive_ui(line,numBytes,updateGlobals=True):
- global outputBytes
- global progCounter
- evalNumBytes=[]
- for e in line[1:]:
- evalNum,err=evalExpression(e,progCounter)
- if evalNum == None:
- print((EWAC+"{}").format(line,err))
- return False
- if type(evalNum) == str:
- stringBytes,err=directive_str(evalNum,numBytes)
- if stringBytes == None:
- print((EWAC+"{}").format(line,err))
- return False
- evalNumBytes+=stringBytes
- continue
- elif numBytes == 1: evalNum,err= to8bitAll(evalNum)
- elif numBytes == 2: evalNum,err=to16bitAll(evalNum)
- elif numBytes == 3: evalNum,err=to24bitAll(evalNum)
- elif numBytes == 4: evalNum,err=to32bitAll(evalNum)
- if evalNum == None:
- print((EWAC+"{}").format(line,err))
- return False
- evalNumBytes.append(evalNum)
- if updateGlobals:
- outputBytes.append(b''.join(evalNumBytes))
- progCounter+=len(outputBytes[-1]) #len of evalNumBytes
- return True
- else: return evalNumBytes
- def directive_u_(line,numBytes,updateGlobals=True):
- global outputBytes
- global progCounter
- evalNumBytes=[]
- for e in line[1:]:
- evalNum,err=evalExpression(e,progCounter)
- if evalNum == None:
- print((EWAC+"{}").format(line,err))
- return False
- if type(evalNum) == str:
- stringBytes,err=directive_str(evalNum,numBytes)
- if stringBytes == None:
- print((EWAC+"{}").format(line,err))
- return False
- evalNumBytes+=stringBytes
- continue
- elif evalNum < 0:
- print((EWAC+"Can't convert \"{}\" to unsigned {}-bit number").format(line,e,numBytes*8))
- return False
- elif numBytes == 1: evalNum,err= to8bitAll(evalNum)
- elif numBytes == 2: evalNum,err=to16bitAll(evalNum)
- elif numBytes == 3: evalNum,err=to24bitAll(evalNum)
- elif numBytes == 4: evalNum,err=to32bitAll(evalNum)
- if evalNum == None:
- print((EWAC+"{}").format(line,err))
- return False
- evalNumBytes.append(evalNum)
- if updateGlobals:
- outputBytes.append(b''.join(evalNumBytes))
- progCounter+=len(outputBytes[-1]) #len of evalNumBytes
- return True
- else: return evalNumBytes
- def directive_i_(line,numBytes,updateGlobals=True):
- global outputBytes
- global progCounter
- evalNumBytes=[]
- for e in line[1:]:
- evalNum,err=evalExpression(e,progCounter)
- if evalNum == None:
- print((EWAC+"{}").format(line,err))
- return False
- if type(evalNum) == str:
- stringBytes,err=directive_str(evalNum,numBytes)
- if stringBytes == None:
- print((EWAC+"{}").format(line,err))
- return False
- evalNumBytes+=stringBytes
- continue
- elif evalNum > ((256**numBytes)-1):
- print((EWAC+"Can't convert \"{}\" to signed {}-bit number").format(line,e,numBytes*8))
- return False
- elif numBytes == 1: evalNum,err= to8bitAll(evalNum)
- elif numBytes == 2: evalNum,err=to16bitAll(evalNum)
- elif numBytes == 3: evalNum,err=to24bitAll(evalNum)
- elif numBytes == 4: evalNum,err=to32bitAll(evalNum)
- if evalNum == None:
- print((EWAC+"{}").format(line,err))
- return False
- evalNumBytes.append(evalNum)
- if updateGlobals:
- outputBytes.append(b''.join(evalNumBytes))
- progCounter+=len(outputBytes[-1]) #len of evalNumBytes
- return True
- else: return evalNumBytes
- def directive_fill(line):
- global progCounter
- global outputBytes
- if len(line) < 2 or len(line) > 3:
- print((EWAC+"Directive \"!fill\" requires 1-2 args, not {}").format(line,len(line)-1)); return False
- fillCount,err=evalExpression(line[1],progCounter)
- if fillCount == False: print((EWAC+"{}").format(line,err)); return False
- fillValue=0
- if len(line) == 3: fillValue,err=evalExpression(line[2],progCounter)
- if fillValue == None: print((EWAC+"{}").format(line,err)); return False
- if fillValue != _clamp(fillValue, 0,255): print((EWAC+"!fill value \"{}\" out of bounds (must be 0->255)").format(line,fillValue)); return False
- progCounter+=fillCount; outputBytes.append([fillValue.to_bytes(1,"little"),]*fillCount)
- return True
- def directive_align(line):
- global progCounter
- global outputBytes
- if len(line) < 2 or len(line) > 3:
- print((EWAC+"Directive \"!align\" requires 1-2 args, not {}").format(line,len(line)-1)); return False
- alignA,err=evalExpression(line[1],progCounter)
- if alignA == None: print((EWAC+"{}").format(line,err)); return False
- alignN=0
- if len(line) == 3: alignN,err=evalExpression(line[2],progCounter)
- if alignN != _clamp(alignN, 0,255): print((EWAC+"!align value \"{}\" out of bounds (must be 0->255)").format(line,alignN)); return False
- alignC=alignA-progCounter%alignA
- progCounter+=alignC; outputBytes.append([alignN.to_bytes(1,"little"),]*alignC)
- return True
- def directive_AT_EQ(line):
- global progCounter
- if len(line) != 2:
- print((EWAC+"Directive \"{}\" requires 1 arg, not {}").format(line,line[0],len(line)-1))
- return False
- progCounter,err=evalExpression(line[1],progCounter)
- if progCounter == None:
- print((EWAC+"{}").format(line,err))
- return False
- if progCounter < 0:
- print((EWAC+"{} value \"{}\" can't be < 0").format(line,line[0],progCounter))
- return False
- elif DisallowProgCounterToGoPast16Bit and progCounter > 0xffff:
- print((EWAC+"{} value \"{}\" can't be > 0xffff (65535)").format(line,line[0],progCounter))
- return False
- outputBytes.append(progCounter)
- return True
- def directive_tofile(line):
- global outputFileName
- try: #check if file name is valid
- if len(line) != 2:
- print((EWAC+"{} requires 1 arg, not {}").format(line,line[0],len(line)-1))
- return False
- outputFileName=line[1]
- if outputFileName[0] == '"' and outputFileName[-1] == '"':
- outputFileName=outputFileName[1:-1]
- existedPreviously=exists(outputFileName)
- outputFile=open(outputFileName,"a")
- outputFile.close()
- if not existedPreviously:
- deleteFile(outputFileName)
- except Exception as err:
- print((EWAC+"{}").format(line,err)); return False
- return True
- def directive_save(line):
- #fileName,byteList
- global outputFileName
- global outputBytes
- global progCounter
- try:
- if len(line) > 2:
- print((EWAC+"{} requires 0-1 args, not {}").format(line,line[0],len(line)-1))
- return False
- errorOnOverwrite=False
- if len(line) == 2: errorOnOverwrite=eval(line[1])
- if errorOnOverwrite and exists(outputFileName):
- print((EWAC+"File \"{}\" already exists").format(line,outputFileName))
- return False
- if len(outputBytes) == 0:
- print((EWAC+"Length of output bytes is 0").format(line))
- return False
- outputFile=open(outputFileName,"wb")
- for chunk in outputBytes:
- chunkType=type(chunk)
- if chunkType == int: outputFile.seek(chunk,0)
- elif chunkType == bytes: outputFile.write(chunk)
- elif chunkType == list: outputFile.write(b''.join(chunk))
- outputFile.close()
- outputBytes=[]
- if setProgCounter0AfterSaving: progCounter=0
- return True
- except Exception as err:
- print((EWAC+"{}").format(line,err)); return False
- #def directive_flush():
- def directive_binary(line):
- global progCounter
- global outputBytes
- if len(line) < 2 or len(line) > 3:
- print((EWAC+"{} requires 1-2 args, not {}").format(line,line[0],len(line)-1))
- return False
- fileName=line[1]
- if fileName[0] == '"' and fileName[-1] == '"': fileName=fileName[1:-1]
- seekBytes=0
- try:
- if len(line) == 3: seekBytes=evalExpression(line[2],progCounter)
- if type(seekBytes) != int:
- print((EWAC+"eval of \"{}\" should be of type <class 'int'>, not {}").format(line,seekBytes,type(seekBytes)))
- return False
- except Exception as err:
- print((EWAC+"{}").format(line,err))
- if not exists(fileName):
- print((EWAC+"Binary file \"{}\" doesn't exist").format(line,fileName))
- return False
- file=open(fileName,"rb")
- file.seek(seekBytes,0)
- fileBytes=file.read()
- file.close()
- if len(fileBytes) == 0:
- print((EWAC+"Binary file \"{}\"'s byte length is 0 after seeking").format(line,fileName))
- outputBytes.append(fileBytes)
- progCounter+=len(fileBytes)
- return True
- def directive_chrset(line):
- global charset
- if len(line) != 2:
- print((EWAC+"{} requires 1 arg, not {}").format(line,line[0],len(line)-1))
- return False
- fileName=line[1]; fileBytes=None
- if not exists(fileName):
- print((EWAC+"Charset encoding file \"{}\" doesn't exist").format(line,fileName))
- return False
- try:
- file=open(fileName,"rb")
- fileBytes=file.read()
- file.close()
- except Exception as err:
- print((EWAC+"{}").format(line,err))
- return False
- if len(fileBytes) != 256:
- print((EWAC+"Length of charset encoding file should be 256, not {}").format(line,fileName,len(fileBytes)))
- return False
- charset=[n for n in fileBytes]
- return True
- def directive_savlbl(line):
- global progCounter
- global labels
- global localLabels
- if len(line) < 2 or len(line) > 3:
- print((EWAC+"{} requires 1-2 args, not {}").format(line,line[0],len(line)-1))
- return False
- fileName=line[1]
- if fileName[0] == '"' and fileName[-1] == '"': fileName=fileName[1:-1]
- errorOnOverwrite=False
- try:
- if len(line) == 3: errorOnOverwrite=evalExpression(line[2],progCounter)
- if type(errorOnOverwrite) != bool:
- print((EWAC+"eval of \"{}\" should be of type <class 'bool'>, not {}").format(line,errorOnOverwrite,type(errorOnOverwrite)))
- return False
- if errorOnOverwrite and exists(fileName):
- print((EWAC+"File \"{}\" already exists").format(line,fileName))
- return False
- file=open(fileName,"w")
- file.write("labels="+pformat(labels))
- file.close()
- except Exception as err:
- print((EWAC+"{}").format(line,err))
- return True
- directives={
- "!8" :True,
- "!16" :True,
- "!24" :True,
- "!32" :True,
- "!u8" :True,
- "!u16" :True,
- "!u24" :True,
- "!u32" :True,
- "!i8" :True,
- "!i16" :True,
- "!i24" :True,
- "!i32" :True,
- "!fill" :True,
- "!align" :True,
- "!@=" :True, "!pc=":True,
- "!tofile":True, "!to":True,
- "!save" :True, "!savefile":True,
- "!flush" :True, "!flushbytes":True,
- "!binary":True, "!bin":True,
- "!chrset":True, "!encoding":True,
- "!savlbl":True, "!savelabels":True
- }
- parameters={
- "i":"00",
- "l":"01",
- "h":"10",
- "c":"11", "s":"11", "a":"11"
- }
- descriptors={ "^":"00", "#":"01", "@":"10", "*":"11" }
- instructions={
- #MMM: OOOO,MN,MX, P, D, E, ^, #, @, *,
- "hcf":("0000",1,1, False,False,False, False,False,False,False), #
- "jpa":("0000",2,2, False,False, True, False,False, True,False),
- "jpr":("0000",1,1, False,False,False, True,False,False,False),
- "bnz":("0000",2,2, False,False, True, False,False,False,False),
- "ina":("0001",2,2, True,False,False, False,False,False,False), #
- "tar":("0010",2,2, True,False,False, False,False,False,False), #
- "tra":("0011",2,2, True,False,False, False,False,False,False),
- "ldr":("0100",3,4, True, True, True, True, True, True, True),
- "str":("0101",3,4, True, True, True, True,False, True, True),
- #"ina":("0001",2,2, True,False,False, False,False,False,False), #
- "adc":("0110",2,3, False, True, True, True, True, True, True),
- "sbc":("0111",2,3, False, True, True, True, True, True, True),
- "add":("1000",2,3, False, True, True, True, True, True, True),
- "ror":("1001",2,3, False, True, True, True, True, True, True), #
- "and":("1010",2,3, False, True, True, True, True, True, True),
- "ora":("1011",2,3, False, True, True, True, True, True, True),
- "xor":("1100",2,3, False, True, True, True, True, True, True),
- #"bnz":("0000",2,2, False,False, True, False,False,False,False), #
- "cmp":("1101",2,3, False, True, True, True, True, True, True),
- "smb":("1110",2,3, False, True, True, True, True, True, True),
- "sys":("1111",2,3, False, True, True, True, True, True, True),
- }
- def stitchInstruction(line): #base 2 instruction,byte count,error
- mnemonic=line[0].lower()
- parameter,descriptor,expression=None,None,None
- instruction=instructions.get(mnemonic)
- if not instruction:
- return None,None,"Malformed or nonexistent mnemonic \""+mnemonic+"\""
- opcode=instruction[0]
- lineArgc=len(line); byteMin,byteMax=instruction[1:3]
- if _clamp(lineArgc, byteMin,byteMax) != lineArgc:
- print((EWAC+"Invalid number of line arguments for instruction \"{}\"\
- (should be between {} and {}, not {})").format(line, mnemonic, byteMin,byteMax, lineArgc))
- return None,None
- uP,uD,uE=instruction[3:6] #use P,D,E
- argIndex, byteCount,expression=1, 1,0
- #parameter handling
- if uP:
- parameter=line[argIndex].lower()
- if not parameters.get(parameter):
- print((EWAC+"Invalid parameter \"{}\"").format(line,line[argIndex]))
- return None,None
- opcode=parameters[parameter]+opcode
- argIndex+=1
- elif mnemonic == "jpa": opcode="01"+opcode
- elif mnemonic == "jpr": opcode="10"+opcode
- elif mnemonic == "bnz": opcode="11"+opcode
- else: opcode="00"+opcode
- #address mode descriptor handling
- if uD:
- descriptor=line[argIndex].lower()
- if not descriptors.get(descriptor):
- print((EWAC+"Invalid address mode desriptor \"{}\"").format(line,line[argIndex]))
- return None,None
- opcode=descriptors[descriptor]+opcode
- byteCount+=min(2, int(descriptors[descriptor],2) )
- argIndex+=1
- elif mnemonic == "bnz":
- opcode="00"+opcode
- byteCount+=1 #should =2 now
- else: opcode="00"+opcode
- #expression handling
- expressionBytes=b''
- if mnemonic == "jpa":
- if lineArgc != 2:
- print((EWAC+"Instruction \"{}\" requires an expression").format(line,line[0]))
- return None,None
- expression,err=evalExpression(line[argIndex],progCounter)
- if expression == None: print((EWAC+"{}").format(line,err)); return None,None
- elif type(expression) == str:
- print((EWAC+"Instructions can't use strings for expressions").format(line))
- return None,None
- elif expression < 0:
- print((EWAC+"Can't convert \"{}\" to unsigned 16-bit number").format(line,line[1]))
- return None,None
- else: expressionBytes,err=to16bitAll(expression)
- if expressionBytes == None: print((EWAC+"{}").format(line,err)); return None,None
- elif mnemonic == "bnz":
- if lineArgc != 2:
- print((EWAC+"Instruction \"{}\" requires an expression").format(line,line[0]))
- return None,None
- #tbd: put +2 of progCounter inside evalExpression if problems occur
- expression,err=evalExpression(line[argIndex],progCounter+2,relativeMode=True)
- if expression == None: print((EWAC+"{}").format(line,err)); return None,None
- elif type(expression) == str:
- print((EWAC+"Instructions can't use strings for expressions").format(line))
- return None,None
- elif expression > 127:
- print((EWAC+"Can't convert \"{}\" so signed 8-bit number").format(line,line[1]))
- return None,None
- else: expressionBytes,err=to8bitAll(expression)
- if expressionBytes == None: print((EWAC+"{}").format(line,err)); return None,None
- elif byteCount>1 and lineArgc<(1+uP+uD+uE):
- #is there no expression where there should be?
- print((EWAC+"Address mode \"{}\" requires an expression argument").format(line,descriptor))
- return None,None
- elif uE and byteCount>1:
- #for everything except jpa or bnz
- expression,err=evalExpression(line[argIndex],progCounter)
- if expression == None: print((EWAC+"{}").format(line,err)); return None,None
- elif type(expression) == str:
- print((EWAC+"Instructions can't use strings for expressions").format(line))
- return None,None
- elif byteCount == 2: expressionBytes,err=to8bitAll(expression)
- elif byteCount == 3: expressionBytes,err=to16bitAll(expression)
- else: print((EWAC+"This error shouldn't occur!").format(line)); return None,None
- if expressionBytes == None: print((EWAC+"{}").format(line,err)); return None,None
- elif byteCount==1 and lineArgc>(1+uP+uD):
- #is there an expression where there shouldn't be?
- print((EWAC+"Address mode \"{}\" does not take an expression argument").format(line,descriptor))
- return None,None
- #print(mnemonic, opcode,expression, int(opcode,2).to_bytes(1,"little"),expressionBytes)
- return [int(opcode,2).to_bytes(1,"little")+expressionBytes],byteCount
- timeStart=time()
- if len(argv) < 2: exit()
- #black box preprocessor magic
- proc=subprocess.Popen(["cpp","-x","assembler-with-cpp","-nostdinc","-CC","-undef","-P"]+argv[1:]+["_PreProcOutput",],
- stdout=subprocess.PIPE, shell=True)
- while proc.poll() == None: sleep(0.02)
- pExitCode=proc.poll()
- pOutput,pError = proc.communicate()
- if len(pOutput) != 0: print(pOutput.decode("utf-8"))
- if pExitCode != 0: exit()
- #parse output of preprocessor
- lines,err=getSeparated("_PreProcOutput")
- if lines == None: print("Error while parsing: "+err); exit()
- #(yes, it is basically assembling twice,
- #so labels are all defined before instruction handling begins)
- #assemble line by line
- for assembler_pass in range(2):
- for line in lines:
- lineCompleted=False
- identifier=line[0][0]
- if identifier == '!': #assembler directive
- directiveName=line[0]
- if not directives.get(directiveName):
- print((EWAC+"Directive \"{}\" doesn't exist").format(line,line[0])); break
- if directiveName == "!8":
- if not directive_ui(line,1): break
- elif directiveName == "!16":
- if not directive_ui(line,2): break
- elif directiveName == "!24":
- if not directive_ui(line,3): break
- elif directiveName == "!32":
- if not directive_ui(line,4): break
- elif directiveName == "!u8":
- if not directive_u_(line,1): break
- elif directiveName == "!u16":
- if not directive_u_(line,2): break
- elif directiveName == "!u24":
- if not directive_u_(line,3): break
- elif directiveName == "!u32":
- if not directive_u_(line,4): break
- elif directiveName == "!i8":
- if not directive_i_(line,1): break
- elif directiveName == "!i16":
- if not directive_i_(line,2): break
- elif directiveName == "!i24":
- if not directive_i_(line,3): break
- elif directiveName == "!i32":
- if not directive_i_(line,4): break
- elif directiveName == "!fill":
- if not directive_fill(line): break
- elif directiveName == "!align":
- if not directive_align(line): break
- elif directiveName in ["!@=","!pc=","!PC="]:
- if not directive_AT_EQ(line): break
- elif directiveName in ["!tofile","!to"]:
- if not directive_tofile(line): break
- elif directiveName in ["!save","!savefile"] and assembler_pass==1: #2nd pass only
- if not directive_save(line): break
- elif directiveName in ["!flush","!flushbytes"]:
- outputBytes=[] #tbd: might need to put more stuff here at some point
- elif directiveName in ["!binary","!bin"]:
- if not directive_binary(line): break
- elif directiveName in ["!chrset","!encoding"]:
- if not directive_chrset(line): break
- elif directiveName in ["!savlbl","!savelabels"] and assembler_pass==1: #2nd pass only
- if not directive_savlbl(line): break
- elif identifier == ':': #define label
- if assembler_pass == 0: #1st pass only
- newLabel=line[0][1:-1]
- if line[0][-1] != ":":
- print((EWAC+"Label definition missing a ':' as its last char").format(line)); break
- if labels.get(newLabel):
- print((EWAC+"Label \"{}\" is already defined").format(line,newLabel)); break
- labels[newLabel]=[progCounter,{}]
- currentLabel=newLabel
- labels=reverseSortDict(labels)
- elif identifier == '.': #define local label
- if assembler_pass == 0: #1st pass only
- if line[0][-1] != ":":
- print((EWAC+"Local label definition missing a ':' as its last char").format(line)); break
- newLocal=line[0][:-1]
- if newLocal in labels[currentLabel][1]:
- print((EWAC+"Label \"{}{}\" is already defined").format(line,currentLabel,line[0])); break
- localLabels[currentLabel+newLocal]=progCounter #["label.local"] = progCounter
- labels[currentLabel][1][newLocal]=progCounter
- localLabels=reverseSortDict(localLabels)
- elif assembler_pass == 1: #instruction handling done on 2nd pass
- instruction,byteCount=stitchInstruction(line)
- if instruction == None: break
- outputBytes+=instruction
- progCounter+=byteCount
- if DisallowProgCounterToGoPast16Bit and progCounter > 0xffff:
- print((EWAC+"Program counter = {} ({}), which is past 0xffff").format(line,hex(progCounter),progCounter))
- break
- lineCompleted=True
- if assembler_pass == 0: outputBytes=[0x0000]
- if not lineCompleted: break;
- if len(outputBytes) > 0:
- if overwriteOutputFileIfBytesNotEmpty or not exists(outputFileName):
- directive_save([])
- elif exists(outputFileName):
- pprint(outputBytes,width=40)
- print("(Warning: output bytes is not empty post-assembly; the above data will be lost)")
- else: directive_save([])
- if deletePreprocessorOutput: deleteFile("_PreProcOutput")
- print("Finished assembling in {}ms".format( int((time()-timeStart)*1000) ))
Add Comment
Please, Sign In to add comment