def formula(env, f, heap = int( macros.HEAP_START ) ): tag = str( id( f )) if type(f) == Leaf: if f == 'True': # Find a new memory address on the heap. heap = heap + 1 # Generate instruction to store the integer representing True on the heap. inst = 'set ' + str(heap) + ' 1' # Return the instruction list and top of the heap. return ([inst], heap, heap + 1 ) if f == 'False': # Find a new memory address on the heap. heap = heap + 1 # Generate instruction to store the integer representing False on the heap. inst = 'set ' + str(heap) + ' 0' # Return the instruction list and top of the heap. return ([inst], heap, heap + 1) if type(f) == Node: for label in f: children = f[label] if label == "Variable": varName = children[ 0 ] varAddr = env[ varName ] instsVar = [ 'doc value of ' + varName + ' addr = ' + str( varAddr )] instsVar += macros.copy( varAddr, heap ) return ( instsVar, heap, heap + 1) if label == 'Not': # Compile the subtree f to obtain the list of # instructions that computes the value represented # by f. f = children[0] (insts, heap, nextHeap) = formula( env, f, heap ) # Generate more instructions to change the memory # location in accordance with the definition of the # Not operation. instsNot = \ ["branch setZero" + tag + " " + str(heap),\ "set " + str(heap) + " 1",\ "goto finish" + tag,\ "label setZero" + tag,\ "set " + str(heap) + " 0",\ "label finish" + tag\ ] return (insts + instsNot, heap, heap+1) if label == 'Or': # Compile the two subtrees and get the instructions # lists as well as the addresses in which the results # of computing the two subtrees would be stored if someone # were to run those machine instructions. f1 = children[0] f2 = children[1] (insts1, leftResult, nextHeap) = formula( env, f1, heap ) (insts2, rightResult, nextHeap) = formula( env, f2, nextHeap ) # Increment the heap counter so we store the # result of computing Or in a new location. heap4 = nextHeap + 1 # Add instructions that compute the result of the # Or operation. instsOr = macros.add( leftResult, rightResult, macros.ADD_RESULT ) instsOr += [\ "branch setOne" + tag + " 0",\ "goto finish" + tag,\ "label setOne" + tag,\ "set " + macros.ADD_RESULT + " 1",\ "label finish" + tag,\ ] instsOr += macros.copy( "0", str( heap4 ) ) return (insts1 + insts2 + instsOr, heap4, heap4+1) if label == 'And': # adding left and right results: true == 1 and false == 0 # false + false == 0 : and -> 0 # false + true == 1 : and -> 0 # true + false == 1 : and -> 0 # true + true == 2 : and -> 1 # so 0->0, 1->0, 2->1 # we generate # goto zero # goto zero # goto one # and we jump based on the result of adding the children of And # Compile the two subtrees and get the instructions # lists as well as the addresses in which the results # of computing the two subtrees would be stored if someone # were to run those machine instructions. f1 = children[0] f2 = children[1] (insts1, leftResult, nextHeap) = formula( env, f1, heap ) (insts2, rightResult, nextHeap) = formula( env,f2, nextHeap ) # Increment the heap counter so we store the # result of computing And in a new location. heap4 = nextHeap + 1 heap5 = heap4 + 1 # Add instructions that compute the result of the # Or operation. instsAnd = macros.add( leftResult, rightResult, heap4 ) instsAnd += macros.relativeJump( heap4 ) instsAnd += [\ "goto zero" + tag,\ "goto zero" + tag,\ "goto one" + tag,\ "label zero" + tag,\ "set " + macros.ADD_RESULT + " 0",\ "goto finish" + tag,\ "label one" + tag,\ "set " + macros.ADD_RESULT + " 1",\ "label finish" + tag,\ ] instsAnd += macros.copy( "0", str( heap5 ) ) return (insts1 + insts2 + instsAnd, heap5, heap5 + 1)
def macroTests(): testRelJump = ''' set 200 0 set 100 3 ''' + toStr( macros.relativeJump( 100 ) ) + ''' set 200 1 goto finish set 200 2 goto finish set 200 3 goto finish label finish assert 200 2 ''' test( testRelJump ) testCopy = ''' set 100 1 ''' + toStr( macros.copy( 100, 200 ) ) + ''' assert 200 1 ''' test( testCopy ) testAdd = ''' set 100 1000 set 101 2000 ''' + toStr( macros.add( 100, 101, 102 ) ) + ''' assert 102 3000 ''' test( testAdd ) testIncr = ''' set 100 2000 set 200 2000 ''' + toStr( macros.incrementBy( 100, 1 ) ) + ''' ''' + toStr( macros.incrementBy( 200, -1 ) ) + ''' assert 100 2001 assert 200 1999 ''' test( testIncr ) testDeref = ''' set 100 200 set 200 1000 set 300 0 ''' + toStr( macros.deref( 100, 300 ) ) + ''' assert 300 1000 ''' test( testDeref ) testIndirectSet = ''' set 100 101 set 101 1000 set 200 201 set 201 0 ''' + toStr( macros.indirectSet( 100, 200 ) ) + ''' assert 201 1000 ''' test( testIndirectSet ) testIndirectSetLiteral = ''' set 100 200 set 200 0 ''' + toStr( macros.indirectSetLiteral( 100, 123 ) ) + ''' assert 200 123 ''' test( testIndirectSet ) testIndirectIncrement = ''' set 100 101 set 101 1000 ''' + toStr( macros.indirectIncrement( 100, 50 ) ) + ''' assert 101 1050 ''' test( testIndirectIncrement ) testIndirectIncrement = ''' set 100 101 set 101 1000 ''' + toStr( macros.indirectIncrement( 100, 50 ) ) + ''' assert 101 1050 ''' test( testIndirectIncrement ) testStack = ''' set 100 2222 set 200 0 ''' + toStr( macros.push( 100 ) ) + ''' assert -1 2222 ''' + toStr( macros.pop( 200 ) ) + ''' doc assert 200 2222 ''' + toStr( macros.pushLiteral( 10 ) ) + ''' assert -1 10 '''+ toStr( macros.pushLiteral( 4 ) ) + ''' assert -2 4 '''+ toStr( macros.pop( 100 ) ) + ''' assert 100 4 '''+ toStr( macros.pop( 200 ) ) + ''' assert 200 10 ''' test( testStack ) pcall = ''' ''' + toStr( macros.procedure( "foo", [ 'set 300 1 ', 'set 301 2'])) + ''' ''' + toStr( macros.call( "foo", "blah" ) ) + ''' assert 300 1 assert 301 2 ''' test( pcall )