使用yylex()从输入字符串获取令牌类型的列表

时间:2018-07-31 18:00:55

标签: parsing bison flex-lexer lexer

我有一个使用Bison和Flex制作的CLI,它变得又大又复杂,并且我正在尝试为给定的输入字符串获取令牌的完整序列(yytokentype或相应的yytranslate Bison符号编号)。解析器。

理想情况下,每次调用yyerror()时,我都想存储在解析期间标识的令牌序列。我不需要知道yylval的状态,动作等,只需知道由输入到缓冲区的字符串产生的标记列表即可。

如果不存在执行此操作的简单方法,那么仅是从字符串开始的独立方法-> yytokentypes将起作用。

下面的代码仅具有调试打印输出,一旦我弄清楚如何获取令牌,我将更改为将其存储在所需的位置。

// When an error condition is reached, yylex() to get the yytokentypes
void yyerror(const char *s)
{
    std::cerr<<"LEX\n";
    int tok; // yytokentype
    do
    {
        tok = yylex();
        std::cerr<<tok<<",";
    }while(tok);
    std::cerr<<"LEX\n";
}

2 个答案:

答案 0 :(得分:0)

好的,我想出了一种无需重新标记输入字符串的方法。 Flex允许您定义YY_DECL,默认情况下会在生成的lexer文件中找到YY_DECL来生成yylex()声明:

#ifndef YY_DECL
  //some other stuff
#define YY_DECL int yylex (void)
#endif /* !YY_DECL */

就这样

/** The main scanner function which does all the work.
 */
YY_DECL
{
    // Body of yylex() which returns the yytokentype
}

我能做的一件棘手的事情是通过YY_DECL重新定义yylex()以捕获每个令牌,然后将其返回给调用者。这使我可以为每个调用存储yytokentype,而无需一点一点地更改解析器的行为。下面,我只是在这里打印出来进行测试:

#define YY_DECL                                 \
int yylex2(void);                               \
int yylex (void)                                \
{                                               \
    int ret;                                    \
    ret = yylex2();                             \
    std::cerr<<"yylex2 returns: "<<ret<<"\n";   \
    return ret;                                 \
}                                               \

答案 1 :(得分:0)

一个更简单的解决方案是只使用YY_DECL宏更改词法分析器的名称,然后在末尾添加yylex的定义:

%{
// ...
#include "parser.tab.h"
#define YY_DECL static int wrapped_lexer(void)
%}

%%
  /* rules */
%%
int yylex(void) {
  int token = wrapped_lexer();
  /* do something with the token */
  return token;
}

已经说过,除非源代码由于某种原因一次只能读取一次,否则总体上来说,仅在遇到错误时重新扫描输入可能比在发生错误时保存令牌列表要快得多。乐兴确实非常快,在许多用例中,语法上正确的输入比错误的输入更常见。