打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
Debugging

The top-down nature of Spirit makes the generated parser easy to micro- debug using the standard debugger bundled with the C++ compiler we are using. With recursive-descent, the parse traversal utilizes the hardware stack through C++ function call mechanisms. There are no difficult to debug tables or state machines that obscure the parsing logic flow. The stack trace we see in the debugger follows faithfully the hierarchical grammar structure.
Spirit自上而下的本质使得生成的分析器很容易使用与我们所用的C++编译器捆绑在一起的标准调试器来进行微型调试。通过递归下降,分析的遍历通过C++函数调用机制利用了硬件的堆栈。调试解析模糊逻辑流的表格或状态机并没有难度。我们在调试器中所看到的堆栈跟踪忠实地遵守语法结构的层次。

Since any production rule can initiate a parse traversal , it is a lot easier to pinpoint the bugs by focusing on one or a few rules. For relatively complex parsing tasks, the same way we write robust C++ programs, it is advisable to develop a grammar iteratively on a per-module basis where each module is a small subset of the complete grammar. That way, we can stress-test individual modules piecemeal until we reach the top-most module. For instance, when developing a scripting language, we can start with expressions, then move on to statements, then functions, upwards until we have a complete grammar. 
因为任何产生式规则都可以启动一个分析遍历,所以就更容易通过集中关注一个或几个规则来查明缺陷。对于相对复杂的分析任务,与我们编写强大的C++程序一样,建议基于每个模块来开发语法,每个模块都是完整语法的一个小子集。这样,我们可以对单个模块进行压力测试,直至到达最顶层的模块。例如,在开发一种脚本语言时,我们可以从表达式开始,然后是语句,然后是函数,向上直至我们完成一个完整的语法。

At some point when the grammar gets quite complicated, it is desirable to visualize the parse traversal and see what's happening. There are some facilities in the framework that aid in the visualisation of the parse traversal for the purpose of debugging. The following macros enable these features.
当语法变得足够复杂的某一点时,最好进行可视化的分析遍历,看看发生了什么。在框架中有一些工具,可以帮助分析遍历的可视化,达到调试的目的。以下宏将启用这些功能。

Debugging Macros 调试所用的宏

BOOST_SPIRIT_ASSERT_EXCEPTION

Spirit contains assertions that may activate when spirit is used incorrectly. By default these assertions use the assert macro from the standard library. If you want spirit to throw an exception instead, define BOOST_SPIRIT_ASSERT_EXCEPTION to the name of the class that you want to be thrown. This class's constructor will be passed a const char* stringified version of the file, line, and assertion condition, when it is thrown. If you want to totally disable the assertion, #define NDEBUG.
Spirit带有一些断言,它们会在spirit被错误使用时激活。缺省情况下,这些断言使用标准库的 assert 宏。如果你希望spirit抛出异常,则将 BOOST_SPIRIT_ASSERT_EXCEPTION 定义为你要抛出的异常类。在被抛出时,该类的构造函数将被传入一个 const char*,其中记录了文件版本、行号和断言条件。如果想完全关闭断言,请 #define NDEBUG.

BOOST_SPIRIT_DEBUG

Define this to enable debugging.
定义此宏以激活调试。

With debugging enabled, special output is generated at key points of the parse process, using the standard output operator (operator<<) with BOOST_SPIRIT_DEBUG_OUT (default is std::cout, see below) as its left operand.
当调试被激活时,在分析过程的关键点将生成一些特定的输出,输出的方式是使用标准输出操作符(operator<<)并以 BOOST_SPIRIT_DEBUG_OUT (缺省为 std::cout, 见后)作为左操作数。

In order to use spirit's debugging support you must ensure that appropriate overloads of operator<< taking BOOST_SPIRIT_DEBUG_OUT as its left operand are available. The expected semantics are those of the standard output operator.
 为了使用spirit的调试支持,你必须确保以 BOOST_SPIRIT_DEBUG_OUT 作为左操作数的合适 operator<< 是可用的。所期望的语义就是标准输出操作符的语义。

These overloads may be provided either within the namespace where the corresponding class is declared (will be found through Argument Dependent Lookup) or [within an anonymous namespace] within namespace boost::spirit, so it is visible where it is called.
这些重载可以在相应类被声明的名字空间中提供(通过ADL查找),也可以在 namespace boost::spirit 中提供,这样在调用时它就是可见的。

Note in particular that when BOOST_SPIRIT_DEBUG_FLAGS_CLOSURES is set, overloads of operator<< taking instances of the types used in closures as their right operands are required.
注意,特别地,当 BOOST_SPIRIT_DEBUG_FLAGS_CLOSURES 被设置时,operator<< 的重载所要求的右操作数是在闭包中所使用的类型的实例。

You may find an example of overloading the output operator for std::pair in a related FAQ entry.
你可在 相关FAQ条目 中看到一个例子,示范了用于 std::pair 的输出操作符重载。

By default, if the BOOST_SPIRIT_DEBUG macro is defined, all available debug output is generated. To fine tune the amount of generated text you can define the BOOST_SPIRIT_DEBUG_FLAGS constant to be equal of a combination of the following flags:
缺省情况下,如果 BOOST_SPIRIT_DEBUG 宏被定义,将生成所有可用的调试输出。要细调生成文本的数量,你可以将 BOOST_SPIRIT_DEBUG_FLAGS 常量定义为以下标志位的组合:

Available flags to fine tune debug output 用于细调调试输出的标志
BOOST_SPIRIT_DEBUG_FLAGS_NODES

print information about nodes (general for all parsers)

打印关于节点的信息(对所有分析器通用)

BOOST_SPIRIT_DEBUG_FLAGS_TREES

print information about parse trees and AST's (general for all tree parsers)

打印关于分析树和AST的信息(对所有树分析器通用)

BOOST_SPIRIT_DEBUG_FLAGS_CLOSURES print information about closures (general for all parsers with closures)
打印关于闭包的信息(对所有带闭包的分析器通用)
BOOST_SPIRIT_DEBUG_FLAGS_ESCAPE_CHAR

print information out of the esc_char_parser

打印 esc_char_parser 的信息

BOOST_SPIRIT_DEBUG_FLAGS_SLEX print information out of the SLEX parser
打印 SLEX 分析器的信息

BOOST_SPIRIT_DEBUG_OUT

Define this to redirect the debugging diagnostics printout to somewhere else (e.g. a file or stream). Defaults to std::cout.
定义此宏可将调试诊断输出重定向至其它地方(如某个文件或流)。缺省输出至 std::cout.

BOOST_SPIRIT_DEBUG_TOKEN_PRINTER

The BOOST_SPIRIT_DEBUG_TOKEN_PRINTER macro allows you to redefine the way characters are printed on the stream.
BOOST_SPIRIT_DEBUG_TOKEN_PRINTER 允许你重定义打印至流的方式字符。

If BOOST_SPIRIT_DEBUG_OUT is of type StreamT, the character type is CharT and BOOST_SPIRIT_DEBUG_TOKEN_PRINTER is defined to foo, it must be compatible with this usage:
如果 BOOST_SPIRIT_DEBUG_OUT 的类型为 StreamT,字符类型为 CharTBOOST_SPIRIT_DEBUG_TOKEN_PRINTER 被定义为 foo,则它必须兼容于以下用法:

    foo(StreamT, CharT)

The default printer requires operator<<(StreamT, CharT) to be defined. Additionaly, if CharT is convertible to a normal character type (char, wchar_t or int), it prints control characters in a friendly manner (e.g., when it receives '\n' it actually prints the \ and n charactes,instead of a newline).
缺省的打印机要求 operator<<(StreamT, CharT) 被定义。另外,如果 CharT 可以转换为普通的字符类型(char, wchar_tint),则它会以一种友好的风格打印控制字符(如,当它收到 '\n' 时,实际打印的是 \n 字符,而不是换行)。

BOOST_SPIRIT_DEBUG_PRINT_SOME

The BOOST_SPIRIT_DEBUG_PRINT_SOME constant defines the number of characters from the stream to be printed for diagnosis. This defaults to the first 20 characters.
BOOST_SPIRIT_DEBUG_PRINT_SOME 常量定义了从流至被打印的诊断信息的字符数量。缺省为头20个字符。

BOOST_SPIRIT_DEBUG_TRACENODE

By default all parser nodes are traced. This constant may be used to redefine this default. If this is 1 (true), then tracing is enabled by default, if this constant is 0 (false), the tracing is disabled by default. This preprocessor constant is set to 1 (true) by default.
缺省情况下,所有分析器节点都被跟踪。这个常量可用于重定义该缺省行为。如果它为 1 (true),则跟踪被缺省打开,如果该常量为 0 (false),则跟踪被缺省关闭。这个预处理器常量缺省被设为 1 (true)。

Please note, that the following BOOST_SPIRIT_DEBUG_...() macros are to be used at function scope only.
请注意,以下的 BOOST_SPIRIT_DEBUG_...() 宏只能被用在函数作用域中。

BOOST_SPIRIT_DEBUG_NODE(p)

Define this to print some debugging diagnostics for parser p. This macro
定义此宏为分析器 p 打印某些调试诊断信息。该宏

  • Registers the parser name for debugging
    为调试注册分析器名
  • Enables/disables the tracing for parser depending on BOOST_SPIRIT_DEBUG_TRACENODE
    根据 BOOST_SPIRIT_DEBUG_TRACENODE 为分析器打开/关闭跟踪

Pre-parse: Before entering the rule, the rule name followed by a peek into the data at the current iterator position is printed.
分析前:在进行规则之前,打印规则名及当前迭代器位置读入的数据。

Post-parse: After parsing the rule, the rule name followed by a peek into the data at the current iterator position is printed. Here, '/' before the rule name flags a succesful match while '#' before the rule name flags an unsuccesful match.
分析后:在规则被分析之后,打印规则名及当前迭代器位置读入的数据。在此,规则名之前的'/'表示成功匹配,而规则名之前的'#'表示不成功的匹配。

The following are synonyms for BOOST_SPIRIT_DEBUG_NODE
以下是 BOOST_SPIRIT_DEBUG_NODE 的同义词

  1. BOOST_SPIRIT_DEBUG_RULE
  2. BOOST_SPIRIT_DEBUG_GRAMMAR

BOOST_SPIRIT_DEBUG_TRACE_NODE(p, flag)

Similar to BOOST_SPIRIT_DEBUG_NODE. Additionally allows selective debugging. This is useful in situations where we want to debug just a hand picked set of nodes.
类似于 BOOST_SPIRIT_DEBUG_NODE。另外还允许选择性调试。当我们想只对部分节点调试时可用。

The following are synonyms for BOOST_SPIRIT_DEBUG_TRACE_NODE
以下是 BOOST_SPIRIT_DEBUG_TRACE_NODE 的同义词

  1. BOOST_SPIRIT_DEBUG_TRACE_RULE
  2. BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR

BOOST_SPIRIT_DEBUG_TRACE_NODE_NAME(p, name, flag)

Similar to BOOST_SPIRIT_DEBUG_NODE. Additionally allows selective debugging and allows to specify the name used during debug printout. This is useful in situations where we want to debug just a hand picked set of nodes. The name may be redefined in situations, where the parser parameter does not reflect the name of the parser to debug.
类似于 BOOST_SPIRIT_DEBUG_NODE。并允许选择性调试和在调试输出时指定名字。当我们想只调试部分节点时可用。当分析器参数不能反映被调试分析器的名字时,name 可用于重定义。

The following are synonyms for BOOST_SPIRIT_DEBUG_TRACE_NODE
以下是 BOOST_SPIRIT_DEBUG_TRACE_NODE 的同义词

  1. BOOST_SPIRIT_DEBUG_TRACE_RULE_NAME
  2. BOOST_SPIRIT_DEBUG_TRACE_GRAMMAR_NAME

Here's the original calculator with debugging features enabled:
以下是带有调试功能的原始计算器:

    #define BOOST_SPIRIT_DEBUG  ///$$$ DEFINE THIS BEFORE ANYTHING ELSE $$$///
#include "boost/spirit/include/classic.hpp"

/***/

/*** CALCULATOR GRAMMAR DEFINITIONS HERE ***/

BOOST_SPIRIT_DEBUG_RULE(integer);
BOOST_SPIRIT_DEBUG_RULE(group);
BOOST_SPIRIT_DEBUG_RULE(factor);
BOOST_SPIRIT_DEBUG_RULE(term);
BOOST_SPIRIT_DEBUG_RULE(expr);

Be sure to add the macros inside the grammar definition's constructor. Now here's a sample session with the calculator.
请确认将这些宏加在语法定义的构造函数内部。以下是该计算器的一个会话示例。

    Type an expression...or [q or Q] to quit    1 + 2    grammar(calc):	"1 + 2"      rule(expression):	"1 + 2"        rule(term):	"1 + 2"          rule(factor):	"1 + 2"            rule(integer):	"1 + 2"    push	1            /rule(integer):	" + 2"          /rule(factor):	" + 2"        /rule(term):	" + 2"        rule(term):	"2"          rule(factor):	"2"            rule(integer):	"2"    push	2            /rule(integer):	""          /rule(factor):	""        /rule(term):	""    popped 1 and 2 from the stack. pushing 3 onto the stack.      /rule(expression):	""    /grammar(calc):	""    -------------------------
Parsing succeeded
result = 3
-------------------------

We typed in "1 + 2". Notice that there are two successful branches from the top rule expr. The text in red is generated by the parser's semantic actions while the others are generated by the debug-diagnostics of our rules. Notice how the first integer rule took "1", the first term rule took "+" and finally the second integer rule took "2".
我们输入 "1 + 2"。注意,顶层规则 expr 有两个成功的分支。红色的文本是由分析器的语义动作所生成,而其它文本是由我们规则的调试诊断所生成。留意第一个 integer 规则是如何获得 "1",第一个 term 规则如何获得 "+" 以及最后,第二个 integer 如何获得 "2"。

Please note the special meaning of the first characters appearing on the printed lines:
请注意,出现在打印行的第一个字符的特殊意义:

  • a single '/' starts a line containing the information about a successfully matched parser node (rule<>, grammar<> or subrule<>)
    以单个 '/' 开始的行,包含了一个成功匹配的分析器节点(rule<>, grammar<>subrule<>)的信息
  • a single '#' starts a line containing the information about a failed parser node
    以单个 '#' 开始的行,包含了一个失败的分析器节点的信息
  • a single '^' starts a line containing the first member (return value/synthesised attribute) of the closure of a successfully matched parser node.
    以单个 '^' 开始的行,包含了一个成功匹配的分析器节点的闭包的第一个成员(返回值/synthesised属性attribute)。

Check out calc_debug.cpp to see debugging in action.
关于调试的运作,请查看 calc_debug.cpp

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
【热】打开小程序,算一算2024你的财运
c – 当某些结构字段被省略或与结构声明中的顺序不一样时,如何实现正确的解析?
SQLite编译器部分浅析
htmlcxx - html and css APIs for C++
Irony - .NET Compiler Construction Kit (转与 CodeProject)
比开源快30倍的自研SQL Parser设计与实践
commons.net包中的FTPClient.listFiles()方法返回null的问...JAVA中使用FTPClient上传下载
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服