Bison,在 C++ 中与 flex 交互
Bison, interfacing with flex in c++
我尝试写一个编译器,用flex/bison进行扫描和解析。
我的问题是关于这两个如何通信,以便 lex 传递标记类型和(如果需要)语义值。
问题是我找到了不同的(冲突的?)文档。
例如 here 他们提到使用 yylval 子字段作为语义值,return 标记类型(可能是整数)。
[0-9]+ {
yylval->build<int> () = text_to_int (yytext);
return yy::parser::token::INTEGER;
}
[a-z]+ {
yylval->build<std::string> () = yytext;
return yy::parser::token::IDENTIFIER;
}
但是,我看到了(也在官方文档中)this:
"-" return yy::calcxx_parser::make_MINUS (loc);
"+" return yy::calcxx_parser::make_PLUS (loc);
"*" return yy::calcxx_parser::make_STAR (loc);
"/" return yy::calcxx_parser::make_SLASH (loc);
"(" return yy::calcxx_parser::make_LPAREN (loc);
")" return yy::calcxx_parser::make_RPAREN (loc);
":=" return yy::calcxx_parser::make_ASSIGN (loc);
{int} {
errno = 0;
long n = strtol (yytext, NULL, 10);
if (! (INT_MIN <= n && n <= INT_MAX && errno != ERANGE))
driver.error (loc, "integer is out of range");
return yy::calcxx_parser::make_NUMBER (n, loc);
}
{id} return yy::calcxx_parser::make_IDENTIFIER (yytext, loc);
. driver.error (loc, "invalid character");
<<EOF>> return yy::calcxx_parser::make_END (loc);
这里完全没有提到yylval,我们return是一些奇怪的make_???函数,我不明白它们在哪里定义,它们接受什么参数以及它们 return.
有人可以向我说明这两种方法之间的区别吗,如果我应该使用第二种方法,请对那些神秘的 make_ 做一个简短的解释???方法?
提前致谢!
您 link 的文档部分是描述 备选 API 的两部分中的第一部分。最好从beginning开始阅读,那里解释说:
The actual interface with yylex depends whether you use unions, or variants.
您引用的示例使用变体,因此使用 complete symbols 接口,其中定义了 make_*
方法。 (这些不是标准库或 Boost 变体;它们是由 bison 框架定义的简单可区分联合 class。)
您使用哪种 API 完全取决于您;他们都有优点和缺点。
还有第三种选择:使用 C 接口构建解析器和词法分析器。这不会阻止您使用 C++ 数据类型,但您不能将它们直接放入解析器堆栈;您需要使用指针,这使得内存管理更加手动。 (实际上,还有两种不同的 C API:传统的,解析器在需要令牌时自动调用扫描器,以及 "push" 接口,扫描器使用每个令牌调用解析器。)
我尝试写一个编译器,用flex/bison进行扫描和解析。 我的问题是关于这两个如何通信,以便 lex 传递标记类型和(如果需要)语义值。
问题是我找到了不同的(冲突的?)文档。
例如 here 他们提到使用 yylval 子字段作为语义值,return 标记类型(可能是整数)。
[0-9]+ {
yylval->build<int> () = text_to_int (yytext);
return yy::parser::token::INTEGER;
}
[a-z]+ {
yylval->build<std::string> () = yytext;
return yy::parser::token::IDENTIFIER;
}
但是,我看到了(也在官方文档中)this:
"-" return yy::calcxx_parser::make_MINUS (loc);
"+" return yy::calcxx_parser::make_PLUS (loc);
"*" return yy::calcxx_parser::make_STAR (loc);
"/" return yy::calcxx_parser::make_SLASH (loc);
"(" return yy::calcxx_parser::make_LPAREN (loc);
")" return yy::calcxx_parser::make_RPAREN (loc);
":=" return yy::calcxx_parser::make_ASSIGN (loc);
{int} {
errno = 0;
long n = strtol (yytext, NULL, 10);
if (! (INT_MIN <= n && n <= INT_MAX && errno != ERANGE))
driver.error (loc, "integer is out of range");
return yy::calcxx_parser::make_NUMBER (n, loc);
}
{id} return yy::calcxx_parser::make_IDENTIFIER (yytext, loc);
. driver.error (loc, "invalid character");
<<EOF>> return yy::calcxx_parser::make_END (loc);
这里完全没有提到yylval,我们return是一些奇怪的make_???函数,我不明白它们在哪里定义,它们接受什么参数以及它们 return.
有人可以向我说明这两种方法之间的区别吗,如果我应该使用第二种方法,请对那些神秘的 make_ 做一个简短的解释???方法?
提前致谢!
您 link 的文档部分是描述 备选 API 的两部分中的第一部分。最好从beginning开始阅读,那里解释说:
The actual interface with yylex depends whether you use unions, or variants.
您引用的示例使用变体,因此使用 complete symbols 接口,其中定义了 make_*
方法。 (这些不是标准库或 Boost 变体;它们是由 bison 框架定义的简单可区分联合 class。)
您使用哪种 API 完全取决于您;他们都有优点和缺点。
还有第三种选择:使用 C 接口构建解析器和词法分析器。这不会阻止您使用 C++ 数据类型,但您不能将它们直接放入解析器堆栈;您需要使用指针,这使得内存管理更加手动。 (实际上,还有两种不同的 C API:传统的,解析器在需要令牌时自动调用扫描器,以及 "push" 接口,扫描器使用每个令牌调用解析器。)