Чтобы ответить на вопрос в том виде, в котором он был задан (без чрезмерного повторения того, что появляется в других ответах)
Лексеры и парсеры не сильно отличаются, как предполагает принятый ответ. Оба основаны на простых языковых формализмах: обычные языки для лексеров и, почти всегда, контекстно-свободные (CF) языки для синтаксических анализаторов. Обе они связаны с довольно простыми вычислительными моделями, автоматом конечных состояний и автоматом стека. Регулярные языки - это особый случай контекстно-свободных языков, так что лексеры могут быть созданы с использованием несколько более сложной технологии CF. Но это не очень хорошая идея, по крайней мере, по двум причинам.
Фундаментальный момент в программировании заключается в том, что системный компонент должен быть оснащен самой подходящей технологией, чтобы его было легко создавать, понимать и поддерживать. Технология не должна быть излишней (с использованием методов, намного более сложных и дорогостоящих, чем необходимо), и не должна быть на пределе своих возможностей, поэтому требуются технические искажения для достижения желаемой цели.
Вот почему «Кажется модным ненавидеть регулярные выражения». Хотя они могут многое сделать, им иногда требуется очень нечитаемое кодирование для достижения этого, не говоря уже о том, что различные расширения и ограничения в реализации несколько снижают их теоретическую простоту. Обычно лексеры этого не делают и обычно представляют собой простую, эффективную и подходящую технологию для анализа токена. Использование парсера CF для токена было бы излишним, хотя это возможно.
Другая причина не использовать формализм CF для лексеров заключается в том, что может возникнуть соблазн использовать всю мощь CF. Но это может вызвать серьезные проблемы с чтением программ.
По сути, большая часть структуры программного текста, из которой извлекается значение, представляет собой древовидную структуру. Он выражает, как предложение синтаксического анализа (программа) генерируется из правил синтаксиса. Семантика получена композиционными методами (гомоморфизм для математически ориентированных) из способа составления синтаксических правил для построения дерева разбора. Следовательно, древовидная структура имеет важное значение. Тот факт, что токены отождествляются с лексером на основе регулярного набора, не меняет ситуацию, потому что CF, составленный из регулярного, все еще дает CF (я говорю очень свободно о регулярных преобразователях, которые преобразуют поток символов в поток токенов).
Однако CF, составленный из CF (через преобразователи CF ... извините за математику), не обязательно дает CF, и может сделать вещи более общими, но менее понятными на практике. Таким образом, CF не подходит для лексеров, хотя его можно использовать.
Одно из основных различий между обычным и CF состоит в том, что обычные языки (и преобразователи) очень хорошо сочетаются практически с любым формализмом различными способами, в то время как языки CF (и преобразователи) этого не делают, даже с самими собой (за некоторыми исключениями).
(Обратите внимание, что обычные преобразователи могут иметь другое применение, например, формализацию некоторых методов обработки синтаксических ошибок.)
BNF - это просто особый синтаксис для представления грамматик CF.
EBNF является синтаксическим сахаром для BNF , использующим средства регулярного обозначения, чтобы дать более краткую версию грамматик BNF. Он всегда может быть преобразован в эквивалентный чистый БНФ.
Тем не менее, регулярные обозначения часто используются в EBNF только для того, чтобы подчеркнуть эти части синтаксиса, которые соответствуют структуре лексических элементов, и должны быть распознаны с помощью лексера, тогда как остальные должны быть скорее представлены в прямой BNF. Но это не абсолютное правило.
Подводя итог, можно сказать, что более простая структура токена лучше анализируется с помощью более простой технологии обычных языков, в то время как древовидная структура языка (синтаксиса программы) лучше обрабатывается грамматиками CF.
Я бы предложил также посмотреть на ответ AHR .
Но это оставляет открытым вопрос: почему деревья?
Деревья являются хорошей основой для определения синтаксиса, потому что
они дают простую структуру тексту
Есть очень удобно связывать семантику с текстом на основе этой структуры с помощью математически хорошо понятной технологии (композиционность через гомоморфизмы), как указано выше. Это фундаментальный алгебраический инструмент для определения семантики математических формализмов.
Следовательно, это хорошее промежуточное представление, о чем свидетельствует успех абстрактных синтаксических деревьев (AST). Обратите внимание, что AST часто отличаются от дерева разбора, потому что технология синтаксического анализа, используемая многими профессионалами (такими как LL или LR), применяется только к подмножеству грамматик CF, таким образом, вызывая грамматические искажения, которые впоследствии исправляются в AST. Этого можно избежать с помощью более общей технологии синтаксического анализа (основанной на динамическом программировании), которая принимает любую грамматику CF.
Утверждение о том, что языки программирования являются контекстно-зависимыми (CS), а не CF, являются произвольными и спорными.
Проблема в том, что разделение синтаксиса и семантики является произвольным. Проверка объявлений или соглашения о типе может рассматриваться как часть синтаксиса или как часть семантики. То же самое относится и к гендерному и числовому соглашению на естественных языках. Но существуют естественные языки, где множественное число зависит от фактического семантического значения слов, так что оно не вписывается в синтаксис.
Многие определения языков программирования в денотационной семантике помещают объявления и проверку типов в семантику. Заявление Ира Бакстера о том, что парсеры CF взламываются, чтобы получить контекстную чувствительность, требуемую синтаксисом, в лучшем случае - произвольный взгляд на ситуацию. Это может быть организовано как взломать в некоторых компиляторах, но это не обязательно.
Также дело не только в том, что парсеры CS (в том смысле, в каком они здесь используются в других ответах) сложны и менее эффективны. Они также неадекватны для того, чтобы явно выразить вид контекстной чувствительности, который может потребоваться. И они, естественно, не создают синтаксическую структуру (такую как деревья разбора), которая удобна для получения семантики программы, то есть для генерации скомпилированного кода.