def parse(path): f = open(path) lines = f.readlines() lines = lmap(lambda x: x.strip().split(), lines) lines = lmap(lambda x: removeComment(x), lines) lines = lmap(lambda x: makeValid(x), lines) return lines
def validate(code): #get non-halt instructions notHalt = lfilter(lambda x: x[0] != "halt", code) registersUsed = list(set(lmap(lambda x: x[1], notHalt))) numRegisters = max(registersUsed) + 1 if min(registersUsed) < 0: error("Register numbers must be non-negative.") totalLines = len(code) linesReferenced = sum(lmap(lambda x: x[2:], code),()) if min(linesReferenced) <= 0 or max(linesReferenced) > totalLines: error("All line numbers must refer to existing lines of code.") return [0] * numRegisters
def tableFormat(cLabels, iData, comment): columnLabels = copy(cLabels) intData = copy(iData) #whoops, aliasing if len(columnLabels) != len(intData): #this shouldn't actually happen, just a sanity check error("Number of column labels does not match amount of data given.") for i in range(len(columnLabels)): if columnLabels[i][0] == "!": columnLabels[i] = columnLabels[i][1:] #remove bang intData[i] = displayAsSeq(intData[i]) data = lmap(lambda x: str(x), intData) numItems = len(data) columnWidth = [] for i in range(numItems): columnWidth.append(max(len(columnLabels[i]), len(data[i])) + 2) columnFormatted = [] dataFormatted = [] for i in range(numItems): target = columnWidth[i] col = columnLabels[i] dat = data[i] columnFormatted.append(" " + col + " " * (target - len(col) - 1)) dataFormatted.append(" " + dat + " " * (target - len(dat) - 1)) singleMid = "" doubleTop = "" doubleBot = "" for width in columnWidth: singleMid += chr(9472) * width doubleTop += "═" * width doubleBot += "═" * width singleMid += "┼" doubleTop += "╤" doubleBot += "╧" singleMid = singleMid[:-1] #last character doubleTop = doubleTop[:-1] doubleBot = doubleBot[:-1] topLine = "╔" + doubleTop + "╗" columns = "║" + "│".join(columnFormatted) + "║" midLine = "╟" + singleMid + "╢ " + comment.strip() data = "║" + "│".join(dataFormatted) + "║" bottomLine = "╚" + doubleBot + "╝" return "\n".join([topLine, columns, midLine, data, bottomLine])
def run(): fileName = input(".rmm file path to compile: ") if fileName.split(".")[-1] != "rmm": error("File must be a .rmm (register machine macro) file.") f = open(fileName) lines = f.readlines() lines = lmap(lambda x: x.strip(), lines) #remove newline lines = lfilter(lambda x: x != "", lines) #remove empty lines hasMacros = False if "MACROS" in lines: hasMacros = True if not hasMacros: pass #defer to the original interpreter #TODO: is this dead code? if "MACROS" not in lines: error("\"MACROS\" divider must be in code before macros.") macroDiv = lines.index("MACROS") #line that divides code from macro definitions rmCode = lines[:macroDiv] rmmCode = lines[macroDiv+1:] rmmCode = lmap(lambda x: x.split(" "), rmmCode) #split into tokens #isolate code snippets for converting into macros macros = [] #list of code snippets progress = [] for line in rmmCode: if line[0] == "macro": if progress != []: macros.append(progress) #read until the next "macro" token, then add to list progress = [line] else: progress.append(line) macros.append(progress) #add all the macros to a dictionary for easy lookup macroDict = {} for m in macros: mac = Macro(m) #convert to macro object macroDict[mac.name] = mac #with all macros found, go back and convert line references to labels for m in macroDict: thisMacro = macroDict[m] for i in range(len(thisMacro.code)): line = thisMacro.code[i] labelLine = [[i+1]] instruction = line[0] nR = getRegArgNum(macroDict, instruction) for i in range(len(line)): if i <= nR: #either the instruction or one of the register args labelLine.append(line[i]) #just copy it over else: #a line arg try: labelLine.append([int(line[i])]) #attempt to convert to int and make a label except: labelLine.append(line[i]) #otherwise just copy thisMacro.labCode.append(labelLine) #add line to labeled code #add line labels and convert line refs to labels in the code being compiled rmCode = lmap(lambda x: x.split(),rmCode) for i in range(len(rmCode)): line = rmCode[i] instr = line[0] nR = getRegArgNum(macroDict, instr) nL = getLineArgNum(macroDict, instr) for j in range(len(line)): if j > nR: #line arg try: line[j] = [int(line[j])] except: pass extLabel = [i+1] rmCode[i] = [extLabel] + line[:nR + nL + 1] #expand code by substituting for macros expanded = False while(not expanded): expanded = True for i in range(len(rmCode)): line = rmCode[i] label = line[0] instr = line[1] if instr not in ["inc", "dec", "halt"]: nR = getRegArgNum(macroDict, instr) expanded = False regSub = line[2:2+nR] lineSub = line[2+nR:] mac = macroDict[instr] sub = mac.substitute(macroDict, regSub, lineSub, label) rmCode = rmCode[:i] + sub + rmCode[i+1:] break ########## DEBUG #for line in rmCode: # print(line) #print() #input() ########## maxDepth = max(lmap(lambda x: len(x[0]), rmCode)) #max depth of any label for i in range(len(rmCode)): line = rmCode[i] for j in range(len(line)): if type(line[j]) == list: line[j] += [1] * (maxDepth - len(line[j])) #pad with 1s to max depth #add labels to dictionary labelDict = {} for i in range(len(rmCode)): line = rmCode[i] label = line[0] lineNo = i+1 labelDict[tuple(label)] = lineNo #replace labels with line numbers for i in range(len(rmCode)): line = rmCode[i] for j in range(len(line)): if type(line[j]) == list: line[j] = labelDict[tuple(line[j])] rmCode = lmap(lambda x: x[1:], rmCode) #remove line numbers #create temp register dictionary tempDict = {} registersUsed = [] for line in rmCode: if len(line) > 1: #if not halt reg = line[1] try: #not a temp register line[1] = int(reg) registersUsed.append(int(reg)) except: pass unused = [] usedSet = set(registersUsed) highestUsed = max(registersUsed) internalUnused = set(range(highestUsed + 1)).difference(usedSet) #register numbers that got skipped unused += list(internalUnused) tempsLeft = len(allTemps) - len(unused) unused += list(range(highestUsed+1, highestUsed+1+tempsLeft)) #add additional registers as needed for line in rmCode: print(line) print() #naive replacement for i in range(len(allTemps)): tempDict[allTemps[i]] = unused[i] for line in rmCode: if len(line) > 1: reg = line[1] if type(reg) == str: #temp register that needs to be replaced line[1] = tempDict[reg] f = open(fileName.split(".")[0] + ".rm", "w+") for line in rmCode: line = lmap(lambda x: str(x), line) f.write(" ".join(line) + "\n") #debug for line in rmCode: print(line) print("\n") for m in macroDict: print(str(macroDict[m]) + "\n") print("\n")
def run(path=None, regInput=None): #arguments passed through to naive interpreter setup (code, registers) = setup(path, regInput) diagram = Diagram(code) current = diagram.entry trace = [] #list for keeping track of instructions since last loop # (Instruction object, identifier, target) # I: increment # D: decrement # Z: zero check (register was unable to be decremented) #TODO style = False annPath = '' while True: if current in lmap(lambda x: x[0], trace): print("Loop caught!") instrTrace = lmap(lambda x: x[0], trace) loop = trace[instrTrace.index( current):] #from current instruction forward #print("Loop: %s"%(str(loop))) trace = [] #clear trace list decd = [] #indices of decremented registers for t in loop: if t[1] == "D" or t[1] == "Z": if t[2] not in decd: decd.append(t[2]) #add decremented register to list autoIters = float("inf") #number of safe iterations we can do for i in decd: #for each decremented register thisReg = lfilter(lambda x: x[2] == i, loop) seq = lmap( lambda x: x[1], thisReg) #sequence of things happening to this register #print("%i: %s"%(i,seq)) if "Z" in seq: running = registers[i] for c in seq: if c == "I": running += 1 elif c == "D": if running == 0: autoIters = 0 #already broke behavior else: running -= 1 else: if running != 0: autoIters = 0 else: lowest = 0 running = 0 for c in seq: if c == "I": running += 1 else: running -= 1 lowest = min(lowest, running) safe = lowest * -1 #smallest value of the register without it getting decremented while 0 #running is the net change from the loop if running < 0: safeIters = (registers[i] - safe) // (running * -1) autoIters = min(autoIters, safeIters) if autoIters == 0: #whoops, no point break if autoIters == float("inf"): error("Infinite loop detected") if autoIters > 0: net = [0] * len(registers) #net change to each register for t in loop: tgt = t[2] if t[1] == "I": net[tgt] += 1 elif t[1] == "D": net[tgt] -= 1 for i in range(len(net)): net[i] *= autoIters #net change after all safe iterations for i in range(len(registers)): registers[i] += net[i] display(registers, style, annPath) if autoIters >= 2: print("%i iterations skipped!" % (autoIters)) else: tgt = current.target if current.instr == "I": registers[tgt] += 1 display(registers, style, annPath) trace.append((current, "I", tgt)) current = current.goto elif current.instr == "D": if registers[tgt] == 0: trace.append((current, "Z", tgt)) current = current.zgoto else: registers[tgt] -= 1 display(registers, style, annPath) trace.append((current, "D", tgt)) current = current.goto else: #halt print("~DONE~") return registers
def run(): (code, registers) = setup() tracePrompt = input("Show trace? (y/n): ") trace = (tracePrompt.lower() == "y") stylizedPrompt = input("Stylized output? (y/n): ") stylized = (stylizedPrompt.lower() == "y") hasAnn = False if stylized: annPath = input("Annotation file path? (blank for no file): ") if annPath != "": hasAnn = True annFile = open(annPath) annLines = annFile.readlines() if trace: #don't want to go step-by step if there's no trace sbsPrompt = input("Step-by-step? (y/n): ") sbs = (sbsPrompt.lower() == "y") outputPrompt = input("Output to file? (y/n): ") output = (outputPrompt.lower() == "y") if output: outpath = input("File path to output to: ") outfile = open(outpath,"w") #default labels are R0, R1, ... defaultLab = lmap(lambda x: "R" + str(x),range(len(registers))) labels = copy(defaultLab) comment = "" pc = 1 while True: if hasAnn: aLine = annLines[pc-1] semiSplit = aLine.split(";") aRegLabels = semiSplit[0] comment = semiSplit[1] if aRegLabels != "": #empty means do nothing if aRegLabels[0] == "&": labels = copy(defaultLab) else: someLabels = aRegLabels.split(",") for i in range(len(labels)): if someLabels[i] != "": labels[i] = someLabels[i] line = code[pc-1] instr = line[0] if instr == "inc": reg = line[1] goto = line[2] registers[reg] += 1 #increment register, goto specified line pc = goto elif instr == "dec": reg = line[1] goto = line[2] zgoto = line[3] if registers[reg] == 0: pc = zgoto continue else: registers[reg] -= 1 pc = goto else: if not trace: if stylized: print(tableFormat(labels,registers,comment)) else: print(registers) #show final state of registers print("~DONE~") return if trace: #show middle steps if stylized: print(tableFormat(labels,registers,comment)) else: print(registers) if sbs: input() if output: if stylized: outfile.write(tableFormat(labels,registers,comment)+"\n") else: outfile.write(str(registers)+"\n")