- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我正在尝试学习如何构建基于 C++ 的词法分析器/解析器,我正在关注多个在线教程和指南,我的代码主要是根据这两个指南构建的:1 , 2尽管我添加和调整了我认为合适的内容。
首先,我有一个词法分析器的头文件:
#ifndef SHELL_VARIABLELEXER_HPP
#define SHELL_VARIABLELEXER_HPP
#if ! defined(yyFlexLexerOnce)
#include <FlexLexer.h>
#endif
#include "ShellVariableParser.hpp"
#include "location.hh"
namespace SHELL
{
/// This overloads the yyFlexLexer class
class ShellVariableLexer : public yyFlexLexer
{
private:
/// a yylval pointer
ShellVariableParser::semantic_type *yylval = nullptr;
/// a ocation pointer
ShellVariableParser::location_type *loc = nullptr;
public:
/// This constructor only creates the location type.
ShellVariableLexer(std::istream *in) : yyFlexLexer(in)
{
loc = new ShellVariableParser::location_type();
}
using FlexLexer::yylex;
/// A declaration for the yylex function, errors if not here!
virtual ShellVariableParser::symbol_type yylex(ShellVariableParser::semantic_type* const lval, ShellVariableParser::location_type* location);
};
}
#endif // ShellVariableLEXER_HPP
然后我定义了我的 .l 文件,它通过 flex 和 g++ 构建得很好:
%{
#include <string>
#include "Shell/ShellVariableLexer.hpp"
#undef YY_DECL
#define YY_DECL SHELL::ShellVariableParser::symbol_type SHELL::ShellVariableLexer::yylex(SHELL::ShellVariableParser::semantic_type * const lval, SHELL::ShellVariableParser::location_type *location)
#define yyterminate() return SHELL::ShellVariableParser::make_END(*loc)
#define YY_USER_ACTION loc->step(); loc->columns(yyleng);
%}
%option yylineno
%option yyclass="SHELL::ShellVariableLexer"
%option outfile="src/Shell/ShellVariableLexer.cpp"
%option noyywrap
%option c++
%%
%{
yylval = lval;
%}
[0-9]+\.[0-9]+ {
std::string Tmp(yytext, yyleng);
return SHELL::ShellVariableParser::make_FLOAT(std::stod(Tmp, NULL), *loc);
}
[0-9]+ {
std::string Tmp(yytext, yyleng);
return SHELL::ShellVariableParser::make_INTEGER(std::stoi(Tmp, NULL), *loc);
}
"$" return SHELL::ShellVariableParser::make_DOLLARSIGN(*loc);
"{" return SHELL::ShellVariableParser::make_LBRACE(*loc);
"}" return SHELL::ShellVariableParser::make_RBRACE(*loc);
"+" return SHELL::ShellVariableParser::make_PLUS(*loc);
"-" return SHELL::ShellVariableParser::make_MINUS(*loc);
"*" return SHELL::ShellVariableParser::make_MULTIPLY(*loc);
"/" return SHELL::ShellVariableParser::make_DIVIDE(*loc);
"(" return SHELL::ShellVariableParser::make_LPARAN(*loc);
")" return SHELL::ShellVariableParser::make_RPARAN(*loc);
"\"" return SHELL::ShellVariableParser::make_DQUOTE(*loc);
(?i:ON) return SHELL::ShellVariableParser::make_ON(*loc);
(?i:OFF) return SHELL::ShellVariableParser::make_OFF(*loc);
(?i:TRUE) return SHELL::ShellVariableParser::make_TRUE(*loc);
(?i:FALSE) return SHELL::ShellVariableParser::make_FALSE(*loc);
[ \t]
[a-zA-Z_][0-9a-zA-Z_]+ {
std::string Tmp(yytext, yyleng);
return SHELL::ShellVariableParser::make_VARIABLE(Tmp, *loc);
}
[0-9a-zA-Z_ :/\t]+ {
std::string Tmp(yytext, yyleng);
return SHELL::ShellVariableParser::make_STRING(Tmp, *loc);
}
%%
然后我创建了我的 .y 文件,该文件通过 bison OK,但在使用 g++ 编译时失败,我不会在这里显示整个文件,只显示第一部分,规则与我的错误无关:
%defines "include/Shell/ShellVariableParser.hpp"
%skeleton "lalr1.cc"
%define api.namespace {SHELL}
%define parser_class_name {ShellVariableParser}
%output "src/Shell/ShellVariableParser.cpp"
%define api.value.type variant
%define api.token.constructor
%define parse.assert
// %lex-param {semantic_type* const yylval}
// %lex-param {location_type* location}
%code requires
{
#include <utility>
#include <string>
#include <vector>
#include "ShellVariables.hpp"
#include "Util/IO.hpp"
namespace SHELL
{
class ShellVariableLexer;
}
// The following definitions is missing when %locations isn't used
# ifndef YY_NULLPTR
# if defined __cplusplus && 201103L <= __cplusplus
# define YY_NULLPTR nullptr
# else
# define YY_NULLPTR 0
# endif
# endif
}
%parse-param {ShellVariableLexer &lexer}
%define parse.trace
%define parse.error verbose
%code
{
#include "ShellVariableLexer.hpp"
#undef yylex
#define yylex lexer.yylex
}
%token<double> FLOAT
%token<int64_t> INTEGER
%token<std::string> STRING
%token<std::string> VARIABLE
%token DOLLARSIGN
%token LBRACE
%token RBRACE
%token PLUS
%token MINUS
%token MULTIPLY
%token DIVIDE
%token LPARAN
%token RPARAN
%token DQUOTE
%token ON
%token OFF
%token TRUE
%token FALSE
%token END
%locations
%type <std::pair<uint8_t,VariableType>> All;
%type <std::pair<uint8_t,VariableType>> Bool;
%type <std::pair<uint8_t,VariableType>> Integer;
%type <std::pair<uint8_t,VariableType>> Float;
%type <std::pair<uint8_t,VariableType>> String;
%type <std::string> __string__;
%type <VariableType> variable;
%%
编译时出现以下错误:
src/Shell/ShellVariableParser.cpp: In member function ‘virtual int SHELL::ShellVariableParser::parse()’:
src/Shell/ShellVariableParser.cpp:494:46: error: no matching function for call to ‘SHELL::ShellVariableParser::basic_symbol<SHELL::ShellVariableParser::by_type>::basic_symbol(int)’
symbol_type yylookahead (yylex ());
根据这个link我希望 bison 生成的 yylex 函数与 lexer 头文件中定义的函数相同。但这种情况并非如此。如果我尝试通过取消注释 .y 文件中的两行 %lex-param
来手动添加这些参数,我会收到以下错误:
src/Shell/ShellVariableParser.cpp: In member function ‘virtual int SHELL::ShellVariableParser::parse()’:
src/Shell/ShellVariableParser.cpp:494:45: error: ‘yylval’ was not declared in this scope
symbol_type yylookahead (yylex (yylval, location));
我猜这可能是正确的方法,除了变量名 yylval
和 location
?还是我错过了其他一些选择?
我将 gcc 6.2.0 版与 Ubuntu GLIBC 2.24-3ubuntu2、flex 2.6.1 版和 bison 3.0.4 版一起使用。
我仍然不知道是什么原因造成的,我尝试将 .l 文件中的 yylex
转换为返回整数,而不是 make_
我返回了实际的标记:
%{
#include <string>
#include "Shell/ShellVariableLexer.hpp"
#undef YY_DECL
#define YY_DECL int SHELL::ShellVariableLexer::yylex(SHELL::ShellVariableParser::semantic_type * const lval, SHELL::ShellVariableParser::location_type *location)
#define yyterminate() return SHELL::ShellVariableParser::token::END
#define YY_USER_ACTION loc->step(); loc->columns(yyleng);
%}
%option yylineno
%option yyclass="SHELL::ShellVariableLexer"
%option outfile="src/Shell/ShellVariableLexer.cpp"
%option noyywrap
%option c++
%%
%{
yylval = lval;
%}
[0-9]+\.[0-9]+ {
std::string Tmp(yytext, yyleng);
yylval->build<double>(std::stod(Tmp));
return SHELL::ShellVariableParser::token::FLOAT;
}
[0-9]+ {
std::string Tmp(yytext, yyleng);
yylval->build<int64_t>(std::stoi(Tmp));
return SHELL::ShellVariableParser::token::INTEGER;
}
"$" return SHELL::ShellVariableParser::token::DOLLARSIGN;
"{" return SHELL::ShellVariableParser::token::LBRACE;
"}" return SHELL::ShellVariableParser::token::RBRACE;
"+" return SHELL::ShellVariableParser::token::PLUS;
"-" return SHELL::ShellVariableParser::token::MINUS;
"*" return SHELL::ShellVariableParser::token::MULTIPLY;
"/" return SHELL::ShellVariableParser::token::DIVIDE;
"(" return SHELL::ShellVariableParser::token::LPARAN;
")" return SHELL::ShellVariableParser::token::RPARAN;
"\"" return SHELL::ShellVariableParser::token::DQUOTE;
(?i:ON) return SHELL::ShellVariableParser::token::ON;
(?i:OFF) return SHELL::ShellVariableParser::token::OFF;
(?i:TRUE) return SHELL::ShellVariableParser::token::TRUE;
(?i:FALSE) return SHELL::ShellVariableParser::token::FALSE;
[ \t]
[a-zA-Z_][0-9a-zA-Z_]+ {
yylval->build<std::string>(yytext);
return SHELL::ShellVariableParser::token::VARIABLE;
}
[0-9a-zA-Z_ :/\t]+ {
yylval->build<std::string>(yytext);
return SHELL::ShellVariableParser::token::STRING;
}
%%
在 bison 文件中,我刚刚删除了 %define api.token.constructor
行和两个 %lex-param
行。它工作正常。
所以基本上我所做的就是改变 yylex 的返回类型,而不是它的参数!到底为什么这行得通,但第一个实现却行不通?为什么 return int
有效,但 return symbol_type
无效?!
最佳答案
您误读了 C++ 错误消息。编译器没有提示 yylex
的参数.错误消息(为了便于阅读,压缩了 SHELL::ShellVariableParser
)说:
error: no matching function for call to
‘SH...er::basic_symbol<SH...er::by_type>::basic_symbol(int)’
symbol_type yylookahead (yylex ());
事实上,symbol_type
是 SHELL::ShellVariableParser::basic_symbol<SHELL::ShellVariableParser::by_type>
的类型别名,因此更具可读性的渲染将是
error: no matching function for call to ’symbol_type::symbol_type(int)’
换句话说,yylex()
返回 int
, 但自 symbol_type
没有采用 int
的构造函数, yylookahead
的声明无效。
所以问题是 yylex
的返回类型 ,你大概打算成为 symbol_type
.
不幸的是,(在我看来笨拙的)flex C++ 接口(interface)对您不利。在基类中 FlexLexer
, yylex()
被声明为返回 int
的虚函数.由于您的 ShellVariableLexer 派生自 FlexLexer
, 你不能定义 yylex()
作为返回不同的类型。
当然,您可以添加一个不必要的参数,这或多或少是您对 ShellVariableParser::yylex
的声明。做:
virtual ShellVariableParser::symbol_type yylex(ShellVariableParser::semantic_type* const lval, ShellVariableParser::location_type* location);
但由于参数只是避免将方法与基类中声明的方法混淆所必需的,因此您可以使用更简单的方法,例如:
ShellVariableParser::symbol_type yylex(int);
然后安排成调用的版本
#define yylex() lexer.yylex(0)
(将其声明为虚拟没有多大意义。基类没有类似的原型(prototype),因此将其声明为虚拟的唯一原因是您要子类化 ShellVariableParser
。)
关于c++ - Bison 没有使用正确的 yylex 参数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/44471372/
#include using namespace std; class C{ private: int value; public: C(){ value = 0;
这个问题已经有答案了: What is the difference between char a[] = ?string?; and char *p = ?string?;? (8 个回答) 已关闭
关闭。此题需要details or clarity 。目前不接受答案。 想要改进这个问题吗?通过 editing this post 添加详细信息并澄清问题. 已关闭 7 年前。 此帖子已于 8 个月
除了调试之外,是否有任何针对 c、c++ 或 c# 的测试工具,其工作原理类似于将独立函数复制粘贴到某个文本框,然后在其他文本框中输入参数? 最佳答案 也许您会考虑单元测试。我推荐你谷歌测试和谷歌模拟
我想在第二台显示器中移动一个窗口 (HWND)。问题是我尝试了很多方法,例如将分辨率加倍或输入负值,但它永远无法将窗口放在我的第二台显示器上。 关于如何在 C/C++/c# 中执行此操作的任何线索 最
我正在寻找 C/C++/C## 中不同类型 DES 的现有实现。我的运行平台是Windows XP/Vista/7。 我正在尝试编写一个 C# 程序,它将使用 DES 算法进行加密和解密。我需要一些实
很难说出这里要问什么。这个问题模棱两可、含糊不清、不完整、过于宽泛或夸夸其谈,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开,visit the help center . 关闭 1
有没有办法强制将另一个 窗口置于顶部? 不是应用程序的窗口,而是另一个已经在系统上运行的窗口。 (Windows, C/C++/C#) 最佳答案 SetWindowPos(that_window_ha
假设您可以在 C/C++ 或 Csharp 之间做出选择,并且您打算在 Windows 和 Linux 服务器上运行同一服务器的多个实例,那么构建套接字服务器应用程序的最明智选择是什么? 最佳答案 如
你们能告诉我它们之间的区别吗? 顺便问一下,有什么叫C++库或C库的吗? 最佳答案 C++ 标准库 和 C 标准库 是 C++ 和 C 标准定义的库,提供给 C++ 和 C 程序使用。那是那些词的共同
下面的测试代码,我将输出信息放在注释中。我使用的是 gcc 4.8.5 和 Centos 7.2。 #include #include class C { public:
很难说出这里问的是什么。这个问题是含糊的、模糊的、不完整的、过于宽泛的或修辞性的,无法以目前的形式得到合理的回答。如需帮助澄清此问题以便重新打开它,visit the help center 。 已关
我的客户将使用名为 annoucement 的结构/类与客户通信。我想我会用 C++ 编写服务器。会有很多不同的类继承annoucement。我的问题是通过网络将这些类发送给客户端 我想也许我应该使用
我在 C# 中有以下函数: public Matrix ConcatDescriptors(IList> descriptors) { int cols = descriptors[0].Co
我有一个项目要编写一个函数来对某些数据执行某些操作。我可以用 C/C++ 编写代码,但我不想与雇主共享该函数的代码。相反,我只想让他有权在他自己的代码中调用该函数。是否可以?我想到了这两种方法 - 在
我使用的是编写糟糕的第 3 方 (C/C++) Api。我从托管代码(C++/CLI)中使用它。有时会出现“访问冲突错误”。这使整个应用程序崩溃。我知道我无法处理这些错误[如果指针访问非法内存位置等,
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 我们不允许提问寻求书籍、工具、软件库等的推荐。您可以编辑问题,以便用事实和引用来回答。 关闭 7 年前。
已关闭。此问题不符合Stack Overflow guidelines 。目前不接受答案。 要求我们推荐或查找工具、库或最喜欢的场外资源的问题对于 Stack Overflow 来说是偏离主题的,因为
我有一些 C 代码,将使用 P/Invoke 从 C# 调用。我正在尝试为这个 C 函数定义一个 C# 等效项。 SomeData* DoSomething(); struct SomeData {
这个问题已经有答案了: Why are these constructs using pre and post-increment undefined behavior? (14 个回答) 已关闭 6
我是一名优秀的程序员,十分优秀!