Ищете четкое определение того, что такое «токенизатор», «парсер» и «лексеры» и как они связаны друг с другом и используются?

151

Я ищу четкое определение того, что такое «токенизатор», «парсер» и «лексер» и как они связаны друг с другом (например, использует ли парсер токенизатор или наоборот)? Мне нужно, чтобы программа прошла через исходные файлы c / h для извлечения декларации данных и определений.

Я искал примеры и могу найти некоторую информацию, но я действительно изо всех сил пытался понять основные понятия, такие как грамматические правила, деревья синтаксического анализа и абстрактное синтаксическое дерево и как они взаимосвязаны друг с другом. В конечном итоге эти концепции необходимо сохранить в реальной программе, но 1) как они выглядят, 2) существуют ли общие реализации.

Я смотрел на Википедию по этим темам и программам, таким как Lex и Yacc, но никогда не изучая класс компиляторов (EE Major), мне трудно полностью понять, что происходит.

lordhog
источник

Ответы:

166

Токенайзер разбивает поток текста на токены, обычно путем поиска пробелов (табуляции, пробелов, новых строк).

Лексер по сути является токенизатором, но обычно он придает дополнительный токен токенам - этот токен является числом, этот токен является строковым литералом, этот другой токен является оператором равенства.

Парсер берет поток токенов из лексера и превращает его в абстрактное синтаксическое дерево, представляющее (обычно) программу, представленную в исходном тексте.

В последний раз я проверял, что лучшей книгой на эту тему была «Компиляторы: принципы, методы и инструменты», обычно известная как «Книга Дракона».

Роджер Липскомб
источник
8
Без сомнения, «Книга Дракона» - хорошая книга, но она требует от читателя хорошего знания основ CS. Некоторая книга с более практической привлекательностью будет «Написание компиляторов и интерпретаторов» Рональда Мак, «Реализация современных компиляторов», Эндрю Аппель; «Компилятор Констракшн», Никлаус Вирт; «Компиляция с C # и Java» и «Компиляторы и генераторы компиляторов: введение в C ++» Пэта Терри; и, конечно же, «Полное руководство ANTLR» Терренса Парра.
Андре Артус
5
Просто чтобы быть уверенным, я не сбиваю вашу рекомендацию. «Книга Дракона» была моей первой книгой о технологиях компиляции, но она была трудновыполнимой по сравнению, скажем, с книгой Вирта, которую вы можете купить за несколько часов. В то время у меня было мало вариантов, так как это была единственная книга, которую я мог достать (это был 1991 год, до Amazon и WWW). У меня было это и коллекция текстовых файлов, созданных Джеком У. Креншоу, под названием «ДАВАЙТЕ СТРОИТЬ КОМПИЛЯТОР» (спасибо, Джек!). Это все еще книга для более полного понимания принципов, но большинству программистов просто нужно прагматичное введение.
Андре Артус
10
Я не согласен с тем, что синтаксический анализатор / по определению / создает абстрактное синтаксическое дерево. Парсеры могут производить всевозможные выходные данные. Например, распространенным явлением является то, что анализатор генерирует последовательность вызовов некоторого интерфейса построителя - см. Шаблон построителя в книге «Банды четырех». Ключевым моментом является то, что синтаксический анализатор анализирует последовательность токенов, чтобы определить, соответствует ли последовательность какой-либо (обычно контекстно-свободной) грамматике и может выдавать некоторый вывод на основе грамматической структуры последовательности.
Теодор Норвелл
2
«Давайте построим компилятор» находится здесь: compilers.iecc.com/crenshaw . Я нашел ссылку отсюда: prog21.dadgum.com/30.html
Роджер Липскомб
1
@Pithkos: если это единственные ограничения, все, что вы сказали, это то, что функция принимает входные данные в одной безымянной (математической) области и производит и выводит данные в другой неименованной области, например, F (X) -> Y Вы можете только назвать это «функцией». Если вы настаиваете, что доменом X является <StreamOfCharacter, Grammar>, а доменом Y является Tree со свойством, которое отражает форму грамматики, то F (X, G) -> T будет чем-то, что я бы назвал синтаксический анализатор. Часто мы каррируем F относительно G, потому что G не часто меняется, поэтому F [G] (X) -> T - это то, что вы обычно видите как синтаксический анализатор.
Ира Бакстер
18

Пример:

int x = 1;

Лексер или токенизер разделит это на токены 'int', 'x', '=', '1', ';'.

Парсер возьмет эти токены и использует их для некоторого понимания:

  • у нас есть заявление
  • это определение целого числа
  • целое число называется «х»
  • 'x' должен быть инициализирован значением 1
Гра
источник
9
Лексер заметит, что "int", "=" и ";" являются токенами без дальнейшего значения, что «x» является именем идентификатора или чего-либо, значение «x», и «1» является целым числом или числом, значение «1». Токенизатор не обязательно сделает это.
Дэвид Торнли
5

Я бы сказал, что лексер и токенизатор - это одно и то же, и они разбивают текст на составляющие его части («токены»). Затем парсер интерпретирует токены с помощью грамматики.

Я бы не стал слишком зацикливаться на точном терминологическом использовании - люди часто используют «разбор», чтобы описать любое действие по интерпретации кусочка текста.

Уилл Дин
источник
1
С PEG-парсерами различие между токенизатором и парсером еще менее ясно.
Андре Артус
0

( добавление к данным ответам )

  • Tokenizer также удалит любые комментарии и вернет токены только Lexer.
  • Lexer также определит области действия для этих токенов (переменных / функций)
  • Затем Parser создаст структуру кода / программы
MCHA
источник
1
Здравствуйте @downvoter, не могли бы вы рассказать, почему вы на самом деле сделали downvote?
Корай Тугай
1
Я не отрицатель, но я думаю, что отрицательный голос, возможно, был, потому что ваш ответ не кажется правильным. Токенайзер может убрать шум (как правило, пробелы, но, возможно, и комментарии), но он часто не питает лексера. Основанный на DFA лексер будет токенизировать и идентифицировать, что такое токены (например, число, строка, идентификатор, а также пробел или комментарий), но он не может охватить их, так как для этого потребуется синтаксическое дерево, которое позже будет построено парсер.
Лусеро
1) Я не понимаю вашего различения между «лексером» и «токенизатором». Я создал парсеры для 50+ языков, и у меня никогда не было двух отдельных механизмов, которые разбивают исходный текст на атомы, поэтому для меня это просто синонимы. 2) Если вы компилируете, удаление комментариев и пробелов имеет смысл в лексере. Если вы создаете инструменты преобразования источника в источник, вы не можете потерять комментарии, потому что они должны появиться в преобразованном тексте. Так что ВСЕГДА удалять комментарии - это неправильно; мы можем спорить о том, как удается сохранить пустое пространство. ...
Ира Бакстер
1
... [Инструменты, которые я создаю (см. Мою биографию), фиксируют оба с достаточной точностью, чтобы воспроизвести их в преобразованном коде; мы идем дальше и фиксируем формат атомов, включая странные вещи, такие как кавычки, используемые в символьных строках, и счётчик радиуса / начального нуля для чисел, все это помогает избежать отклонения пользователем преобразованного результата. То, что вы пропустили, это не только то, что лексеры не обязательно отбрасывают информацию, но на самом деле им может понадобиться собирать информацию сверх необработанного токена]. ....
Ира Бакстер
... 3) Лексеры определяют «области видимости» только в безнадежно неуклюжих парсерах, которым трудно справляться с синтаксическими неясностями. Синтаксические анализаторы C и C ++ являются каноническим примером; см. мое обсуждение на stackoverflow.com/a/1004737/120163 ). Не нужно делать это (безобразно). Поэтому я нахожу ваш ответ просто ошибочным.
Ира Бакстер