Разобрать строку с чтением и игнорированием пространств имен пакетов

Я пишу программу, которая открывает файл lisp, вызывает «чтение» в потоке до тех пор, пока поток не станет пустым, и выполняет действия со списками, которые он собирает.

Это работало довольно хорошо, пока я не обнаружил, что «чтение» будет выполнять поиск пакетов, например, если он встретит some-package:foo, он будет жаловаться, что Package SOME-PACKAGE does not exist.

Вот пример, показывающий, что я имею в виду:

(read (make-string-input-stream "(list 'foo :foo some-package:foo)"))

Так что теперь я хотел бы одну из трех вещей:

  1. Сделайте так, чтобы «чтение» игнорировало пространства имен пакетов, чтобы я мог преобразовывать произвольные исходные файлы в списки символов.
  2. Используйте другую библиотеку синтаксического анализа с аналогичным поведением для «чтения», но которая получает только простые символы, либо искажая :, либо игнорируя двоеточие и все, что предшествует ему.
  3. Предварительная обработка файла и использование регулярного выражения или подобного для поиска пакетов и замены их простыми именами, например, преобразование «some-package: foo» в просто «foo»

Целью всего этого в первую очередь было сделать граф зависимостей вызовов функций. Я знаю, что существуют вещи такого рода гораздо более высокого качества, но я хотел сделать это сам для развлечения/обучения. Однако я столкнулся с этой проблемой и не знаю, как действовать дальше.


person Robert Williams    schedule 03.11.2018    source источник
comment
случай 3 будет глючным - потому что имя пакета помогает различать конфликты имен (в случае, если ваш код использует функцию с тем же именем другого пакета), поэтому лучше изменить "some-package:foo" на "some-package-foo", не так ли? Однако тогда появится ошибка, если есть часть программы после (in-package some-package) ...   -  person Gwang-Jin Kim    schedule 03.11.2018
comment
стратегия, которой следует read, объясняется здесь cs .cmu.edu/Groups/AI/html/cltl/clm/node188.html   -  person Gwang-Jin Kim    schedule 03.11.2018
comment
если вы читаете norvig.com/lispy.html, вы видите, как сделать программу чтения lisp на python.. .   -  person Gwang-Jin Kim    schedule 03.11.2018
comment
как насчет того, чтобы разобрать все на строковые токены?   -  person Gwang-Jin Kim    schedule 03.11.2018


Ответы (2)


В вашем случае вы можете обработать состояние ошибки пакета, создав необходимый пакет и перезапустив его. Это также сохранит идентичность символов. Обратите внимание, что вам нужно обрабатывать in-package формы, когда вы сталкиваетесь с ними.

person Svante    schedule 03.11.2018

Самый простой ответ — сказать программе чтения Лиспа читать двоеточие #\: как есть:

(defun read-standalone-char (stream char)
  (declare (ignore stream))
  char)

(defun make-no-package-prefix-readtable (&optional (rt (copy-readtable)))
  "Return a readtable for reading while ignoring package prefixes."
  (set-syntax-from-char #\: #\Space rt)
  (set-macro-character #\: #'read-standalone-char nil rt)
  rt)

(let ((*readtable* (make-no-package-prefix-readtable)))
  (read-from-string "(list 'foo :foo some-package:foo)"))
==> (LIST 'FOO #\: FOO SOME-PACKAGE #\: FOO) ; 33

Очевидная проблема заключается в том, что это будет читать FOO:BAR и FOO :BAR одинаково, но вы можете обойти это.

person sds    schedule 05.11.2018
comment
Он мог бы сделать ':' составным символом с помощью (set-syntax-from-char #\A #\:), а затем найти символ ':' в строке, если требуется дальнейшая обработка. - person Leo; 05.11.2018
comment
@Leo: во-первых, у вас неправильный порядок аргументов в вызове set-syntax-from-char. Во-вторых, не работает, увы. - person sds; 05.11.2018