Я пишу лексер для Markdown.В процессе я понял, что не до конца понимаю, какова должна быть его основная ответственность.
Наиболее распространенное определение лексера заключается в том, что он преобразует входной поток символов в выходнойпоток токенов .
Input → Output
(characters) (tokens)
Поначалу это звучит довольно просто, но возникает вопрос: насколько семантическая интерпретация Лексер должен это сделать, прежде чем передать свои выходные данные токенов парсеру.
Возьмите этот пример синтаксиса Markdown:
### Headline
*This* is an emphasized word.
Он может быть переведен лексером в следующие сериииз токенов:
Вывод Lexer 1
.headline("Headline")
.emphasis("This")
.text"(" is an emphasized word.")
Но он также может быть переведен на более детальный уровень, в зависимости от используемой грамматики (или набора лексем):
Вывод Lexer 2
.controlSymbol("#")
.controlSymbol("#")
.controlSymbol("#")
.text(" Headline")
.controlSymbol("*")
.text("This")
.controlSymbol("*")
.text"(" is an emphasized word.")
Кажется, гораздо более практично, чтобы лексер выдавал вывод, аналогичный выводу Lexer 1 , потому что парсер будет тогда выполнять более легкую работу,Но это также означает, что лексеру нужно семантически понять , что означает код.Это не просто сопоставление последовательности символов токену.Нужно смотреть в будущее и выявлять закономерности.(Например, он должен уметь различать **Hey* you*
и **Hey** you
. Он не может просто перевести двойную звездочку **
в .openingEmphasis
, поскольку это зависит от следующего контекста.)
Согласно этой записи Stackoverflow и определению CommonMark , кажется, имеет смысл сначала разбить вход Markdown на несколько блоков (представляющих одну или несколько строк) изатем проанализируйте содержимое каждого блока на втором этапе.В приведенном выше примере это будет означать следующее:
.headlineBlock("Headline")
.paragraphBlock("*This* is an emphasized word.")
Но это не будет считаться допустимой последовательностью токенов, потому что некоторые лексемы ("*") еще не были проанализированы, и этоПравильно передать это paragraphBlock
парсеру.
Так вот мой вопрос:
Где вы рисуете линию?
Сколько семантикиработу должен делать лексер?Есть ли какое-то сложное определение лексера, о котором я не знаю?
Как лучше всего определить грамматику для лексера?