Я пытаюсь написать компилятор для языка COOL и сейчас занимаюсь лексическим анализом. Конкретно, Flex соответствует наибольшему шаблону, насколько я понимаю.
Таким образом, если у вас есть во Flex:
class A inherits B
Теперь, если мой токен для class
возвращается по следующей схеме:
^"class" return CLASS;
Для меня inherits
маркер:
^"class"[ ]+[a-zA-Z]+[0-9]?[ ]+"inherits"[ ]+ return INHERITS;
Теперь, когда flex соответствует наибольшему шаблону, он всегда будет возвращаться INHERITS
и никогда не класс. Есть ли решение этой проблемы?
Я могу здесь вернуть токен для class
в одиночестве. Но как мне вернуть токен для inherits
поскольку ему ДОЛЖЕН предшествовать class
токен и его имя, за которым следует еще один строковый токен?
Но если я попытаюсь наложить ограничения на inherits
, тогда flex будет соответствовать наибольшему шаблону, а не одному классу.
Тогда я должен возвращать перечисления / число для идентификатора класса индивидуально? И если я сделаю это, как я могу идентифицировать «наследует» идентификатор?
РЕДАКТИРОВАТЬ:
class A inherits B {
main(): SELF_TYPE{...}
}
Как соотносится гибкость с main
? Мой рефлексер различает TypeID, который A
а также main
, который он заявляет ObjectID
, Единственное, что он может сделать, — это смотреть вперед на парантез и, если он найдет (
, он объявляет ObjectID. Но если я сделаю это, я столкнусь с той же проблемой, что и выше: flex никогда не сравнится с (
но всегда main(
,
Вы пытаетесь сделать слишком много во Flex, и, возможно, вы неправильно понимаете роль и границы лексической фазы. Вы не должны пытаться анализировать предложение целиком с помощью одного регулярного выражения Flex. Работа Flex заключается в том, чтобы потреблять поток текста и преобразовывать его в поток целочисленных токенов. Предложение, которое вы предоставили:
class A inherits B
представляет несколько токенов из языка, который требует синтаксического анализа. Flex — это не парсер, это лексический сканер / токенизатор. (Технически это синтаксический анализатор байтов или символов, но вы хотите «анализировать» атомарные единицы, которые представляют слова вашего языка, а не символы).
Таким образом, есть 4 различных токена (атомные единицы), также известные как ТЕРМИНАЛЫ в вышеприведенном предложении: [КЛАСС, А, НАСЛЕДОВАНО, В].
Вам нужно правило IDENTIFIER для Flex, чтобы все, что не соответствует токену, перешло к IDENTIFIER, поэтому токены, возвращаемые Flex анализатору:
CLASS IDENTIFIER INHERITS IDENTIFIER
Работа для Flex состоит в том, чтобы анализировать каждое слово / токен и преобразовывать текст в различные целочисленные значения для использования Bison или любым другим анализатором.
У вас обычно есть грамматика Yacc / Bison BNF для обработки:
class_decl:
CLASS IDENTIFIER
| CLASS IDENTIFIER INHERITS IDENTIFIER
;
Таким образом, ваше правило Lex будет таким, и вам нужно вернуть токен IDENTIFIER в анализатор, при этом прикрепив реальный символ (A, B). Вы получаете это из переменной yytext:
LETTER [a-zA-Z_]
DIGIT [0-9]
LETTERDIGIT [a-zA-Z0-9_]
%%
"class" return(CLASS);
"inherits" return(INHERITS);
{LETTER}{LETTERDIGIT}* {
yylval.sym = new Symbol(yytext);
yylval.sym->line = line;
fprintf(stderr, "TOKEN IDENTIFIER(%s)\n", yytext);
return(IDENTIFIER);
}
Если вы действительно пытаетесь сделать все это во Flex, то это возможно, но вы получите беспорядок, например, если вы попытаетесь проанализировать HTML с помощью регулярных выражений … 🙂