Теория синтаксического разбора и синтаксиса

Я пытаюсь понять, как я должен реализовать подсветку синтаксиса Live при обработке очень большой строки. Я совершенно смущен. Это то, что я знаю:

(Предположим, что у меня есть функция parsedString parseString(rawString))

  • Вызовите parseString(entireText) и замените текущую строку возвращаемой обработанной (и стилизованной и т.д.) строкой при каждом изменении текста. Это плохой подход при обработке больших данных.

  • Кто-то предложил проанализировать отредактированный диапазон и заменить текущую необработанную отредактированную строку на синтаксическую строку parseString(editedRange).

Метод (1) достаточно ясен. Я не могу понять (2). При вводе для каждого символа, добавленного в строку, уведомление запускается, и один символ обрабатывается (и возвращается как есть).

Например, если я хочу красных селекторов при анализе файла .css, как я могу понять, когда есть готовый селектор, за которым следует {, который должен быть окрашен? Я предполагаю, что есть какой-то способ отсрочить разбор, пока не появится совпадение. Как вы это реализуете?

Я не ищу рабочего приложения. Хорошее объяснение было бы полезно также.

Спасибо заранее.

Ответы

Ответ 1

Для повторного анализа инкрементных изменений вам понадобится API нижнего уровня для вашего анализатора.

У анализатора есть состояние, которое изменяется при его обработке. Например, сначала синтаксический анализатор может пропускать пробелы, теперь он может читать число, позже это может быть создание абстрактного синтаксического дерева для выражения. Если вы могли бы сделать снимок всей информации о состоянии парсера в промежуточных точках ввода, то вы можете повторить инкрементное изменение, начиная с последней вехи перед изменением (и, возможно, останавливаясь раньше, если состояние идентично на рубеже, превышающем изменить).

Для простого выделения синтаксиса, как это делают многие программисты, это подход. Выделение синтаксиса требует немного больше, чем токенизация, поэтому захвата не так много. И многие языки программирования имеют множество возможностей для этапов, например, в начале новой строки. В таких случаях вам может даже не понадобиться фактически сохранять состояние парсера, поскольку вы, возможно, знаете, что оно всегда одно и то же в начале строки.

Итак, вам нужен API:

parsedString parseIncrementally(parserState, rawString);