Я пишу свой первый синтаксический анализатор и имею несколько вопросов conerning токенизатор.
В основном мой токенизатор выставляет a nextToken()
функция, которая, как предполагается, возвращает следующий маркер. Эти маркеры отличает тип маркера. Я думаю, что имело бы смысл иметь следующие типы маркера:
<
, :=
, (
и т.п.Теперь, Вы думаете, что это имеет смысл?
Кроме того, я борюсь с NUMBER
тип маркера. Вы думаете, что имеет больше смысла далее разделять его на a NUMBER
и a FLOAT
тип маркера? Без a FLOAT
тип маркера, я получил бы NUMBER
(например, 402), a SYMBOL
(.) сопровождаемый другим NUMBER
(например, 203), если я собирался проанализировать плавание.
Наконец, что Вы думаете, имеет больше смысла для токенизатора возвращаться, когда он встречается с a -909
? Если это возвращается SYMBOL
-
во-первых, сопровождаемый NUMBER
909
или если это возвращает a NUMBER
-909
сразу же?
Это зависит от вашего целевого языка.
Смысл лексера - возвращать токены, которые упрощают написание синтаксического анализатора для вашего языка. Предположим, ваш лексер возвращает ЧИСЛО
, когда видит символ, соответствующий «[0-9] +». Если он видит нецелое число, например «3,1415926», он вернет ЧИСЛО
.
НОМЕР
. Хотя вы можете справиться с этим в своем синтаксическом анализаторе, если ваш лексер выполняет соответствующую работу по пропуску пробелов и комментариев (поскольку они не имеют отношения к вашему синтаксическому анализатору), вы можете в конечном итоге неправильно проанализировать такие вещи, как "123 / * comment " /. \ n / другой комментарий * / 456 "как числа с плавающей запятой.
Что касается лексирования "- [0-9] +" как НОМЕР
против МИНУС
НОМЕР
снова, это зависит от вашего целевого языка, но я обычно иду с МИНУС
НОМЕР
, иначе вы бы лексировали «A = 1-2-3-4» как СИМВОЛ
=
НОМЕР
НОМЕР
НОМЕР
НОМЕР
вместо СИМВОЛ
=
НОМЕР
МИНУС
НОМЕР
МИНУС
НОМЕР
МИНУС
НОМЕР
.
Пока мы обсуждаем эту тему, я настоятельно рекомендую книгу Шаблоны реализации языка , написанную Терренсом Парром, автором ANTLR .
Исходя из моего опыта работы с реальными лексерами:
"hello world"
является строковым литералом, проанализируйте его как одиночный токен. Если -3.058e18
является литералом с плавающей запятой, проанализируйте его также как отдельный токен. Лексеры обычно полагаются на регулярные выражения, которые достаточно выразительны для всего этого и многого другого. Конечно, если литералы достаточно сложные, у вас есть для их разделения (например, блочный литерал в Smalltalk). Думаю, что ответ на ваш вопрос строго привязан к семантике ЧИСЛА. Каким должен быть НОМЕР? Всегда положительное целое число, число с плавающей запятой ...
Я хотел бы предложить вам поискать инструменты flex и yacc (также известные как lex & bison) операционных систем U ** x: это мощные парсеры и генераторы сканеров. которые берут грамматику и выводят компилируемую и легко используемую программу.
Это зависит от того, как вы принимаете токены, если вы делаете это посимвольно, то это может быть немного сложно, но если вы делаете это слово за словом, т.е.
int a = a + 2.0
то токены будут (отбрасывая пробельные символы)
int
a
=
a
+
2.0
Таким образом, вы не столкнетесь с ситуацией, когда вы интерпретируете .
как лексему, а воспринимаете всю строку целиком - именно здесь вы можете определить, является ли она ПЛОСКОСТЬЮ, ЧИСЛОМ или чем угодно.
Лучше всего сделать так, чтобы типы ваших токенов были точно такими же, как терминальные символы вашей грамматики.
Не зная языка / грамматики, я полагаю, вам было бы лучше, если бы вы имели типы токенов для "LESS_THAN", "LESS_THAN_OR_EQUAL", а также "FLOAT", "DOUBLE", "INTEGER" и т. Д.