Попытка построить С# грамматику для bison/wisent
Я никогда раньше не делал Bison или Wisent.
как я могу начать?
Моя реальная цель - создать рабочую грамматику Wisent/Semantic для С#, чтобы разрешить редактирование С# в emacs с завершением кода, а все остальные CEDET. (Для тех, кто не знает, Wisent - это порт emacs- lisp GNU Bison, который включен в CEDET. The Wisent, по-видимому, является европейским бизоном. И, как я понимаю, Bison - это игра-на-словах, происходящие из YACC И CEDET - это сборник Emacs Development Tools. Все догнал? Я не буду пытаться определить emacs.)
Microsoft предоставляет грамматику BNF для С#, включая все расширения LINQ, в справочном документе по языку. Я смог перевести это в .wy файл, который успешно компилируется с помощью semantic-grammar-create-package
.
Но скомпилированная грамматика не работает. В некоторых случаях грамматика "находит" enum
объявления, но не объявления class
. Зачем? Я не знаю. Я не смог распознать атрибуты.
Я не считаю, что "отладка" грамматики очень проста.
Я думал, что я сделаю шаг назад и попытаюсь создать разумную грамматику для гораздо более простого языка, игрушечного языка с несколькими ключевыми словами. Просто чтобы получить некоторый опыт. Даже это доказывает сложность.
Я видел документы .info на грамматике fw и wisent, но... все же эти вещи не совсем разъясняют мне, как материал действительно работает.
Итак,
Q1: какие-либо советы по отладке разумной грамматики в emacs? Есть ли способ запустить "грамматику" в стиле "ворсинок", чтобы узнать, есть ли неиспользованные правила, такие тупики? Как насчет возможности наблюдать за парсером в действии? Что-нибудь подобное?
Q2: Какие-нибудь подсказки о том, чтобы приступить к скорости на bison/wisent вообще? Я думаю, что это инструмент, который позволит мне получить представление о том, как работают правила. Что-то, что обеспечивает некоторую прозрачность, вместо опыта "это не работает", я получаю сейчас с Wisent.
Q3: вместо того, чтобы продолжать бороться с этим, я должен отказаться и стать органическим фермером?
ps: Я знаю о существующей грамматике С# в каталоге contrib CEDET/semantic. Эта вещь работает, но... Она не поддерживает последнюю спецификацию С#, включая LINQ, частичные классы и методы, доходность, анонимные методы, инициализаторы объектов и т.д. Также он в основном воспроизводит партию кода С#. Он вынюхивает классы и методы, а затем выручает. Даже петли foreach сделаны не совсем правильно. Это хорошо, насколько это возможно, но я бы хотел, чтобы это было лучше. То, что я пытаюсь сделать, это сделать его текущим, а также расширить его, чтобы проанализировать больше кода С#.
Ответы
Ответ 1
Вы можете посмотреть пример calc в семантической/wisent-директории. Это довольно просто, а также показывает, как использовать% left и% right. Он будет "исполнять" код, а не конвертировать его в теги. Некоторые другие простые грамматики включают "точечный" синтаксический анализатор в cogre и парсер srecode в srecode.
Для разумной отладки в меню есть флаг вербности, хотя, честно говоря, я не пробовал. Существует также wisent-debug-on-entry, который позволяет вам выбрать действие, которое заставит отладчик Emacs остановиться в этом действии, чтобы вы могли видеть, что это за значения.
У более старого "бычьего" парсера есть режим отладки, который позволяет вам пройти через правила, но он никогда не был перенесен на wisent. Это особенность, которую я очень пропустил, когда пишу убедительные парсеры.
Ответ 2
Что касается Q1:
1-й убедитесь, что на самом деле используется wisent parser:
(fetch-overload 'semantic-parse-stream)
должен возвращать wisent-parse-stream
.
Запустите следующий фрагмент эскиза:
(easy-menu-add-item semantic-mode-map '(menu-bar cedet-menu) ["Wisent-Debug" wisent-debug-toggle :style toggle :selected (wisent-debug-active)])
(defun wisent-debug-active ()
"Return non-nil if wisent debugging is active."
(assoc 'wisent-parse-action-debug (ad-get-advice-info-field 'wisent-parse-action 'after)))
(defun wisent-debug-toggle ()
"Install debugging of wisent-parser"
(interactive)
(if (wisent-debug-active)
(ad-unadvise 'wisent-parse-action)
(defadvice wisent-parse-action (after wisent-parse-action-debug activate)
(princ (format "\ntoken:%S;\nactionList:%S;\nreturn:%S\n"
(eval i)
(eval al)
(eval ad-return-value)) (get-buffer-create "*wisent-debug*"))))
(let ((fileName (locate-file "semantic/wisent/wisent" load-path '(".el" ".el.gz")))
fct found)
(if fileName
(with-current-buffer (find-file-noselect fileName)
(goto-char (point-max))
(while (progn
(backward-list)
(setq fct (sexp-at-point))
(null
(or
(bobp)
(and
(listp fct)
(eq 'defun (car fct))
(setq found (eq 'wisent-parse (cadr fct))))))))
(if found
(eval fct)
(error "Did not find wisent-parse.")))
(error "Source file for semantic/wisent/wisent not found.")
)))
Он создает новую запись Wisent-Debug в меню "Разработка". Щелчок по этой записи позволяет отладить отладку синтаксического анализатора. В следующий раз, когда вы перепрофилируете буфер с помощью wisent-parser, он выводит информацию об отладке в буфер * wisent debug *. Буфер * wisent debug * не отображается автоматически, но вы найдете его через буферное меню.
Чтобы избежать наводнения * wisent debug *, вы должны отключить "Reparse when idle".
Время от времени вы снимаете очистку буфера * wisent debug * с помощью erase-buffer.