#parsing #architecture #syntax-highlighting #language-design #code-completion
#синтаксический анализ #архитектура #синтаксис-выделение #язык-дизайн #код-завершение
Вопрос:
В течение некоторого времени я думал о разработке небольшого игрушечного языка с нуля, ничего, что будет «править миром», но в основном в качестве упражнения. Я понимаю, что для достижения этой цели нужно многому научиться.
Этот вопрос касается трех разных концепций (синтаксический анализ, выделение кода и завершение), которые кажутся мне чрезвычайно похожими. Конечно, синтаксический анализ и ASTgen являются частью компиляции, в то время как выделение и завершение кода — это скорее особенность IDE, но мне интересно, в чем сходства и различия.
Мне нужны некоторые подсказки от кого-то более опытного в этой теме. Какой код может быть общим для этих концепций и каковы соображения архитектуры, которые могли бы помочь в этом смысле?
Ответ №1:
Что вам нужно, так это редактор структур, ориентированный на синтаксис. Это тот, который сочетает синтаксический анализ с построением AST и использует анализатор для прогнозирования того, что вы можете ввести следующим (либо завершение синтаксиса), либо имеет привязку к последнему запуску компилятора, так что он может интерпретировать точку редактирования, чтобы увидеть, какие допустимые идентификаторы могут появиться следующими, путем проверки таблицы символов компилятора, которая была последней актуальной на данный момент в коде.
Самая сложная часть — предложить пользователю беспрепятственный доступ; она в значительной степени должна верить, что редактирует текст, или (опыт работы со структурными редакторами показывает) она отвергнет это как неудобное.
Это требует много механизмов для координации и довольно больших усилий. Хорошей новостью является то, что вам в любом случае нужен синтаксический анализатор для компилятора; если редактирование также выполняет синтаксический анализ, AST, необходимый компилятору, по существу, доступен. (Конечно, вам также нужно беспокоиться о пакетной компиляции). Компилятор должен создать таблицу символов; так что вы можете использовать это в процессе завершения редактирования. Более сложная новость заключается в том, что синтаксические анализаторы намного сложнее создавать; они не могут просто объявить видимую пользователем синтаксическую ошибку и завершить работу; скорее, они должны быть терпимы к ряду ошибок, существующих в один и тот же момент, сохранять частичные значения для фрагментов и объединять их по мере удаления ошибок пользователем.
Сотрудники Berkeley Harmonia проделывают хорошую работу в этой области. Вам стоит прочитать некоторые из их статей, чтобы получить подробное представление о проблемах и одном подходе к их решению.
Другой важный подход, который, похоже, пытаются использовать разработчики (в частности, преднамеренного программирования и XText), — это объектно-ориентированные редакторы, где вы привязываете действия редактирования к каждому узлу AST и связываете каждую точку на экране с узлом AST. Затем действия редактирования вызывают действия, специфичные для AST-узла (вставить символ, повернуть направо, подняться …), и он может решить, как действовать и как изменить экран. Возможно, вы можете заставить эти редакторы делать что угодно; на практике это немного сложнее. Я использовал эти редакторы; они не похожи на текстовые редакторы. Есть несколько пользователей-энтузиастов, но YMMV.
Я думаю, вам, вероятно, следует выбирать между попыткой создать такой редактор или попыткой определить новый язык. Выполнение обоих сразу, скорее всего, приведет к возникновению проблем.
Комментарии:
1. Спасибо за ответ. Хотя вы предоставляете несколько ценных ссылок, я все еще упускаю из виду некоторые различия, о которых вы упоминаете, между анализатором в компиляторе и анализатором в IDE. Например, я представляю анализатор в IDE как некоторую функцию всего кода текущая строка -> возможные доработки, которая уже присутствует в некоторых компиляторах (например, gcc предлагает альтернативы, когда вы предоставляете функции неправильные типы аргументов).
2. Анализатор IDE должен «делать больше», чем анализатор компилятора, в том смысле (как вы отметили), что ему нужно знать, что является законным следующим (как это делает компилятор) и что является вероятным следующим (о чем компилятор обычно вообще не заботится). «Вероятный» основан на контексте всего приложения; в основном это данные таблицы символов, созданные компилятором и, возможно, обновляемые IDE по мере использования. (GCC, предоставляющий вам альтернативы, на самом деле выполняет этот «вероятный» вид диагностики. Конечно, это полезно, именно поэтому вы хотели, чтобы это было и в IDE 🙂