Advertisement
Guest User

again

a guest
Jan 28th, 2020
89
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 10.97 KB | None | 0 0
  1. from functools import reduce
  2. #'(+ 1 2 (+ 2 3))' -> ['+', 1, 2, ['+', 2, 3]]
  3. # parsing
  4.  
  5.  
  6.  
  7. #'(car (quote (+ 42 13)))' -> ['(','car','(','quote','(','+','42','13',')',')',')']
  8.  
  9. class LispInterException(ValueError):pass
  10.  
  11. def tokenize(line):
  12. word_holder = ''
  13. tokens = []
  14. for i in line:
  15. if i == '(' or i == ')':
  16. if word_holder == '':
  17. tokens.append(i)
  18. else:
  19. tokens.append(word_holder)
  20. word_holder = ''
  21. tokens.append(i)
  22. elif i == ' ':
  23. if word_holder != '':
  24. tokens.append(word_holder)
  25. word_holder = ''
  26. else:
  27. word_holder += i
  28. if word_holder != '':
  29. tokens.append(word_holder)
  30. return tokens
  31.  
  32.  
  33.  
  34.  
  35.  
  36. #tokens: '(','42','(','13',')','666',')'
  37. #stack: '(','42',['13']
  38.  
  39. def parse(array): #via stack
  40. stack = []
  41. for i in array:
  42. if i != ')':
  43. if i.isdigit():
  44. stack.append(int(i))
  45. else:
  46. stack.append(i)
  47. else:
  48. resulting_list = []
  49. while stack and stack[-1] != '(':
  50. resulting_list.append(stack.pop())
  51. if stack:
  52. stack.pop()
  53. else:
  54. raise LispInterException("Exception: Missing opening skobochka")
  55. stack.append(resulting_list[::-1])
  56. return stack.pop()
  57.  
  58.  
  59. def to_str(final_list, count, result): #making result look like lisp code
  60. print(final_list)
  61. if count == len(final_list):
  62. return result[:-1] + ') '
  63. else:
  64. if final_list[count] == '\'' or final_list[count] == ',':
  65. return to_str(final_list, count + 1, result)
  66. elif type(final_list[count]) == list:
  67. return to_str(final_list, count + 1, result + to_str(final_list[count], 0, '('))
  68. elif type(final_list[count]) == int:
  69. return to_str(final_list, count + 1, result + str(final_list[count]) + ' ')
  70. else:
  71. return to_str(final_list, count + 1, result + final_list[count] + ' ')
  72.  
  73. global_d = {}
  74. local_d = {}
  75.  
  76. def my_eval(expr, global_d, local_d):
  77. if type(expr) == int: #displaying int number
  78. return expr
  79.  
  80. elif expr == '#t' or expr == '#f': #displaying true/false
  81. return expr
  82.  
  83. elif expr == 'global': #displaying global dict
  84. return global_d
  85.  
  86. elif expr == 'clear global': #Clearing global dict
  87. global_d.clear()
  88. return 'global dictionary is cleared'
  89.  
  90. elif expr == 'exit': #exit key
  91. exit('Exiting terminal')
  92.  
  93. elif type(expr) == str: #Calling variable
  94. if expr in local_d:
  95. return local_d[expr]
  96. elif expr in global_d:
  97. return global_d[expr]
  98. else:
  99. raise LispInterException("Exception: Variable is not defined")
  100.  
  101. elif type(expr) == list and expr[0] == '+': #plus
  102. #print('plusuu')
  103. return reduce(lambda x,y: x + my_eval(y, global_d, local_d), expr[1:], 0)
  104.  
  105. elif type(expr) == list and expr[0] == '-': #minus
  106. #print('minusuu')
  107. if len(expr) == 2: #Lisp returns -x if it's (- x)
  108. return my_eval(expr[1], global_d, local_d) * -1
  109. else:
  110. return reduce(lambda x,y: x - my_eval(y, global_d, local_d), expr[1:], 0)
  111.  
  112. elif type(expr) == list and expr[0] == '*': #multiply
  113. #print('umnojau')
  114. return reduce(lambda x,y: x * my_eval(y, global_d, local_d), expr[1:], 1)
  115.  
  116. elif type(expr) == list and expr[0] == '/': #divide
  117. #print('delu')
  118. if len(expr) == 1:
  119. return 'Error: You can\'t call eval for the empty division symbol'
  120. else:
  121. return reduce(lambda x,y: x / my_eval(y, global_d, local_d), expr[1:])
  122.  
  123. elif type(expr) == list and expr[0] == 'null': #null
  124. #print('null func')
  125. if my_eval(expr[1], global_d, local_d):
  126. return '#f'
  127. else:
  128. return '#t'
  129.  
  130. elif type(expr) == list and expr[0] == '=': #equal
  131. #print('equal func')
  132. if my_eval(expr[1], global_d, local_d) == my_eval(expr[2], global_d, local_d):
  133. return '#t'
  134. else:
  135. return '#f'
  136.  
  137. elif type(expr) == list and expr[0] == '/=': #not equal
  138. #print('not equal func')
  139. if my_eval(expr[1], global_d, local_d) != my_eval(expr[2], global_d, local_d):
  140. return '#t'
  141. else:
  142. return '#f'
  143.  
  144. elif type(expr) == list and expr[0] == '>': #more than
  145. #print('more than func')
  146. if my_eval(expr[1], global_d, local_d) > my_eval(expr[2], global_d, local_d):
  147. return '#t'
  148. else:
  149. return '#f'
  150.  
  151. elif type(expr) == list and expr[0] == '<': #less than
  152. #print('less than func')
  153. if my_eval(expr[1], global_d, local_d) < my_eval(expr[2], global_d, local_d):
  154. return '#t'
  155. else:
  156. return '#f'
  157.  
  158. elif type(expr) == list and expr[0] == '>=': #more or equal than
  159. #print('more or equal than func')
  160. if my_eval(expr[1], global_d, local_d) >= my_eval(expr[2], global_d, local_d):
  161. return '#t'
  162. else:
  163. return '#f'
  164.  
  165. elif type(expr) == list and expr[0] == 'if': #if function
  166. #print('if func')
  167. if my_eval(expr[1], global_d, local_d) == '#t':
  168. return my_eval(expr[2], global_d, local_d)
  169. else:
  170. return my_eval(expr[3], global_d, local_d)
  171.  
  172. elif type(expr) == list and expr[0] == '<=': #less or equal than
  173. #print('less or equal func')
  174. if my_eval(expr[1], global_d, local_d) <= my_eval(expr[2], global_d, local_d):
  175. return '#t'
  176. else:
  177. return '#f'
  178.  
  179. elif type(expr) == list and expr[0] == 'cons': #car + cdr (cons 1 2) -> '(1.2) | (cons 1 '(b c d)) -> '(1 b c d)
  180. #print('cons func')
  181. a = my_eval(expr[1], global_d, local_d)
  182. b = my_eval(expr[2], global_d, local_d)
  183. if type(b) != list:
  184. raise LispInterException("Exception: this intepreter can't handle pairs")
  185. else:
  186. return [a] + b
  187.  
  188. elif type(expr) == list and expr[0] == 'list': #Creating lists
  189. #print('list func')
  190. return [my_eval(i, global_d, local_d) for i in expr[1:]]
  191.  
  192. elif type(expr) == list and expr[0] == 'car': #head of list
  193. #print('car func')
  194. return my_eval(expr[1], global_d, local_d)[0]
  195.  
  196. elif type(expr) == list and expr[0] == 'cdr': #list without head
  197. #print('cdr func')
  198. return my_eval(expr[1], global_d, local_d)[1:]
  199.  
  200. elif type(expr) == list and expr[0] == 'quote': #quoting expression into list
  201. #print('quote func')
  202. return expr[1]
  203.  
  204. elif type(expr) == list and expr[0] == 'let': #local namespace parallel (let ((var1 value1) (var2 value2)) body)
  205. #print('let func')
  206. local_d_new = local_d.copy() #переносим все предыдущие значения в новый дикт, так как надо изолировать дикт в параметрах подаваемый на данный шаг рекурсии и подаваемый на следующий шаг рекурсии
  207. for i in expr[1]: #Заполнение словаря новыми переменными из текущей итерации рекурсии
  208. local_d_new[i[0]] = my_eval(i[1], global_d, local_d)
  209. return my_eval(expr[2], global_d, local_d_new)
  210.  
  211. elif type(expr) == list and expr[0] == 'let*': #local namespace one after another (let* ((var1 value1) (var2 value2)) body)
  212. for i in expr[1]: #Создание новой копии словаря после каждого добавления переменной, чтобы в последующих шагах, если использовалась перезаданная переменная из прошлого шага, было использовано новое значение
  213. local_d = local_d.copy()
  214. local_d[i[0]] = my_eval(i[1], global_d, local_d)
  215. return my_eval(expr[2], global_d, local_d)
  216.  
  217. elif type(expr) == list and expr[0][0] == 'lambda': #making lambda expression ((lambda (params) (body)) params-value)
  218. #print('lambda func')
  219. local_d = local_d.copy()
  220. actuals = [my_eval(i, global_d, local_d) for i in expr[1:]]
  221. for i,j in enumerate(expr[0][1]):
  222. local_d[j] = actuals[i]
  223. return (my_eval(expr[0][2], global_d, local_d))
  224.  
  225. elif type(expr) == list and expr[0] == 'define':
  226. #print('define func')
  227. if type(expr[1]) == str: #для присваивания атому
  228. global_d[expr[1]] = my_eval(expr[2], global_d, local_d)
  229. return 'defined variable ' + expr[1]
  230. else: #Для присваивания функции
  231. if not all(isinstance(n, str) for n in expr[1]):
  232. raise LispInterException('Exception: define - not an identifier, identifier with default, or keyword for procedure argument')
  233. else:
  234. global_d[expr[1][0]] = [['lambda', expr[1][1:], expr[2]]]
  235. return 'defined function ' + str(expr[1][0])
  236.  
  237. else:
  238. if expr[0] in local_d:
  239. print('searching in local')
  240. return my_eval(global_d[expr[0]] + expr[1:], global_d, local_d)
  241. elif expr[0] in global_d:
  242. print('searching in global')
  243. return my_eval(global_d[expr[0]] + expr[1:], global_d, local_d)
  244. else:
  245. raise LispInterException('Exception: you gave some bullshit to the eval')
  246.  
  247.  
  248. #Прогнать парсинг с отладочной печатью
  249. #Написать функцию самостоятельно перегона из стринга в инт, из инта в стринг
  250. #Доделать всю арифметику, а также car cdr quote cons if
  251.  
  252. # REPL = Read Eval Print Loop
  253.  
  254. def repl():
  255. global_d = {}
  256. while True:
  257. expr = input("MICRO-LISP: ")
  258. try:
  259. result = (my_eval(parse(tokenize(expr)), global_d, {}))
  260. if type(result) == int:
  261. print(my_eval(parse(tokenize(expr)), global_d, {}))
  262. else:
  263. print(to_str(my_eval(parse(tokenize(expr)), global_d, {}), 0, '(')[:-1])
  264. except LispInterException as e:
  265. print (e)
  266.  
  267. repl()
  268.  
  269. #Добавить в необходимые места ексепшены (например, не хватает открывающейся скобки)
  270. #Сделать Define
  271. #Реализовать специальную конструкцию If, чтобы експрешион ((if (= 1 1) (lambda (x) (+ 1 x)) (lambda (y) (+ 2 x))) 42) выполнялся (прописать myeval...)
  272. #Реализовать интерпретатор без рекурсии
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement