我正在研究编译器,我想提高它的性能.我发现大约50%的时间花在解析源文件上.由于源文件非常小,之后我做了很多转换,在我看来它是可以完善的.
我的解析器是一个带有词法分析器(带有lexer :: pos_iterator)的Boost Spirit解析器,我有一个中等大小的语法.我正在将源解析为AST.
我的问题是我不知道解析过程中花费的时间最多:AST节点,词法分析器,解析器规则或内存的副本.
我不认为这是I/O问题,因为我正在使用SSD并且我在开始时完全读取文件然后仅使用内存版本.
我尝试使用分析器,但是花费时间的方法是Boost的一些方法,其名称长达数百个字符,我不知道它们到底做了什么......
那么,是否有一种首选方法来对Boost Spirit Parser及其语法进行基准测试?或者是否有一些规则可用于验证某些特定点的效率?
谢谢
感兴趣的人的来源:
c++ benchmarking boost-spirit boost-spirit-qi boost-spirit-lex
我尝试使用Boost Spirit为一个小编程语言实现一个Lexer.
我必须得到一个令牌的值,我得到一个bad_get异常:
在抛出'boost :: bad_get'的实例后调用终止
what():boost :: bad_get:失败的值得到使用boost :: get Aborted
这样做时我得到了这个例外:
std::string contents = "void";
base_iterator_type first = contents.begin();
base_iterator_type last = contents.end();
SimpleLexer<lexer_type> lexer;
iter = lexer.begin(first, last);
end = lexer.end();
std::cout << "Value = " << boost::get<std::string>(iter->value()) << std::endl;
Run Code Online (Sandbox Code Playgroud)
我的词法分析器定义如下:
typedef std::string::iterator base_iterator_type;
typedef boost::spirit::lex::lexertl::token<base_iterator_type, boost::mpl::vector<unsigned int, std::string>> Tok;
typedef lex::lexertl::actor_lexer<Tok> lexer_type;
template<typename L>
class SimpleLexer : public lex::lexer<L> {
private:
public:
SimpleLexer() {
keyword_for = "for";
keyword_while = "while";
keyword_if = "if";
keyword_else = "else"; …Run Code Online (Sandbox Code Playgroud) 我有一个简单的配置文件解析器,由spirit :: lex和spirit :: qi构建.当词法分析器到达模式时,include "path"我希望包含文件的文本.您可能知道,spirit :: lexer :: begin()启动扫描过程:
// Read file contents into a std::string
...
// _first and _last are const char*
_first = _contents.c_str();
_last = &_first[_input.size()];
// _token is a lexer::iterator_type for the current token
_token = _lexer.begin(_first, _last);
Run Code Online (Sandbox Code Playgroud)
我的想法是有一个存储lexer状态的堆栈表示为结构:
struct LexerState
{
const char* first;
const char* last;
std::string contents;
};
Run Code Online (Sandbox Code Playgroud)
词法分析器将识别模式,include "path"并在语义动作中提取包含文件的路径.然后,将当前词法分析器状态推入堆栈,将文件的内容加载到字符串中,并使用lexer :: begin()按上述方式初始化新状态.
当词法分析器找到EOF字符时,弹出堆栈并使用先前的词法分析器状态变量调用lexer :: begin().
可以这样重复调用lexer :: begin()吗?如何让lex :: lexer识别include "path"模式和EOF字符而不将令牌返回到qi解析器?
最后,有没有其他或更好的方法来实现这一目标?
我尝试继续处理我之前的示例并扩展规则.我的问题是,使用ID_IDENTIFIER的规则不起作用 - 虽然我知道词法分析器正在工作(使用单元测试).
这是一个例子:
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
namespace qi = boost::spirit::qi;
namespace lex = boost::spirit::lex;
enum LexerIDs { ID_IDENTIFIER, ID_WHITESPACE, ID_INTEGER, ID_FLOAT, ID_PUNCTUATOR };
template <typename Lexer>
struct custom_lexer : lex::lexer<Lexer>
{
custom_lexer()
: identifier ("[a-zA-Z_][a-zA-Z0-9_]*")
, white_space ("[ \\t\\n]+")
, integer_value ("[1-9][0-9]*")
, hex_value ("0[xX][0-9a-fA-F]+")
, float_value ("[0-9]*\\.[0-9]+([eE][+-]?[0-9]+)?")
, float_value2 ("[0-9]+\\.([eE][+-]?[0-9]+)?")
, punctuator ("\\[|\\]|\\(|\\)|\\.|&>|\\*\\*|\\*|\\+|-|~|!|\\/|%|<<|>>|<|>|<=|>=|==|!=|\\^|&|\\||\\^\\^|&&|\\|\\||\\?|:|,")// [ ] ( ) . &> ** * + - ~ ! / % << >> < > <= >= == != ^ & …Run Code Online (Sandbox Code Playgroud) 我尝试学习使用boost :: spirit.为此,我想创建一些简单的词法分析器,将它们组合起来,然后使用精神开始解析.我尝试修改示例,但它没有按预期运行(结果r不正确).
这是词法分析器:
#include <boost/spirit/include/lex_lexertl.hpp>
namespace lex = boost::spirit::lex;
template <typename Lexer>
struct lexer_identifier : lex::lexer<Lexer>
{
lexer_identifier()
: identifier("[a-zA-Z_][a-zA-Z0-9_]*")
, white_space("[ \\t\\n]+")
{
using boost::spirit::lex::_start;
using boost::spirit::lex::_end;
this->self = identifier;
this->self("WS") = white_space;
}
lex::token_def<> identifier;
lex::token_def<> white_space;
std::string identifier_name;
};
Run Code Online (Sandbox Code Playgroud)
这是我正在尝试运行的示例:
#include "stdafx.h"
#include <boost/spirit/include/lex_lexertl.hpp>
#include "my_Lexer.h"
namespace lex = boost::spirit::lex;
int _tmain(int argc, _TCHAR* argv[])
{
typedef lex::lexertl::token<char const*,lex::omit, boost::mpl::false_> token_type;
typedef lex::lexertl::lexer<token_type> lexer_type;
typedef lexer_identifier<lexer_type>::iterator_type iterator_type;
lexer_identifier<lexer_type> my_lexer;
std::string test("adedvied das934adf dfklj_03245");
char const* first …Run Code Online (Sandbox Code Playgroud) 要实现对typedef的支持,当lexer识别标识符并返回不同的标记时,您需要查找符号表.这在flex lexer中很容易完成.我试图使用boost Spirit来构建解析器并在示例中查看,但它们都没有在词法分析器和解析器之间传递任何上下文信息.在mini c编译器教程示例中,最简单的方法是什么?
当我尝试从iterator_range转换令牌的值时,词法分析器在尝试读取下一个令牌时失败.
这是包含令牌定义的Tokens结构:(我不认为这是相关的,但我包括以防万一.)
template <typename Lexer>
struct Tokens : boost::spirit::lex::lexer<Lexer>
{
Tokens();
boost::spirit::lex::token_def<std::string> identifier;
boost::spirit::lex::token_def<std::string> string;
boost::spirit::lex::token_def<bool> boolean;
boost::spirit::lex::token_def<double> real;
boost::spirit::lex::token_def<> comment;
boost::spirit::lex::token_def<> whitespace;
};
template <typename Lexer>
Tokens<Lexer>::Tokens()
{
// Define regex macros
this->self.add_pattern
("LETTER", "[a-zA-Z_]")
("DIGIT", "[0-9]")
("INTEGER", "-?{DIGIT}+")
("FLOAT", "-?{DIGIT}*\\.{DIGIT}+");
// Define the tokens' regular expressions
identifier = "{LETTER}({LETTER}|{DIGIT})*";
string = "\"[a-zA-Z_0-9]*\"";
boolean = "true|false";
real = "{INTEGER}|{FLOAT}";
comment = "#[^\n\r\f\v]*$";
whitespace = "\x20\n\r\f\v\t+";
// Define tokens
this->self
= identifier
| string
| boolean
| real
| '{' …Run Code Online (Sandbox Code Playgroud) 我有一个非常简单的路径构造,我试图用boost spirit.lex解析.
我们有以下语法:
token := [a-z]+
path := (token : path) | (token)
Run Code Online (Sandbox Code Playgroud)
所以我们这里只讨论冒号分隔的小写ASCII字符串.
我有三个例子"xyz","abc:xyz","abc:xyz:".
前两个应被视为有效.第三个,有一个尾随结肠,不应被视为有效.不幸的是,解析器我已经认识到这三个都是有效的.语法不应该允许空令牌,但显然精神就是这样做的.为了让第三个被拒绝,我错过了什么?
此外,如果您阅读下面的代码,则在注释中还有另一个版本的解析器要求所有路径以分号结尾.当我激活那些线时,我可以得到适当的行为(即拒绝"abc:xyz:;"),但这不是我想要的.
有人有主意吗?
谢谢.
#include <boost/config/warning_disable.hpp>
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/lex_lexertl.hpp>
#include <boost/spirit/include/phoenix_operator.hpp>
#include <iostream>
#include <string>
using namespace boost::spirit;
using boost::phoenix::val;
template<typename Lexer>
struct PathTokens : boost::spirit::lex::lexer<Lexer>
{
PathTokens()
{
identifier = "[a-z]+";
separator = ":";
this->self.add
(identifier)
(separator)
(';')
;
}
boost::spirit::lex::token_def<std::string> identifier, separator;
};
template <typename Iterator>
struct PathGrammar
: boost::spirit::qi::grammar<Iterator>
{
template <typename TokenDef>
PathGrammar(TokenDef const& tok)
: PathGrammar::base_type(path)
{
using boost::spirit::_val; …Run Code Online (Sandbox Code Playgroud) 我正在编写DSL并使用Boost Spirit词法分析器来标记我的输入.在我的语法中,我想要一个类似于此的规则(tok词法分析器在哪里):
header_block =
tok.name >> ':' >> tok.stringval > ';' >>
tok.description >> ':' >> tok.stringval > ';'
;
Run Code Online (Sandbox Code Playgroud)
而不是为语言指定保留字(例如"name","description")并处理词法分析器和语法之间的同步,我想只是将匹配的所有内容标记[a-zA-Z_]\w*为单个标记类型(例如tok.symbol),并让语法梳理出来.如果我没有使用词法分析器,我可能会这样做:
stringval = lexeme['"' >> *(char_ - '"') >> '"'];
header_block =
lit("name") >> ':' >> stringval > ';' >>
lit("description") >> ':' >> stringval > ';'
;
Run Code Online (Sandbox Code Playgroud)
使用词法分析器,我可以编译以下规则,但当然它匹配的比我想要的多 - 它不关心特定的符号值"name"和"description":
header_block =
tok.symbol >> ':' >> tok.stringval > ';' >>
tok.symbol >> ':' >> tok.stringval > ';'
;
Run Code Online (Sandbox Code Playgroud)
我正在寻找的是这样的:
header_block = …Run Code Online (Sandbox Code Playgroud) 问题很简单,我写了一个词法分析器,使用boost :: spirit,但是我似乎找不到方法来生成EOF令牌. - 那怎么会这样做呢?