PL λαβ
Lab 4.1a[최준혁]: 조건, 비교 본문
Code
내장 비교 연산과 조건문까지 구현하였습니다. 마찬가지로 기본 진행방식은 참고 페이지를 따라하였고, 부분부분 파이썬에 맞도록 수정하였습니다. 계속 미루고 있었던 에러 리턴과 처리를 문자열로 통일하여 동작하도록 하였는데, 후에 이 부분은 Error class로 고치면 더 깔끔할것 같습니다.
mycode.py
from boilerplate import *
# from environment_mark2 import *
class Bindings:
def __init__(self, parent):
self.parent = parent
self.symbols = dict()
def add_symbol(self, symbol, value):
if symbol.type == Type.SYM:
self.symbols[symbol.value.upper()] = value
def __str__(self):
if isNil(self.parent):
return f"ENV class : root"
else:
return f"ENV class : {str(self.parent)}"
def __repr__(self):
return self.__str__()
def env_create(parent):
new_bindings = Bindings(parent)
# if not isNil(parent):
# parent.add_child(new_bindings)
return new_bindings
def env_get(env, symbol):
parent = env.parent
if symbol.value.upper() in env.symbols:
return env.symbols[symbol.value.upper()]
if type(parent) is Bindings:
pass
elif isNil(parent):
# return "Error unbound", nilp()
return nilp()
return env_get(parent, symbol)
def env_set(env, symbol, value):
env.add_symbol(symbol, value)
# return ErrorType.ERROR_OK
return "Error OK", nilp()
def listp(expr):
while not isNil(expr):
if expr.type != Type.PAIR:
return False
expr = expr.cdr()
return True
def eval_expr(expr, env):
if expr.type == Type.SYM:
# return ErrorType.ERROR_OK, env_get(env, expr)
return "Error OK", env_get(env, expr)
elif expr.type != Type.PAIR:
# return ErrorType.ERROR_OK, expr
return "Error OK", expr
if not listp(expr):
# return ErrorType.ERROR_SYNTAX, nilp()
return "Error Syntax", nilp()
op = expr.car()
args = expr.cdr()
if op.type == Type.SYM:
if op.value.upper() == "QUOTE":
if isNil(args) or not isNil(args.cdr()):
return "Error Args", nilp()
return "Error OK", args.car()
elif op.value.upper() == "DEF":
if isNil(args) or isNil(args.cdr()) or not isNil(args.cdr().cdr()):
return "Error Args", nilp()
sym = args.car()
if sym.type != Type.SYM:
return "Error Type", nilp()
err, val = eval_expr(args.cdr().car(), env)
env_set(env, sym, val)
return "Error OK", sym
elif op.value.upper() == "LAM": # lambda
if isNil(args) or isNil(args.cdr()):
return "Error Args", nilp()
return make_closure(env, args.car(), args.cdr())
elif op.value.upper() == "IF":
if isNil(args) or isNil(args.cdr()) or isNil(args.cdr().cdr()) or not isNil(args.cdr().cdr().cdr()):
return "Error Args", nilp()
err, cond = eval_expr(args.car(), env)
if err != "Error OK":
return err, nilp()
val = args.cdr().cdr().car() if isNil(cond) else args.cdr().car()
return eval_expr(val, env)
err, op = eval_expr(op, env)
if err != "Error OK":
return err, nilp()
args = copy_list(args)
p = args
while not isNil(p):
err, p.value[0] = eval_expr(p.car(), env)
if err != "Error OK":
return err, nilp()
p = p.cdr()
return apply(op, args)
return "Error Syntax", nilp()
def make_builtin(fn):
a = Data()
a.type = Type.BUILTIN
a.value = fn
return a
def make_closure(env, args, body):
if not listp(args) or not listp(body):
return "Error Syntax", nilp()
p = args
while not isNil(p):
if p.car().type != Type.SYM:
return "Error Type", nilp()
p = p.cdr()
result = cons(env, cons(args, body))
result.type = Type.CLOSURE
return "Error OK", result
def copy_list(lst):
if isNil(lst):
return nilp()
a = cons(lst.car(), nilp())
p = a
lst = lst.cdr()
while not isNil(lst):
p.value[1] = cons(lst.car(), nilp())
p = p.cdr()
lst = lst.cdr()
return a
def apply(fn, args):
if fn.type == Type.BUILTIN:
return fn.value(args)
elif fn.type != Type.CLOSURE:
return "Error Type", nilp()
env = env_create(fn.car())
arg_names = fn.cdr().car()
body = fn.cdr().cdr()
while not isNil(arg_names):
if isNil(args):
return "Error Args", nilp()
env_set(env, arg_names.car(), args.car())
arg_names = arg_names.cdr()
args = args.cdr()
if not isNil(args):
return "Error Args", nilp()
while not isNil(body):
err, result = eval_expr(body.car(), env)
if err != "Error OK":
return err, nilp()
body = body.cdr()
return "Error OK", result
def builtin_car(args):
return "Error OK", args.car()
# if isNil(args) or not isNil(args.cdr()):
# return "Error Args", nilp()
#
# if isNil(args.car()):
# return "Error OK", nilp()
# elif args.car().type != Type.PAIR:
# return "Error Type", nilp()
# else:
# return "Error OK", args.car().car()
def builtin_cdr(args):
return "Error OK", args.cdr()
# if isNil(args) or not isNil(args.cdr):
# return "Error Args", nilp()
#
# if isNil(args.car()):
# return "Error OK", nilp()
# elif args.car().type != Type.PAIR:
# return "Error Type", nilp()
# else:
# return "Error OK", args.car().cdr()
def builtin_cons(args):
if isNil(args) or isNil(args.cdr()) or not isNil(args.cdr().cdr()):
return "Error Args", nilp()
return "Error OK", cons(args.car(), args.cdr())
def builtin_add(args):
if isNil(args) or isNil(args.cdr()) or not isNil(args.cdr().cdr()):
return "Error Args", nilp()
a = args.car()
b = args.cdr().car()
if a.type != Type.INT or b.type != Type.INT:
return "Error Type", nilp()
return "Error OK", mkint(args.car().value + args.cdr().car().value)
def builtin_subtract(args):
if isNil(args) or isNil(args.cdr()) or not isNil(args.cdr().cdr()):
return "Error Args", nilp()
a = args.car()
b = args.cdr().car()
if a.type != Type.INT or b.type != Type.INT:
return "Error Type", nilp()
return "Error OK", mkint(args.car().value - args.cdr().car().value)
def builtin_multiply(args):
if isNil(args) or isNil(args.cdr()) or not isNil(args.cdr().cdr()):
return "Error Args", nilp()
a = args.car()
b = args.cdr().car()
if a.type != Type.INT or b.type != Type.INT:
return "Error Type", nilp()
return "Error OK", mkint(args.car().value * args.cdr().car().value)
def builtin_divide(args):
if isNil(args) or isNil(args.cdr()) or not isNil(args.cdr().cdr()):
return "Error Args", nilp()
a = args.car()
b = args.cdr().car()
if a.type != Type.INT or b.type != Type.INT:
return "Error Type", nilp()
return "Error OK", mkint(args.car().value // args.cdr().car().value)
def builtin_numeq(args):
if isNil(args) or isNil(args.cdr()) or not isNil(args.cdr().cdr()):
return "Error Args", nilp()
a = args.car()
b = args.cdr().car()
if a.type != Type.INT or b.type != Type.INT:
return "Error Type", nilp()
result = mksym("T") if a.value == b.value else nilp()
return "Error OK", result
def builtin_less(args):
if isNil(args) or isNil(args.cdr()) or not isNil(args.cdr().cdr()):
return "Error Args", nilp()
a = args.car()
b = args.cdr().car()
if a.type != Type.INT or b.type != Type.INT:
return "Error Type", nilp()
result = mksym("T") if a.value < b.value else nilp()
return "Error OK", result
if __name__ == "__main__":
env = env_create(nilp())
env_set(env, mksym("CAR"), make_builtin(builtin_car))
env_set(env, mksym("CDR"), make_builtin(builtin_cdr))
env_set(env, mksym("CONS"), make_builtin(builtin_cons))
env_set(env, mksym("+"), make_builtin(builtin_add))
env_set(env, mksym("-"), make_builtin(builtin_subtract))
env_set(env, mksym("*"), make_builtin(builtin_multiply))
env_set(env, mksym("/"), make_builtin(builtin_divide))
env_set(env, mksym("T"), mksym("T"))
env_set(env, mksym("="), make_builtin(builtin_numeq))
env_set(env, mksym("<"), make_builtin(builtin_less))
while True:
parsedlist = Parser(Lexer(Input()._input()).lex())
# print("\n===== === PAR === =====")
# print(parsedlist)
# print("===== === OUT === =====")
err, result = eval_expr(parsedlist, env)
if err != "Error OK":
print(err)
else:
print(result)
# print(env)
boilerplate.py
실습시간에 나왔던 0이 None Type으로 처리되는 문제는 조교님이 제시해주신 해답을 살짝 수정해서 적용하였습니다.
### ......
def Parser(tokenlist):
if len(tokenlist) == 0:
return Err(Nil(), ErrorType.NO_INPUT_FILE)
LA = tokenlist.pop(0)
if LA.type == Keyword.LPAREN:
if tokenlist[0].type == Keyword.RPAREN:
return nilp()
L = []
while tokenlist[0].type != Keyword.RPAREN:
L.append(Parser(tokenlist))
tokenlist.pop(0)
LR = iCons(L)
return LR
elif LA.type == Keyword.RPAREN:
return Err(LA, ErrorType.UNEXPECTED_TOKEN)
else:
if LA.value.isdigit(): # int
return Data(Type.INT, int(LA.value))
elif LA.value.replace('.', '', 1).isdigit(): # float
return Data(Type.REAL, float(LA.value))
else:
return Data(Type.SYM, str(LA.value))
### ......
TEST
>> (if t 3 4)
3
>> (if nil 3 4)
4
>> (if 0 t nil)
T
>> (= 3 3)
T
>> (< 11 4)
NIL
>> (define fact (lambda (x) (if (= x 0) 1 (* x (fact (- x 1))))))
fact
>> (fact 3)
6
>> (fact 10)
3628800
>>
'kos' 카테고리의 다른 글
Lab 5.1a[김예령]: 한글 스킴 (0) | 2021.05.04 |
---|---|
Lab 5.1a[최준혁]: 한글 스킴 (0) | 2021.05.04 |
Lab 4.1a[김예령]: 조건, 비교 (0) | 2021.04.29 |
Lab 3.1a[김예령]: 람다와 클로저 (0) | 2021.04.29 |
Lab 3.1a[최준혁]: 람다와 클로저 (0) | 2021.04.27 |
Comments