如何使用我自己的解析器flex?

时间:2015-02-21 06:57:34

标签: c++ parsing compiler-construction flex-lexer lexical-analysis

我想将词汇分析留给lex,但我自己开发解析器。

我创建了一个token.h标头,其中包含令牌类型的枚举和简单的类层次结构

对于lex规则:

[0-9]+ {yylval = new NumToken(std::stoi(yytext));return NUM;}

如何从解析器代码中获取NumToken指针? 假设我只想打印出令牌..

while(true)
{
    auto t = yylex();
    //std::cout <<yylval.data<<std::endl; // What goes here ?
}

我可以使用yacc / bison执行此操作,但无法找到有关如何手动执行此操作的任何文档或示例。

1 个答案:

答案 0 :(得分:1)

在传统的bison / flex解析器中,yylval是由bison生成的解析器中定义的全局变量,并在bison生成的头文件中声明(应该是#include&#39; d)扫描器)。所以一个简单的解决方案就是复制它:在yylval中声明token.h(作为全局)并在解析器中的某处定义它。

但是现代编程风格已经从使用全局变换(有充分理由),甚至flex甚至会生成不依赖于全局状态的扫描器(如果请求)。要请求此类扫描程序,请指定

%option reentrant
扫描仪定义中的

。默认情况下,这会将yylex的原型更改为:

int yylex(yyscan_t yyscanner);

其中yyscan_t是一个不透明的指针。 (这是C,所以这意味着它是void*。)您可以在Flex manual中了解详细信息。最重要的一点是你可以要求flex也生成一个头文件(带有%option header-file),以便其他翻译单元可以参考创建,销毁和操作yyscan_t的各种函数,以及你需要最低限度地创建一个,以便yylex有一个存储其状态的地方。 (理想情况下,你也会破坏它。)[注1]。

bison使用可重入扫描程序的预期方法是启用%option bison-bridge(如果词法分析器为每个令牌生成源位置信息,则为%option bison-location。这将为yylex原型添加一个额外的参数:

int yylex(YYSTYPE *yylval_param, yyscan_t scanner);

使用'%选项bison-locations&#39;,添加了两个参数:

int yylex(YYSTYPE *yylval_param,
          YYLTYPE *yylloc_param,
          yyscan_t scanner);

灵活生成代码声明的语义类型YYSTYPE和位置类型YYLTYPE 。它们必须出现在您将#include到扫描仪的token.h标题中。

bison-bridge参数的目的是提供一种机制,将语义值yylval返回给调用者(即解析器)。由于yylval实际上与参数yylval_param [注释2]相同,因此它将是实际语义值的指针,因此您需要编写(例如)你的弹性动作yylval->data = ...

这是一种方法。

bison-bridge的一个可能更简单的替代方法就是提供您自己的yylex原型,您可以使用宏YY_DECL。例如,你可以这样做(如果YYSTYPE很简单):

#define YY_DECL std::pair<int, YYSTYPE> yylex(yyscan_t yyscanner)

然后规则可以返回该对:

[0-9]+ {return std::make_pair(NUM, new NumToken(std::stoi(yytext));}

显然,这个主题有很多变种。


注释

  1. 不幸的是,生成的标题包含了很多不必要的包袱,其中包括一系列标准的宏定义&#34;全局&#34;因为在重入扫描仪中这些变量只能用于弹性动作,所以它不会起作用。

  2. 使用bison-bridge生成的扫描程序将yylval定义为宏,该宏引用不透明状态结构中的字段,并将yylval_param存储到此字段中。我们提供了yyget_lvalyyset_lval函数,以便从yylex之外获取或设置此字段。我不知道为什么;它似乎介于不必要和危险之间,因为状态将包含指针到值,如调用yylex中所提供的,一旦调用返回,它可能是一个悬空指针。

相关问题