Compiler construction Bison使用%define api.pure full,不使用%union,但使用C++;改用变体
我有一个手写扫描仪和一个bison解析器,可以解析这个句子(是问题上下文的缩写): 野牛:Compiler construction Bison使用%define api.pure full,不使用%union,但使用C++;改用变体,compiler-construction,bison,yacc,bisonc++,Compiler Construction,Bison,Yacc,Bisonc++,我有一个手写扫描仪和一个bison解析器,可以解析这个句子(是问题上下文的缩写): 野牛: %require "3.2" %define api.pure full %code{ #include <stdio.h> #include <string.h> #include "Scanner.h" #include<iostream> } %code{ int yylex(YYSTYPE *lvalp)
%require "3.2"
%define api.pure full
%code{
#include <stdio.h>
#include <string.h>
#include "Scanner.h"
#include<iostream>
}
%code{
int yylex(YYSTYPE *lvalp);
#include<iostream>
#include<string>
Scanner scanner;
void yyerror(const char *error);
}
%union {
int n;
double d;
char s[1000];
}
%token VAR COL ITYPE
%token IDENTIFIER
%token INTEGER
%token EOL
%type <s> type PrimitiveType IDENTIFIER
%type <s> INTEGER
%%
program:
| program EOL
| program SimpleDeclaration { }
;
SimpleDeclaration: VariableDeclaration
;
VariableDeclaration: VAR IDENTIFIER COL type {std::cout<<"defined variable " << $2 << " with type " << $4 << std::endl; }
type: IDENTIFIER
| PrimitiveType
;
PrimitiveType: ITYPE { strcpy($$, "int"); }
;
%%
int main()
{
scanner.set_file("inp.txt");
return yyparse();
}
void yyerror(const char *error)
{
std::cout << "syntax error" << std::endl;
}
int yylex(YYSTYPE *lvalp)
{
return scanner.get_next_token(lvalp);
}
但是我想使用STL容器和智能指针。在中,如果您的令牌的类型不同,则不会告诉您如何使用无联合的lvalp*
wi。另外,根据我的代码,请将parser.ypp:3.1-21:错误:%define变量“api.pure”未使用
<> >我想在返回正确的令牌的同时分配值,而不使用联合,这样我就可以使用所有C++特性。
注意:我看到了,但我仍然无法理解函数make_Number
是否已经存在或已生成?如何从my next_token()向属于已定义%token的$variables添加值
提前感谢。#定义api。纯
仅适用于使用C api生成的解析器。如果你要求野牛产生一个C++解析器,你不需要那个声明,因为:
解析器通过调用yylex调用扫描器。与C解析器相反,C++解析器总是纯的:使用<代码> %Apple API没有任何意义。
<>但是C++的API与C API有很大的不同。如果你想使用它们,你真的需要阅读整个手册章节(阅读时参考示例)
请注意,Bison创建的variant类型与std::variant
非常不同,因此它可能是您想要的,也可能不是您想要的。与std::variant
不同,Bison的变体不存储变量值的当前类型,因为解析器总是知道堆栈值的类型。在解析时这很好,但它会降低变量作为导出值的用处。(在其他应用程序中也是如此。)但是,如果您想使用像std::string
这样的非平凡类型,它们可以提供帮助,因为Bison可以确保正确调用析构函数。[注1]
如果您打算使用智能指针,您可能会发现自己正在调用std::move
,以避免复制不可复制的对象。(在解析过程中,Bison堆栈上的对象经常被重复复制。)您还需要使用std::move
来避免过度复制字符串。您可以请求Bison在每次访问语义值时自动插入对std::move
的调用,但如果启用此选项,则需要注意仅使用每个语义值一次。(手册中有一个示例。)
<>你一旦决定使用BySon C++的API,你就需要在词汇扫描器的两个调用约定之间进行选择。一个选项是手动调用的,这只是传统的C方法(修改为使用C纯API):lexer返回一个整数(标记类型),并将语义值放在指向参数的STYPE中。如果STYPE是Bison变体,则需要使用emplace
方法在适当的位置构造一个值(从而避免复制)
野牛手册的链接页中有一些例子。有两个使用emplace
的例子让人有点困惑;我的理解是,第二个示例(其中emplace
采用构造函数参数)可用于C++11或更高版本,这些版本现在应该非常通用(IMHO)
或者,您可以使用“完整符号”,这些符号的描述更为详细,并附有更多示例。如果您告诉Bison使用“完整符号”API(使用%define API.token.constructor
声明),那么Bison将自动生成各种make_XXX
函数。要使用这些函数,您必须更改扫描仪的get_next_token
成员函数,以返回symbol\u type
对象,而不是int
(然后它不需要yylvalp参数)。这可能是一个比你想做的更大的改变
笔记:
std::variant
或具有显式定义的api.value.type
的Boost等价物,但这不会产生make*
调用,而且Bison也不知道如何从变量中提取单个类型,因此整个%type
机制无法工作,因此它不是很有吸引力我阅读了文档中的许多内容,尝试了3天,但我不知道如何从我的扫描仪中给bison标记和值?如果您给出一个更具体的答案或一个读数,那就太好了。@MohamadZiadAlkabakibi:我在答案中添加了更多信息,试图解释为解析器提供标记的选项。提供特定的代码并不容易,因为我不知道您的特定需求是什么;手册中有一些示例(如我所示)。你需要明白野牛给了你几个(相互排斥的)选择;你必须决定采取哪种方法。然后你应该尝试一个语法部分的小实现,看看它是否适合你。如果遇到具体问题,请提出更详细的问题(作为新问题)。
%require "3.2"
%define api.pure full
%code{
#include <stdio.h>
#include <string.h>
#include "Scanner.h"
#include<iostream>
}
%code{
int yylex(YYSTYPE *lvalp);
#include<iostream>
#include<string>
Scanner scanner;
void yyerror(const char *error);
}
%union {
int n;
double d;
char s[1000];
}
%token VAR COL ITYPE
%token IDENTIFIER
%token INTEGER
%token EOL
%type <s> type PrimitiveType IDENTIFIER
%type <s> INTEGER
%%
program:
| program EOL
| program SimpleDeclaration { }
;
SimpleDeclaration: VariableDeclaration
;
VariableDeclaration: VAR IDENTIFIER COL type {std::cout<<"defined variable " << $2 << " with type " << $4 << std::endl; }
type: IDENTIFIER
| PrimitiveType
;
PrimitiveType: ITYPE { strcpy($$, "int"); }
;
%%
int main()
{
scanner.set_file("inp.txt");
return yyparse();
}
void yyerror(const char *error)
{
std::cout << "syntax error" << std::endl;
}
int yylex(YYSTYPE *lvalp)
{
return scanner.get_next_token(lvalp);
}
defined variable x with type int