예제 #1
0
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
예제 #2
0
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
예제 #3
0
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])
예제 #4
0
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
예제 #6
0
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")