def get_val(fn_name, dlist): curr_ptr = dlist while (not iseqbool(curr_ptr, SExp(exp_type=2, sym_atm="NIL")) and not iseqbool(car(car(curr_ptr)), fn_name)): curr_ptr = curr_ptr.right if (iseqbool(curr_ptr, SExp(exp_type=2, sym_atm="NIL"))): raise MyError("%s is not a function definition\n" % fn_name) return cdr(car(curr_ptr))
def addtoAlist(plist, x, alist, fn): curr_ptr_p = plist curr_ptr_x = x new_alist = alist while (not iseqbool(curr_ptr_p, SExp(exp_type=2, sym_atm="NIL"))): new_alist = cons(cons(car(curr_ptr_p), car(curr_ptr_x)), new_alist) curr_ptr_x = cdr(curr_ptr_x) curr_ptr_p = cdr(curr_ptr_p) if not iseqbool(curr_ptr_x, SExp(exp_type=2, sym_atm="NIL")): raise MyError("Number of argument does not match for function %s" % fn) return new_alist
def eq(SExp1, SExp2): if SExp1.type == 1: if SExp2.type == 1: return retLisp(SExp1.int_val == SExp2.int_val) else: return SExp(exp_type=2, sym_atm="NIL") elif SExp1.type == 2: if SExp2.type == 2: return retLisp(SExp1.sym_atm == SExp2.sym_atm) else: return SExp(exp_type=2, sym_atm="NIL") else: return SExp(exp_type=2, sym_atm="NIL")
def EQLISP(SExp1, SExp2): if SExp1.type == 1: if SExp2.type == 1: return retLisp(SExp1.int_val == SExp2.int_val) else: return SExp(exp_type=2, sym_atm="NIL") elif SExp1.type == 2: if SExp2.type == 2: return retLisp(SExp1.sym_atm == SExp2.sym_atm) else: return SExp(exp_type=2, sym_atm="NIL") else: raise MyError("Arguments for equal should be atomic and same type")
def evcon(be, alist, dlist): if iseqbool(be, SExp(exp_type=2, sym_atm="NIL")): raise MyError("No condition correct") car_ev_be = evlist(car(be), alist, dlist) # leval, _, _ = lispeval(car(car(be)), alist, dlist) if not chk_numarg(car_ev_be, 2): raise MyError("Number of arguments for COND is not 2") if iseqbool(car(car_ev_be), SExp(exp_type=2, sym_atm="T")): # leval, _, _ = lispeval(car(cdr(be)), alist, dlist) # return leval return car(cdr(car_ev_be)) else: return evcon(cdr(be), alist, dlist)
def main(): # raw_input(SExp_str) # SExp_str = " ( 2 3 4 ) " # SExp_str = "((2.4) (3.5))" # SExp_str = "((ASD3 . 324) (2 . L2))" # SExp_str = "((2.4) . (3.5))" # SExp_str = "(2.(3.4))" # SExp_str = "( 3 (3.5)) " # Full_SExp_str = "(AB.(BC.AB))$( 3 (3.5))$$" # SExp_str = "(s)" # SExp_str = "((()))" # SExp_str = "(ASF2.2)" # just making sure nothing is after $$ # Full_SExp_str = Full_SExp_str[:Full_SExp_str.find("$$")] # list_SExp_str = Full_SExp_str.split("$") # EXPECTS $ AS LAST CHARACTER IN A LINE flag = True alist = SExp(exp_type=2, sym_atm="NIL") dlist = SExp(exp_type=2, sym_atm="NIL") while flag: SExp_str = "" line = raw_input() SExp_str = SExp_str + line.split('$')[0] while (line.find("$") == -1): line = raw_input() SExp_str = SExp_str + line.split('$')[0] if line.find("$$") != -1: flag = False # elif dollar_str != "$": # print "Expected SExp in line and then $ in new line- alternating between SExpression and $" SExp_str = remove_space(SExp_str) try: Fin_SExp, rem_SExp_str = input_lisp(SExp_str) if rem_SExp_str: raise MyError( "error expected input to be finished but got %s" % rem_SExp_str) print "Dot Notation: %s " % print_tree(Fin_SExp) Eval_SExp, state, dlist = lispeval(Fin_SExp, alist, dlist) if state: print "State Changed and dlist looks: %s" % print_tree(dlist) else: print "Evaluation: %s" % print_tree(Eval_SExp) # import pdb # pdb.set_trace() except MyError as e: print "Error in %s: %s" % (SExp_str, e.err_msg)
def get_valAlist(LSExp, alist): list_pair = alist while (not iseqbool(list_pair, SExp(exp_type=2, sym_atm="NIL"))): if iseqbool(car(car(list_pair)), LSExp): return cdr(car(list_pair)) list_pair = cdr(list_pair) raise MyError("Unbounded error %s" % LSExp.sym_atm.name)
def addtodlist(dlist, functparbody): if not chk_numarg(functparbody, 3): raise MyError("Number of arguments for DEFUN should be 3") if iseqbool(atom(car(cdr(functparbody))), SExp(exp_type=2, sym_atm="T")): raise MyError("Parameters for functions should not be a atom") dlist = cons(functparbody, dlist) return dlist
def initiate_atoms(): SExp(exp_type=2, sym_atm="T") SExp(exp_type=2, sym_atm="NIL") SExp(exp_type=2, sym_atm="CONS") SExp(exp_type=2, sym_atm="CAR") SExp(exp_type=2, sym_atm="CDR") SExp(exp_type=2, sym_atm="COND")
def input2(SExp_str, tkn, l_type): if l_type == 1: S1, SExp_str = input_lisp("(" + SExp_str) SExp_str, tkn, l_type = ckNextToken(SExp_str) S2, SExp_str = input2(SExp_str, tkn, l_type) return cons(S1, S2), SExp_str if l_type == 2: return SExp(exp_type=2, sym_atm="NIL"), SExp_str elif l_type == 4: tkn_old = tkn SExp_str, tkn, l_type = ckNextToken(SExp_str) S2, SExp_str = input2(SExp_str, tkn, l_type) return cons(SExp(exp_type=1, int_val=tkn_old), S2), SExp_str elif l_type == 5: tkn_old = tkn SExp_str, tkn, l_type = ckNextToken(SExp_str) S2, SExp_str = input2(SExp_str, tkn, l_type) return cons(SExp(exp_type=2, sym_atm=tkn_old), S2), SExp_str elif l_type == 6: SExp_str, tkn, l_type = ckNextToken(SExp_str) return input2(SExp_str, tkn, l_type) else: raise MyError("error did not expect \".\" at %s" % tkn + SExp_str)
def input_lisp(SExp_str): SExp_str, tkn, l_type = ckNextToken(SExp_str) if l_type == 1: # adding for special () dont know how to handle otherwise temp_SExp_str, tkn, l_type = ckNextToken(SExp_str) if l_type == 2: return SExp(exp_type=2, sym_atm="NIL"), temp_SExp_str S1, SExp_str = input_lisp(SExp_str) SExp_str, tkn, l_type = ckNextToken(SExp_str) # Space automatically implies a list if l_type == 6 or l_type == 2: # list S2, SExp_str = input2(SExp_str, tkn, l_type) return cons(S1, S2), SExp_str elif l_type == 3: S2, SExp_str = input_lisp(SExp_str) SExp_str, tkn, l_type = ckNextToken(SExp_str) if l_type == 2: return cons(S1, S2), SExp_str else: raise MyError("error expected \")\" at %s" % tkn + SExp_str) else: raise MyError("error expected \".\" or \")\" or \" \" at %s" % tkn + SExp_str) # TODO: accepts 4., 4, ), etc if l_type == 4: # if its just a number it better end with $ return SExp(exp_type=1, int_val=tkn), SExp_str # TODO: accepts 4., 4, ), etc if l_type == 5: # if its just a identifier it better end with $ return SExp(exp_type=2, sym_atm=tkn), SExp_str if l_type == 2 or l_type == 3 or l_type == 6 or l_type == -1: raise MyError("error expected Symbolic atom, integer or \"(\" at %s" % tkn + SExp_str)
def lispeval(LSExp, alist, dlist): if iseqbool(atom(LSExp), SExp(exp_type=2, sym_atm="T")): if LSExp.type == 1: return LSExp, 0, dlist elif iseqbool(LSExp, SExp(exp_type=2, sym_atm="T")) or iseqbool( LSExp, SExp(exp_type=2, sym_atm="NIL")): return LSExp, 0, dlist else: return get_valAlist(LSExp, alist), 0, dlist elif iseqbool(atom(car(LSExp)), SExp(exp_type=2, sym_atm="T")): if iseqbool(car(LSExp), SExp(exp_type=2, sym_atm="COND")): return evcon(cdr(LSExp), alist, dlist), 0, dlist elif iseqbool(car(LSExp), SExp(exp_type=2, sym_atm="DEFUN")): return None, 1, addtodlist(dlist, cdr(LSExp)) # TODO: Quote parameter checking elif iseqbool(car(LSExp), SExp(exp_type=2, sym_atm="QUOTE")): return car(cdr(LSExp)), 0, dlist else: return lispapply(car(LSExp), evlist(cdr(LSExp), alist, dlist), alist, dlist), 0, dlist else: raise MyError("SExp should be atom or car of SExp should be atom")
def evlist(LSExp, alist, dlist): curr_ptr = LSExp while (not iseqbool(curr_ptr, SExp(exp_type=2, sym_atm="NIL"))): car_eval, _, _ = lispeval(car(LSExp), alist, dlist) return cons(car_eval, evlist(cdr(LSExp), alist, dlist)) return SExp(exp_type=2, sym_atm="NIL")
def chk_numarg(x, expected): curr_x = x while (not iseqbool(curr_x, SExp(exp_type=2, sym_atm="NIL"))): curr_x = cdr(curr_x) expected -= 1 return True if expected == 0 else False
def cons(SExp_1, SExp_2): return SExp(exp_type=3, SE1=SExp_1, SE2=SExp_2)
def lispapply(fn_name, x, alist, dlist): # fn_name should be an atom as its checked in lispeval if iseqbool(fn_name, SExp(exp_type=2, sym_atm="CAR")): if not chk_numarg(x, 1): raise MyError("Number of argument for CAR not correct") return car(car(x)) elif iseqbool(fn_name, SExp(exp_type=2, sym_atm="CDR")): if not chk_numarg(x, 1): raise MyError("Number of argument for CDR not correct") return cdr(car(x)) elif iseqbool(fn_name, SExp(exp_type=2, sym_atm="EQ")): if not chk_numarg(x, 2): raise MyError("Number of argument for EQ not correct") return EQLISP(car(x), car(cdr(x))) elif iseqbool(fn_name, SExp(exp_type=2, sym_atm="ATOM")): if not chk_numarg(x, 1): raise MyError("Number of argument for ATOM not correct") return atom(car(x)) elif iseqbool(fn_name, SExp(exp_type=2, sym_atm="CONS")): if not chk_numarg(x, 2): raise MyError("Number of argument for CONS not correct") return cons(car(x), car(cdr(x))) elif iseqbool(fn_name, SExp(exp_type=2, sym_atm="NULL")): if not chk_numarg(x, 1): raise MyError("Number of argument for NULL not correct") return eq(car(x), SExp(exp_type=2, sym_atm="NIL")) elif iseqbool(fn_name, SExp(exp_type=2, sym_atm="INT")): if not chk_numarg(x, 1): raise MyError("Number of argument for INT not correct") return SExp(exp_type=2, sym_atm="T") if car(x).type == 1 \ else SExp(exp_type=2, sym_atm="NIL") elif iseqbool(fn_name, SExp(exp_type=2, sym_atm="PLUS")): if not chk_numarg(x, 2): raise MyError("Number of argument for PLUS not correct") if car(x).type == 1 and car(cdr(x)).type == 1: return SExp(exp_type=1, int_val=car(x).int_val + car(cdr(x)).int_val) else: raise MyError("Not correct format for PLUS") elif iseqbool(fn_name, SExp(exp_type=2, sym_atm="MINUS")): if not chk_numarg(x, 2): raise MyError("Number of argument for MINUS not correct") if car(x).type == 1 and car(cdr(x)).type == 1: return SExp(exp_type=1, int_val=car(x).int_val - car(cdr(x)).int_val) else: raise MyError("Not correct format for MINUS") elif iseqbool(fn_name, SExp(exp_type=2, sym_atm="TIMES")): if not chk_numarg(x, 2): raise MyError("Number of argument for TIMES not correct") if car(x).type == 1 and car(cdr(x)).type == 1: return SExp(exp_type=1, int_val=car(x).int_val * car(cdr(x)).int_val) else: raise MyError("Not correct format for TIMES") elif iseqbool(fn_name, SExp(exp_type=2, sym_atm="QUOTIENT")): if not chk_numarg(x, 2): raise MyError("Number of argument for QUOTIENT not correct") if car(x).type == 1 and car(cdr(x)).type == 1: try: return SExp(exp_type=1, int_val=car(x).int_val / car(cdr(x)).int_val) except ZeroDivisionError: raise MyError("Zero cannot be in denomintor for QUOTIENT") else: raise MyError("Not correct format for QUOTIENT") elif iseqbool(fn_name, SExp(exp_type=2, sym_atm="REMAINDER")): if not chk_numarg(x, 2): raise MyError("Number of argument for REMAINDER not correct") if car(x).type == 1 and car(cdr(x)).type == 1: try: return SExp(exp_type=1, int_val=car(x).int_val % car(cdr(x)).int_val) except ZeroDivisionError: raise MyError("Zero cannot be in denomintor for REAMINDER") else: raise MyError("Not correct format for REMAINDER") elif iseqbool(fn_name, SExp(exp_type=2, sym_atm="LESS")): if not chk_numarg(x, 2): raise MyError("Number of argument for LESS not correct") if car(x).type == 1 and car(cdr(x)).type == 1: return retLisp(car(x).int_val < car(cdr(x)).int_val) else: raise MyError("Not correct format for LESS") elif iseqbool(fn_name, SExp(exp_type=2, sym_atm="GREATER")): if not chk_numarg(x, 2): raise MyError("Number of argument for GREATER not correct") if car(x).type == 1 and car(cdr(x)).type == 1: return retLisp(car(x).int_val > car(cdr(x)).int_val) else: raise MyError("Not correct format for GREATER") else: par_bdy = get_val(fn_name, dlist) leval, _, _ = lispeval(car(cdr(par_bdy)), addtoAlist(car(par_bdy), x, alist, fn_name), dlist) return leval
def retLisp(boolval): return SExp(exp_type=2, sym_atm="T") if boolval \ else SExp(exp_type=2, sym_atm="NIL")
def atom(LSExp): return SExp(exp_type=2, sym_atm="T") if LSExp.type != 3 \ else SExp(exp_type=2, sym_atm="NIL")