Ejemplo n.º 1
0
def getRegArgNum(macroDict, name):
  if name == "inc" or name == "dec":
    return 1
  elif name == "halt":
    return 0
  else:
    if name in macroDict:
      return macroDict[name].numRegArgs
    else:
      error("Macro not found.")
Ejemplo n.º 2
0
 def setZgoto(self, zgoto):
     #zgoto is an instruction node
     if self.instr == "D":
         self.zgoto = zgoto
     else:
         error("Only decrement instructions have a zgoto.")
Ejemplo n.º 3
0
 def setGoto(self, goto):
     #goto is an instruction node
     if self.instr == "H":
         error("Halt instructions have no goto.")
     else:
         self.goto = goto
Ejemplo n.º 4
0
 def setTarget(self, target):
     #assume target is valid and is an int
     if self.instr == "H":
         error("Halt instructions have no target.")
     else:
         self.target = target
Ejemplo n.º 5
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")
Ejemplo n.º 6
0
 def error(self,string):
   #for some reason, your __init__ might go awry
   error(string)
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