# simple_interpreter.py # Stephanie Taylor # Implements a simple interpreter # For a language with dynamic typing, no side effects, and only one scope # Then the State class (a dictionary) # Then the functions for the semantics. # This is a version which evaluates expressions only. # Abstract syntax # # Statement = Assignment | Conditional | While | Block | Pass # Assignment = target (Variable), source (Expression) # Conditional = condition (Expression), thenBranch (Statement), elseBranch (Statement) # While = test (Expression), body (Statement) # Block = statements (list of Statements) # Pass = # Expression = BinaryExpression | Variable | Value # BinaryExpression = string op (+,-,*,/,<,>,==,!=,&&,II), Expression left, Expression right # Variable = string name # Value = a literal integer or boolean import AST # Where the nodes are defined class State: # dictionary that stores string names of vars # and AST.Value objects def __init__( self ): self.state = {} def update( self, var, value ): self.state[var.name] = value def getValue( self, var ): return self.state[var.name] def __str__( self ): retstr = '' for name in self.state: retstr += name + ": " + str(self.state[name]) + '\n' return retstr[:-1] # expr should be a BinaryExpression # state should be a State # returns a AST.Value def M_BinaryExpression( expr, state ): if expr.operator == '+': val = M_Expression( expr.left, state ).value + M_Expression( expr.right, state ).value elif expr.operator == '-': val = M_Expression( expr.left, state ).value - M_Expression( expr.right, state ).value elif expr.operator == '*': val = M_Expression( expr.left, state ).value * M_Expression( expr.right, state ).value elif expr.operator == '/': val = M_Expression( expr.left, state ).value / M_Expression( expr.right, state ).value elif expr.operator == '<': val = M_Expression( expr.left, state ).value < M_Expression( expr.right, state ).value elif expr.operator == '>': val = M_Expression( expr.left, state ).value > M_Expression( expr.right, state ).value elif expr.operator == '==': val = M_Expression( expr.left, state ).value == M_Expression( expr.right, state ).value elif expr.operator == '!=': val = M_Expression( expr.left, state ).value != M_Expression( expr.right, state ).value # with short-circuiting elif expr.operator == '&&': if M_Expression( expr.left, state ).value: val = M_Expression( expr.right, state ).value else: val = False elif expr.operator == '||': if not M_Expression( expr.left, state ).value: val = M_Expression( expr.right, state ).value else: val = True else: print( "Undefined Expression", expr.operator ) return None return AST.Value( val ) # expr should be an Expression # state should be a State # returns a AST.Value def M_Expression( expr, state ): if isinstance( expr, AST.BinaryExpression ): return M_BinaryExpression( expr, state ) elif isinstance( expr, AST.Variable ): return state.getValue( expr ) elif isinstance( expr, AST.Value ): return expr else: print( "error!", expr ) def M_Statement( statement, state ): if isinstance( statement, AST.Assignment ): return M_Assignment( statement, state ) elif isinstance( statement, AST.Conditional ): return M_Conditional( statement, state ) elif isinstance( statement, AST.Block ): return M_Block( statement, state ) elif isinstance( statement, AST.While ): return M_While( statement, state ) elif isinstance( statement, AST.ForLoop ): return M_For( statement, state ) elif isinstance( statement, AST.Pass ): return state else: print( "Unknown Statement Type" ) # statement should be an Assignment # state should be a State # returns a State def M_Assignment( statement, state ): state.update( statement.target, M_Expression( statement.source, state ) ) return state def M_Block( block, state ): if (len(block.statements) == 0): return state return M_Block( AST.Block(block.statements[1:]), M_Statement( block.statements[0], state ) ) # Conditional = condition (Expression), thenBranch (Statement), elseBranch (Statement) def M_Conditional( c, state ): if M_Expression( c.condition, state ).value: return M_Statement( c.thenbranch, state ) else: return M_Statement( c.elsebranch, state ) # expr should be a ForLoop # state should be a State # returns a State def M_For( loop, state ): return M_ForLoopLooper( loop, M_Statement( loop.initial, state ) ) def M_ForLoopLooper( loop, state ): if not M_Expression( loop.test, state ).value: return state return M_ForLoopLooper( loop, M_Statement( loop.post, M_Statement( loop.body, state ) ) ) def main1(): # Make a Tree for the expression: 3 + 5 expr = AST.BinaryExpression( AST.Value(3), "+", AST.Value(5) ) # we have an empty state state = State() # Evaluate the tree value = M_Expression( expr, state ) print( value ) def main2(): # Given a state with b = 6 state = State() state.update( AST.Variable( "b" ), AST.Value(6) ) # Make the tree for the expression: (b-2)+4 expr = AST.BinaryExpression( AST.BinaryExpression(AST.Value(6),"-",AST.Value(2)), "+", AST.Value(4) ) # Evaluate the tree. value = M_Expression( expr, state ) print( value ) def main3(): # Given a state with b = 6 state = State() state.update( AST.Variable( "b" ), AST.Value(6) ) # Make the tree for the assignment: c = (b-2)+4 expr = AST.BinaryExpression( AST.BinaryExpression(AST.Value(6),"-",AST.Value(2)), "+", AST.Value(4) ) statement = AST.Assignment( AST.Variable("c"), expr ) # Evaluate the tree. state = M_Assignment( statement, state ) print( state ) def main4(): # if (3 < 5) { # if (6 > 2) { # b = 5; # } # } # else { # c = 10; # } test = AST.BinaryExpression( AST.Value(3),">", AST.Value(5) ) stmnt1 = AST.Assignment( AST.Variable("b"), AST.Value(5) ) stmnt2 = AST.Assignment( AST.Variable("c"), AST.Value(10) ) test2 = AST.BinaryExpression( AST.Value(6),">", AST.Value(2) ) cond2 = AST.Conditional( test2, stmnt1, AST.Pass() ) cond = AST.Conditional( test, cond2, stmnt2 ) state = State() state = M_Statement( cond, state ) print( state ) def main5(): # if (3 < 5) { # b = 5; # b = 6; # d = 42; # } # else { # c = 10; # } test = AST.BinaryExpression( AST.Value(3),"<",AST.Value(5) ) stmnt1a = AST.Assignment( AST.Variable("a"), AST.Value(5) ) stmnt1b = AST.Assignment( AST.Variable("b"), AST.Value(6) ) stmnt1c = AST.Assignment( AST.Variable("d"), AST.Value(42) ) stmnt1 = AST.Block( [stmnt1a,stmnt1b,stmnt1c] ) stmnt2 = AST.Assignment( AST.Variable("c"), AST.Value(10) ) cond = AST.Conditional( test, stmnt1, stmnt2 ) state = State() state = M_Statement( cond, state ) print( state ) def main6(): # if (3 < 4 && 4 < 5) { # a = 3 # } # else { # b = 3 # } test1 = AST.BinaryExpression( AST.Value(3), "<", AST.Value(4) ) test2 = AST.BinaryExpression( AST.Value(4), "<", AST.Value(5) ) overall_test = AST.BinaryExpression( test1, "&&", test2 ) stmnt1 = AST.Assignment( AST.Variable( "A" ), AST.Value(3) ) stmnt2 = AST.Assignment( AST.Variable( "B" ), AST.Value(3) ) cond = AST.Conditional( overall_test, stmnt1, stmnt2 ) state = State() state = M_Statement( cond, state ) print( state ) if __name__ == '__main__': main1() main2() main3() main4() main5() main6()