Здравствуйте, Marty, Вы писали:
M>Это вообще не проблема. Цепочка символов же одна? Значит, и айди будет один, просто в зависимости от контекста по разному будет обрабатываться.
Если в одном контексте a --i означает "вызвать функцию a с аргументом декремент от i", а в другом — "вычесть результат применения унарного минуса к i из a", то лексер не может оперировать лексемой "minusminus".
Он должен порождать две лексемы minus. Это делает смысл лексера эфемерным, потому что нафига он такой нужен? Проще сразу писать парсер.
Композитная лексема — просто очередной нетерминал. Прекрасно работает для контекстно-специфичных ключевых слов. Те же get и set в C#, которые являются ключевыми словами исключительно внутри property definition.
M>У меня, кстати, есть обратная связь, я её обдумывал, когда вспоминал о проблеме >> vs > и > в плюсовых шаблонах.
Я верю, что вы придумали, что с этим делать. С моей точки зрения, это ненужная сложность. Вот вам лексер зачем, собственно, нужен?
M>У меня задумывается как универсальное средство: 1) для разбора сорцов и построения AST, с выдачей диагностических сообщений с указанием места ошибки/предупреждения — в этом варианте доп нагрузку на токенах можно дропать, когда она больше не требуется; 2) хочется иметь возможность репарсинга с определенной позиции, для реализации хотя бы подсветки синтаксиса в редакторе
Ну вот PEG как раз репарсинг прекрасно автоматизирует, т.к. в нём не нужно думать о том, как получить корректный поток лексем для нового представления. Там всего один кэш с простой стратегией вытеснения.
Идеального решения я пока так и не нашёл, но PEG ближе всего к тому, что мне нужно. Судя по всему, я в ближайшем будущем посажу дипломников пилить нормальный фреймворк, а то, скажем, инкрементальный ohm-js сделан крайне странно в плане семантических действий; и в нём нет error autorecovery. При этом статьи про доработку PEG для восстановления после неудачного парсинга есть — надо просто перенести их к продакшн.
С подсветкой синтаксиса всё нетривиально.
Та же VS Code сдалась; в ней красить синтаксис парсером считается неэффективным. Применяют двухуровневую раскраску — основа красится движком на основе регекспов, а парсеру оставляют семантическую раскраску, которой должно быть мало по сравнению с синтаксической. Типа там покрасить в жёлтый переменные функционального типа, затенить константы или недостижимый код, и прочие мелочи.
Но это заставляет решать задачу разбора минимум дважды — один раз грамматикой, второй раз регекспами; особенно бесит при работе над нестабилизированным языком, где синтаксис, грамматика и семантика правятся по нескольку раз в неделю.
А по-другому получается плохо, т.к. проблема курицы и яйца. Чтобы понять, насколько проектируемый язык удобен и хорош, нужно написать на нём приличный корпус текстов. Писать тексты без IDE Assistance крайне утомительно.
Поэтому примеров выходит мало, и на их основе трудно сделать какие-то выводы.
В идеале хочется иметь возможность в наскетчить язык в несколько десятков строчек, и сразу получить все плюшки вроде онлайн диагностики и раскраски синтаксиса; и при этом ещё иметь возможность резко сказать "ой, что-то у нас фигня выходит, давайте теперь переходы будут не просто "номер метки", а goto <labelName>, а labelName — это не номер, а строка, начинающаяся с $. И получить новый extension сразу после перекомпиляции, а не после трёхдневного переписывания лексера, парсера, и textMate раскрасчика синтаксиса.
Как устроена подсветка в настоящей VS, я не в курсе — но явно лучше, чем в VS Code, т.к. последняя красит тот же C# значительно хуже.
Подозреваю, что там какой-то хардкор, трудновоспроизводимый в домашних условиях.
M>Как минимум, номер строки тоже надо хранить
Это всё легко пересчитывать туда-обратно по мере необходимости. Хранить ли позицию в виде "строка/колонка" или просто в виде индекса в строке — дело вкуса.
Уйдемте отсюда, Румата! У вас слишком богатые погреба.