Bison:将 Union 语义类型与 C++ 解析器一起使用
Bison: using the Union semantic type with a C++ parser
我一直在尝试在 Bison 中设置一个小解析器,但是当我尝试构建它时,我得到:
stone.tab.cc: In member function ‘virtual int yy::StoneParser::parse()’:
stone.tab.cc:507:81: error: invalid initialization of non-const reference of type ‘StoneDriver&’ from an rvalue of type ‘yy::StoneParser::semantic_type*’
yyla.type = yytranslate_ (yylex (&yyla.value, &yyla.location, driver));
我怀疑原因是在 bison 生成的 C++ 编译器中使用联合定义的语义类型存在问题,但我似乎无法解决它...
如何生成具有 'union' 语义定义的有效 C++ bison 解析器?
stone.yy:
%skeleton "lalr1.cc"
%require "3.0.4"
%defines
%define parser_class_name {StoneParser}
%code requires
{
# include <string>
class StoneDriver;
}
%param { StoneDriver& driver }
%locations
%code
{
# include "StoneDriver.hpp"
}
%union
{
int intVal;
char* stringVal;
}
%token <stringVal> KEY_ENUM
%token <stringVal> KEY_CLASS
%token K_TEST
%token T_ID
%type <stringVal> class
%type <stringVal> enum
%%
input: toplevel_declarations
toplevel_declarations: toplevel_declarations toplevel_declaration
| %empty
toplevel_declaration: class
| enum
class: KEY_CLASS { $$ = "test"; }
enum: KEY_ENUM { $$ = "test"; }
StoneDriver.hpp
#ifndef STONEDRIVER_INCLUDED_HPP
#define STONEDRIVER_INCLUDED_HPP
#include <string>
#include <map>
#include "stone.tab.hh"
class StoneDriver;
//Tell Flex the lexer's prototype ...
#define YY_DECL \
yy::StoneParser::symbol_type yylex (StoneDriver& driver)
// ... and declare it for the parser's sake.
YY_DECL;
//Scans and parses Stone
class StoneDriver
{
public:
//Constructor
StoneDriver();
//Destructor
virtual ~StoneDriver();
std::map<std::string, int> variables;
int result;
// Handling the scanner.
void scan_begin ();
void scan_end ();
bool trace_scanning;
// Run the parser on file F.
// Return 0 on success.
int parse (const std::string& f);
// The name of the file being parsed.
// Used later to pass the file name to the location tracker.
std::string file;
// Whether parser traces should be generated.
bool trace_parsing;
// Error handling.
void error (const yy::location& l, const std::string& m);
void error (const std::string& m);
};//StoneDriver
#endif
StoneDriver.cpp:
#include "StoneDriver.hpp"
#include "stone.tab.hh"
StoneDriver::StoneDriver()
: trace_scanning (false), trace_parsing (false)
{
variables["one"] = 1;
variables["two"] = 2;
}//constructor
StoneDriver::~StoneDriver()
{
}//destructor
int StoneDriver::parse(const std::string &f)
{
file = f;
scan_begin();
yy::StoneParser parser(*this);
#if YYDEBUG
parser.set_debug_level(trace_parsing);
#endif
int res = parser.parse();
scan_end();
return res;
}//parse
void StoneDriver::error(const yy::location& l, const std::string& m)
{
std::cerr << l << ": " << m << std::endl;
}//error
void StoneDriver::error(const std::string& m)
{
std::cerr << m << std::endl;
}//error
解决方案:
Rici 表明 YY_DECL 的方法签名应该这样定义:
int yylex (semantic_type* YYLVAL, location_type* YYLLOC, TYPE1 ARG1, ...)
就我而言,魔术线是:
#define YY_DECL int yylex( yy::StoneParser::semantic_type* const lval, yy::StoneParser::location_type* location, StoneDriver& driver )
yy::
是我的 Bison 文件中的命名空间(在我的例子中是 stone.yy)
StoneParser
是 stone.yy 定义的 parser_class_name
location_type
是必需的,因为 stone.yy 有 % 个位置
定义。
StoneDriver&
是来自stone.yy的解析上下文,
定义为 %param { StoneDriver& driver }
感谢您的帮助!
错误消息提供了一个稍微清楚的问题指示,尽管它奇怪地集中在 yylex
的第一个参数中的类型不匹配,而不是你为 [= 提供的原型12=] 只有一个参数,而调用有三个参数。 Clang更清晰:
stone.tab.cc:474:39: error: no matching function for call to 'yylex'
yyla.type = yytranslate_ (yylex (&yyla.value, &yyla.location, driver));
^~~~~
./stone_driver.hpp:14:1: note: candidate function not viable: requires single argument 'driver', but 3 arguments were provided
YY_DECL;
^
bison 信息文件第 10.1.5.1 节描述了来自具有 union
语义类型的 C++ 扫描器的 yylex
调用约定:
The interface is as follows.
-- Method on parser: int yylex (semantic_type* YYLVAL, location_type*
YYLLOC, TYPE1 ARG1, ...)
-- Method on parser: int yylex (semantic_type* YYLVAL, TYPE1 ARG1, ...)
Return the next token. Its type is the return value, its semantic
value and location (if enabled) being YYLVAL and YYLLOC.
Invocations of ‘%lex-param {TYPE1 ARG1}’ yield additional
arguments.
这实际上与 C API 中纯解析器使用的调用约定相同:yylex
的前两个参数(如果启用了位置,就像您的程序中的情况一样) ) 是语义值对象的地址和位置对象的地址;第三个和后续参数是由 %param
(如果存在)指定的参数。
所以你应该根据上面的原型修正YY_DECL
的定义。
您还必须更改您的 flex 操作以将 yylval
(或您称之为第一个参数的任何内容)视为指针而不是联合,这主要意味着将 .
更改为 ->
.
我一直在尝试在 Bison 中设置一个小解析器,但是当我尝试构建它时,我得到:
stone.tab.cc: In member function ‘virtual int yy::StoneParser::parse()’: stone.tab.cc:507:81: error: invalid initialization of non-const reference of type ‘StoneDriver&’ from an rvalue of type ‘yy::StoneParser::semantic_type*’ yyla.type = yytranslate_ (yylex (&yyla.value, &yyla.location, driver));
我怀疑原因是在 bison 生成的 C++ 编译器中使用联合定义的语义类型存在问题,但我似乎无法解决它...
如何生成具有 'union' 语义定义的有效 C++ bison 解析器?
stone.yy:
%skeleton "lalr1.cc"
%require "3.0.4"
%defines
%define parser_class_name {StoneParser}
%code requires
{
# include <string>
class StoneDriver;
}
%param { StoneDriver& driver }
%locations
%code
{
# include "StoneDriver.hpp"
}
%union
{
int intVal;
char* stringVal;
}
%token <stringVal> KEY_ENUM
%token <stringVal> KEY_CLASS
%token K_TEST
%token T_ID
%type <stringVal> class
%type <stringVal> enum
%%
input: toplevel_declarations
toplevel_declarations: toplevel_declarations toplevel_declaration
| %empty
toplevel_declaration: class
| enum
class: KEY_CLASS { $$ = "test"; }
enum: KEY_ENUM { $$ = "test"; }
StoneDriver.hpp
#ifndef STONEDRIVER_INCLUDED_HPP
#define STONEDRIVER_INCLUDED_HPP
#include <string>
#include <map>
#include "stone.tab.hh"
class StoneDriver;
//Tell Flex the lexer's prototype ...
#define YY_DECL \
yy::StoneParser::symbol_type yylex (StoneDriver& driver)
// ... and declare it for the parser's sake.
YY_DECL;
//Scans and parses Stone
class StoneDriver
{
public:
//Constructor
StoneDriver();
//Destructor
virtual ~StoneDriver();
std::map<std::string, int> variables;
int result;
// Handling the scanner.
void scan_begin ();
void scan_end ();
bool trace_scanning;
// Run the parser on file F.
// Return 0 on success.
int parse (const std::string& f);
// The name of the file being parsed.
// Used later to pass the file name to the location tracker.
std::string file;
// Whether parser traces should be generated.
bool trace_parsing;
// Error handling.
void error (const yy::location& l, const std::string& m);
void error (const std::string& m);
};//StoneDriver
#endif
StoneDriver.cpp:
#include "StoneDriver.hpp"
#include "stone.tab.hh"
StoneDriver::StoneDriver()
: trace_scanning (false), trace_parsing (false)
{
variables["one"] = 1;
variables["two"] = 2;
}//constructor
StoneDriver::~StoneDriver()
{
}//destructor
int StoneDriver::parse(const std::string &f)
{
file = f;
scan_begin();
yy::StoneParser parser(*this);
#if YYDEBUG
parser.set_debug_level(trace_parsing);
#endif
int res = parser.parse();
scan_end();
return res;
}//parse
void StoneDriver::error(const yy::location& l, const std::string& m)
{
std::cerr << l << ": " << m << std::endl;
}//error
void StoneDriver::error(const std::string& m)
{
std::cerr << m << std::endl;
}//error
解决方案: Rici 表明 YY_DECL 的方法签名应该这样定义:
int yylex (semantic_type* YYLVAL, location_type* YYLLOC, TYPE1 ARG1, ...)
就我而言,魔术线是:
#define YY_DECL int yylex( yy::StoneParser::semantic_type* const lval, yy::StoneParser::location_type* location, StoneDriver& driver )
yy::
是我的 Bison 文件中的命名空间(在我的例子中是 stone.yy)StoneParser
是 stone.yy 定义的 parser_class_name
location_type
是必需的,因为 stone.yy 有 % 个位置 定义。StoneDriver&
是来自stone.yy的解析上下文, 定义为%param { StoneDriver& driver }
感谢您的帮助!
错误消息提供了一个稍微清楚的问题指示,尽管它奇怪地集中在 yylex
的第一个参数中的类型不匹配,而不是你为 [= 提供的原型12=] 只有一个参数,而调用有三个参数。 Clang更清晰:
stone.tab.cc:474:39: error: no matching function for call to 'yylex'
yyla.type = yytranslate_ (yylex (&yyla.value, &yyla.location, driver));
^~~~~
./stone_driver.hpp:14:1: note: candidate function not viable: requires single argument 'driver', but 3 arguments were provided
YY_DECL;
^
bison 信息文件第 10.1.5.1 节描述了来自具有 union
语义类型的 C++ 扫描器的 yylex
调用约定:
The interface is as follows.
-- Method on parser: int yylex (semantic_type* YYLVAL, location_type*
YYLLOC, TYPE1 ARG1, ...)
-- Method on parser: int yylex (semantic_type* YYLVAL, TYPE1 ARG1, ...)
Return the next token. Its type is the return value, its semantic
value and location (if enabled) being YYLVAL and YYLLOC.
Invocations of ‘%lex-param {TYPE1 ARG1}’ yield additional
arguments.
这实际上与 C API 中纯解析器使用的调用约定相同:yylex
的前两个参数(如果启用了位置,就像您的程序中的情况一样) ) 是语义值对象的地址和位置对象的地址;第三个和后续参数是由 %param
(如果存在)指定的参数。
所以你应该根据上面的原型修正YY_DECL
的定义。
您还必须更改您的 flex 操作以将 yylval
(或您称之为第一个参数的任何内容)视为指针而不是联合,这主要意味着将 .
更改为 ->
.