# For a language with dynamic typing, no side effects, and only one scope # First set of classes are AST nodes # Then the State class (a dictionary) # Then the functions for the semantics. # Abstract syntax # # Statement = Assignment | Conditional # Assignment = target (Variable), source (Expression) # Conditional = condition (Expression), thenBranch (Statement), elseBranch (Statement) # Expression = BinaryExpression | Variable | Value | Relation # BinaryExpression = string op (+,-,*,/), Expression left, Expression right # Relation = string op (<,>,==,!=), Expression left, Expression right # Conjunction = string op (AND,OR), Expression left, Expression right # Variable = string name # Value = a literal integer class Skip: pass class Assignment: def __init__( self, target, source ): self.target = target self.source = source class Condition: def __init__( self, condition, thenbranch, elsebranch ): self.condition = condition self.thenbranch = thenbranch self.elsebranch = elsebranch class Block: def __init__( self, statements ): self.statements = statements class BinaryExpression: def __init__( self, left, operator, right ): self.left = left self.operator = operator self.right = right class Relation: def __init__( self, left, operator, right ): self.left = left self.operator = operator self.right = right class Conjunction: def __init__( self, left, operator, right ): self.left = left self.operator = operator self.right = right class While: def __init__( self, test, body ): self.test = test self.body = body class Variable: def __init__( self, name ): self.name = name class Value: def __init__( self, value ): self.value = value def __str__( self ): return str(self.value) class State: # dictionary that stores string names of vars # and 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 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 return Value( val ) # expr should be a Relation # state should be a State # returns a Value def M_Relation( 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 return Value( val ) def M_Conjunction( expr, state ): # with short-circuiting if expr.operator == 'AND': if M_Expression( expr.left, state ).value: return Value( M_Expression( expr.right, state ).value ) else: return Value( False ) if expr.operator == 'OR': if not M_Expression( expr.left ).value: return Value( M_Expression( expr.right, state ).value ) else: return Value( True ) # expr should be an Expression # state should be a State # returns a Value def M_Expression( expr, state ): if isinstance( expr, Relation ): return M_Relation( expr, state ) elif isinstance( expr, Conjunction ): return M_Conjunction( expr, state ) elif isinstance( expr, BinaryExpression ): return M_BinaryExpression( expr, state ) elif isinstance( expr, Variable ): return state.getValue( expr ) elif isinstance( expr, Value ): return expr else: print "error!", expr def M_Statement( statement, state ): if isinstance( statement, Assignment ): return M_Assignment( statement, state ) elif isinstance( statement, Condition ): return M_Condition( statement, state ) elif isinstance( statement, Block ): return M_Block( statement, state ) elif isinstance( statement, While ): return M_While( statement, state ) elif isinstance( statement, Skip ): return state # 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 # statement should be a Condition # state should be a State # returns a State def M_Condition( statement, state ): if M_Expression(statement.condition,state).value: state = M_Statement( statement.thenbranch, state ) else: state = M_Statement( statement.elsebranch, state ) return state def M_BlockHelper( statements, state ): if len(statements) == 0: return state return M_BlockHelper( statements[1:], M_Statement( statements[0], state ) ) def M_Block( block, state ): return M_BlockHelper( block.statements, state ) def M_While( w, state ): if not M_Expression( w.test, state ).value: return state return M_While( w, M_Statement(w.body, state) ) def main1(): # a = 3 + 5 expr = BinaryExpression( Value(3), "+", Value(5) ) stmnt = Assignment( Variable("a"), expr ) state = State() #state.update( Variable("a"), Value(1) ) state = M_Assignment( stmnt, state ) print( state ) def main2(): # b = (6-2)+4 expr = BinaryExpression( BinaryExpression(Value(6),"-",Value(2)), "+", Value(4) ) stmnt = Assignment( Variable("b"), expr ) state = State() state = M_Assignment( stmnt, state ) print( state ) def main3(): # if (3 < 5) { # b = 5; # } # else { # c = 10; # } test = Relation( Value(3),"<",Value(5) ) stmnt1 = Assignment( Variable("b"), Value(5) ) stmnt2 = Assignment( Variable("c"), Value(10) ) cond = Condition( test, stmnt1, stmnt2 ) state = State() state = M_Statement( cond, state ) print( state ) def main4(): # if (3 < 5) { # if (6 > 2) { # b = 5; # } # } # else { # c = 10; # } test = Relation( Value(3),">",Value(5) ) stmnt1 = Assignment( Variable("b"), Value(5) ) stmnt2 = Assignment( Variable("c"), Value(10) ) test2 = Relation( Value(6),">",Value(2) ) cond2 = Condition( test2, stmnt1, Skip() ) cond = Condition( 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 = Relation( Value(3),"<",Value(5) ) stmnt1a = Assignment( Variable("a"), Value(5) ) stmnt1b = Assignment( Variable("b"), Value(6) ) stmnt1c = Assignment( Variable("d"), Value(42) ) stmnt1 = Block( [stmnt1a,stmnt1b,stmnt1c] ) stmnt2 = Assignment( Variable("c"), Value(10) ) cond = Condition( 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 = Relation( Value(3), "<", Value(4) ) test2 = Relation( Value(4), "<", Value(5) ) overall_test = Conjunction( test1, "AND", test2 ) stmnt1 = Assignment( Variable( "A" ), Value(3) ) stmnt2 = Assignment( Variable( "B" ), Value(3) ) cond = Condition( overall_test, stmnt1, stmnt2 ) state = State() state = M_Statement( cond, state ) print( state ) def main7(): # b = 1; # c = 1; # b + 3 * c varb = Variable('b') varc = Variable('c') val3 = Value(3) expr = BinaryExpression(varb, '+', BinaryExpression(val3, '*', varc)) state = State() state.update(varb, Value(1)) state.update(varc, Value(3)) val = M_Expression(expr, state) print(val) def main8(): # beginning with state {} # while (a < 5 ) # a = a + 1 state = State() a = Variable( "a" ) state.update( a, Value(1) ) test = Relation( a, "<", Value(5) ) body = Assignment( a, BinaryExpression( a, "+", Value(1) ) ) wloop = While( test, body ) state = M_While( wloop, state ) print(state) if __name__ == '__main__': main8() #main2() #main7()