Advertisement
Guest User

Untitled

a guest
Aug 4th, 2018
186
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 12.99 KB | None | 0 0
  1.  Новости языка Listh
  2.  by Alone Coder
  3.  
  4. Я долго взвешивал, нужны ли с самого начала дополнительные
  5. структуры данных, кроме списков, которые казались
  6. расточительными по памяти. Решил записать плююсы и минусы
  7. хранения в списках против хранения в куче:
  8.  
  9. - запись в куче можно индексировать (будет массив), а список
  10. нельзя.
  11. ? first fit куча (очень медленная) заполняется на 85%, то есть
  12. для строк она выгоднее в 3.4 раза (но зато мы можем в списке
  13. хранить 16-битные строки), а для программ в 1.7 раза, чем
  14. список. buddy куча (среднемедленная) заполняется на 75%, то есть
  15. для строк она выгоднее в 3 раза (но зато мы можем в списке
  16. хранить 16-битные строки), а для программ в 1.5 раза, чем
  17. список. но эти числа для блоков 10-100 байт, а куча теряет много
  18. памяти на маленьких записях (ей нужно лишних 8 байт на запись).
  19. 4 элемента подряд (16 байт в куче, 16 байт в списке) или строку
  20. из 3 букв (12 байт в куче, 12 байт в списке, т.к. не нужен \0)
  21. выгоднее хранить в списке!
  22. + список выделяет и освобождает память за O(1), практически
  23. мгновенно.
  24. + список не имеет ограничений на длину выделяемого фрагмента, он
  25. выделится всегда, если есть свободная память. можно даже 100
  26. килобайт одним списком.
  27. + реализация списка на куче даст проигрыш в 3 раза (12 байт на
  28. элемент против 4).
  29. + реализация бинарного дерева на куче: 12 байт на узел
  30. (используя NIL), на списке: 4 байта на узел (используя NIL) -
  31. считаем, что листы хранятся отдельно, на них только указываем,
  32. иначе зависит от размера листа.
  33. + список можно увеличивать и уменьшать, а элемент кучи нельзя.
  34.  
  35. То есть не всё так плохо, единственная реальная проблема - как
  36. реализовать массив на списках.
  37.  
  38. а) перебором списка - O(i).
  39. б) сделать поверх списка список чётных элементов, поверх того
  40. тоже и т.д. - O(log(n)).
  41. в) добавить выделяемые блоки по 256 байт в качестве элементов
  42. списка? (хранить указатели на них и иметь операции
  43. индексирования.) память для списков можно сделать на этих
  44. блоках, их даже можно освобождать обратно (если иметь счётчик в
  45. каждом). для этого список свободных можно сделать двусвязным,
  46. тогда можно будет выключать пустые элементы блока и отдать 256
  47. байт.
  48. г) добавить ещё кучу? как делить память между списком и кучей?
  49. д) просто работать в памяти через POKE и PEEK.
  50.  
  51. Я выбрал последний вариант, но заложил в будущем возможность
  52. использовать 256-байтные блоки (для этого понадобилось сделать
  53. список свободных элементов двусвязным, чтобы можно было
  54. ликвидировать элементы в 256-байтном блоке, когда тот
  55. освободится).
  56.  
  57. В прошлый раз я написал далеко не весь код интерпретатора и
  58. обработчиков, к тому же, неотлаженный. Вообще минимальная среда
  59. исполнения включает:
  60.  
  61. - интерпретатор
  62. - арифметика (T, NIL, +, -...)
  63. - работа со списками (VALUE, NEXT, FORM...)
  64. - работа со стеком (DUP, DUP2(повторить 2 элемента), DROP, SWAP,
  65. OVER(повторить 2-й элемент), ROT(вынуть 3-й элемент)...)
  66. - работа с памятью (NEW, DEL...)
  67. - работа с переменными (NEWVAR, FINDVAR, =>, DEF, DEFUN,
  68. EVAL...)
  69. - работа с терминалом (ttypeek, ttyget (изначально работает из
  70. памяти, потом сработает патч, чтобы переключился на клавиатуру),
  71. ttyput...)
  72. - расшифровка и исполнение лиспотекста из терминала.
  73.  
  74. Остальное можно написать на самом Listh или постепенно добавлять
  75. ассемблерные обработчики.
  76. Можно редактор (расшифровку и исполнение команд) написать на
  77. самом Listh. Сначала я так и сделал, планируя набрать эти
  78. Listh-функции прямо в ассемблерном тексте (в виде
  79. последовательности dw:dw), но для этого нужно сразу реализовать
  80. структуры программы (IF, WHILE...). Поэтому я просто вручную
  81. скомпилировал нужные процедуры на ассемблер, а по мере
  82. надобности писал новые прямо на ассемблере.
  83.  
  84. Все лиспосписки (введённая команда, VarList, Prog) сделаны
  85. выводимыми. Для этого у них в начале лежит адрес LispList, в
  86. середине указатели на термы содержимого, а в конце указатель на
  87. терм EndLisp. Термы - тоже списки, в первом элементе у них адрес
  88. обработчика, во втором значение, а далее имя по одному символу
  89. (это относится и к числам - ведь их можно записать по-разному, а
  90. показывать надо именно в том виде, как ввели). Функция печати
  91. лиспосписков ttyputlist рекурсивно выводит все термы, у которых
  92. в первом элементе лежит адрес LispList (он не выводится, как и
  93. последний элемент). Эта функция может печатать и отдельный терм
  94. (у него первый элемент отличается от LispList). Голые списки
  95. чисел эта функция печатать не может, можно написать отдельную
  96. функцию для этого.
  97.  
  98. В процессе реализации пройдены следующие майлстоуны:
  99.  
  100. + работа с памятью (NEW, DEL), проверяем трассировкой
  101. + печать числа ttyputnum, проверяем вызовом из асма
  102. + печать строки ttyputstr, проверяем вызовом из асма
  103. + чтение вложенного лиспосписка (из известных элементов),
  104. проверяем работу strcmp асмовставками, проверяем, как легло в
  105. память (READTERM (READTERM) READTERM)
  106. + печать вложенного лиспосписка, проверяем, что он соответствует
  107. введённому (READTERM (VarList () readlist) READTERM)
  108. + интерпретация лиспосписка (VarList ttyputlist) - печать списка
  109. переменных, проверяем его
  110. + интерпретация лиспосписка (T T + T ttyputnum ttyputnum)
  111. + интерпретация вложенного лиспосписка (T - (T + T) DUP
  112. ttyputnum NOT ttyputnum)
  113. + чтение чисел (с автоматическим созданием константы, если такой
  114. ещё нет), проверяем на (13 + 13 ttyputnum VarList ttyputlist)
  115. + чтение строк (с автоматическим созданием константы, если такой
  116. ещё нет), проверяем на ("abc" ttyputstr VarList ttyputlist)
  117. + показ свободной памяти (FreeMem ttyputnum)=1A4C ("abc"
  118. ttyputstr VarList ttyputlist FreeMem ttyputnum)=1984
  119. + чистить найденное слово или ошибочное слово при вводе (чтобы
  120. не забивать память) (FreeMem ttyputnum)=1A44 ("abc" ttyputstr
  121. VarList ttyputlist FreeMem ttyputnum)=19E4
  122. + команда определения переменной (с занесением в исходник, в
  123. скобках начальное значение) (DEF "newvar" (15) VarList
  124. ttyputlist) или (DEF "newvar" (15 + 11) VarList ttyputlist)
  125. + печать исходника (список введённых команд-определений - в
  126. порядке их ввода) (DEF "newvar" (15) VarList ttyputlist Prog
  127. ttyputlist)
  128. + выполнение нескольких введённых строк (DEF "newvar" (15)
  129. VarList ttyputlist Prog ttyputlist FreeMem ttyputnum)(newvar
  130. ttyputnum)
  131. + команда определения функции (с занесением в исходник) (DEF
  132. "newvar" (15) DEFUN "newfun" (VarList ttyputlist Prog
  133. ttyputlist) FreeMem ttyputnum)(newvar ttyputnum newfun)
  134. + команда QUOTE (QUOTE (VarList ttyputlist Prog ttyputlist) DUP
  135. ttyputlist EVAL FreeMem ttyputnum)
  136. + при переопределении функции класть ссылку на неё не в начало,
  137. а в конец исходника, чтобы было всегда позже объявления
  138. используемых в ней переменных
  139. + команда копирования списка (QUOTE (VarList ttyputlist) FreeMem
  140. ttyputnum copylist FreeMem ttyputnum DUP ttyputlist dellist
  141. FreeMem ttyputnum)
  142. + команда удаления дерева (т.е. LispList со входящими LispList):
  143. (QUOTE (VarList (13) ttyputlist) FreeMem ttyputnum DUP
  144. ttyputlist deltree FreeMem ttyputnum)
  145. + команда копирования дерева (т.е. LispList со входящими
  146. LispList): (QUOTE (VarList (13) ttyputlist) FreeMem ttyputnum
  147. copytree FreeMem ttyputnum DUP ttyputlist deltree FreeMem
  148. ttyputnum)
  149. + ручной ввод (только в скобках, после закрывающей скобки ввести
  150. Enter), с эхом, при вводе неизвестного идентификатора сразу
  151. пишется ошибка, а в список попадает NIL
  152. + печать свободной памяти до ввода, после ввода и после
  153. исполнения команды
  154. + чтение символов (с автоматическим созданием константы, если
  155. такой ещё нет, пробел или кавычку нельзя), проверяем на ('A'
  156. ttyputnum VarList ttyputlist)
  157. + отрицательные числовые константы
  158. + очистка введённой команды (предварительно все новые слова из
  159. введённой команды копируются в VarList, а при DEF/DEFUN
  160. определения копируются в Prog)
  161.  
  162. В планах:
  163.  
  164. - команда удаления переменной/константы/функции из Prog и
  165. VarList (с проверкой использования?)
  166. - команда вывода исходника в файл (без внешних скобок, так что
  167. получится набор сравнительно коротких команд)
  168. - команда ввода исходников из файла
  169. - команда THEN (...) ELSE (...)
  170. - команда REPEAT (...) //UNTIL T
  171. - комментарии, ввод слова должен поддерживать пробелы в
  172. комментариях
  173. - эскейп-коды в строковых константах
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement