Настройка контекста
Синтаксический анализ (чтобы проверить, соответствует ли входной текст указанной грамматике) состоит из двух фаз:
- токенизация, которая выполняется такими инструментами, как lex или flex, с интерфейсом yylex ()) и
- парсинг потока токена, сгенерированного на шаге 1 (согласно пользовательской грамматике), что выполняется такими инструментами, как bison / yacc с интерфейсом yyparse ()).
При выполнении фаза 1 при заданном входном потоке при каждом вызове yylex () идентифицируется токен (строка char), а yytext указывает на первый символ этой строки. Например: при вводе поток "int x = 10;" и с помощью правил lex для токенизации, соответствующей языку C, первые 5 вызовов yylex () идентифицируют следующие 5 токенов "int", "x", "=", "10", ";" и каждый раз yytext будет указывать на первый символ возвращаемого токена.
Фаза 2 , Парсер (который вы упомянули как yacc) - это программа, которая каждый раз вызывает эту функцию yylex для получения токена и использует эти токены, чтобы проверить, соответствует ли она правилам грамматика. Эти вызовы yylex будут возвращать токены в виде некоторых целочисленных кодов. Например, в предыдущем примере первые 5 вызовов yylex () могут возвращать в синтаксический анализатор следующие целые числа: TYPE, ID, EQ_OPERATOR и INTEGER (чьи фактические целочисленные значения определены в некотором заголовочном файле).
Теперь все, что видит анализатор, это те целочисленные коды, которые иногда могут оказаться бесполезными. Например, в работающем примере вы можете связать TYPE с int, ID с некоторым указателем на таблицу символов и INTEGER с десятичным 10. Для этого каждый токен, возвращаемый yylex, связан с другим значением VALUE, типом по умолчанию которого является int, но у вас могут быть пользовательские типы для этого. В среде lex к этому VALUE обращаются как yylval.
Например, снова в соответствии с текущим примером, yylex может иметь следующее правило для идентификации 10
[0-9]+ { yylval.intval = atoi(yytext); return INTEGER; }
и следующие для идентификации х
[a-zA-Z][a-zA-Z0-9]* {yylval.sym_tab_ptr = SYM_TABLE(yytext); return ID;}
Обратите внимание, что здесь я определил тип VALUE (или yylval) как объединение, содержащее int (intval) и указатель int * (sym_tab_ptr).
Но в мире yacc это ЗНАЧЕНИЕ идентифицируется как $ n. Например, рассмотрим следующее правило yacc для определения конкретного оператора присваивания
TYPE ID '=' VAL: { //In this action part of the yacc rule, use $2 to get the symbol table pointer associated with ID, use $4 to get decimal 10.}
Ответ на ваш вопрос
Если вы хотите получить доступ к значению yytext определенного токена (который связан с миром lex) в мире yacc, используйте это старое значение VALUE в качестве следующего:
- Увеличьте тип объединения VALUE, добавив еще одно поле, например char * lex_token_str
- В правиле lex do yylval.lex_token_str = strdup (yytext)
- Затем в мире yacc получите к нему доступ, используя соответствующий $ n.
- В случае, если вы хотите получить доступ более чем к одному значению токена (например, для идентификатора токена, идентифицированного лексом, анализатор может захотеть получить доступ как к имени, так и к указателю таблицы символов), а затем увеличить тип объединения VALUE со структурным членом, содержащим char * (для имени) и int * (для указателя symtab).