我如何解析包含 bison/flex?

How I to parse includes with bison/flex?

我想通过解析链接描述文件来做下面的例子

example.ld

MEMORY 
{
  INCLUDE example_include.ld 
}

example_include.ld

rom   : ORIGIN = 0, LENGTH = 256K

我找到了一些可以执行此操作的代码,但它是 c flex/bison 并且我使用的是 c++ flex / bison。

我发现我可以使用 yyFlexLexer lexer; 这为我提供了:yy_create_buffer() 等等......

这是我在 binutils/ld/ldlex.l 中找到的代码。也许它可以帮助我。

void
lex_push_file (FILE *file, const char *name, unsigned int sysrooted)
{
    if (include_stack_ptr >= MAX_INCLUDE_DEPTH)
    {
      einfo ("%F:includes nested too deeply\n");
    }
  file_name_stack[include_stack_ptr] = name;
  lineno_stack[include_stack_ptr] = lineno;
  sysrooted_stack[include_stack_ptr] = input_flags.sysrooted;
  include_stack[include_stack_ptr] = YY_CURRENT_BUFFER;

  include_stack_ptr++;
  lineno = 1;
  input_flags.sysrooted = sysrooted;
  yyin = file;
  yy_switch_to_buffer (yy_create_buffer (yyin, YY_BUF_SIZE));
}

我的问题是,我没有找到好的例子或文档,如何使用c++ bison / flex?例如,我不能使用 yyin,因为它是受保护的,而不是 public。

最简单的解决方案是递归调用解析器,将要解析的文件传递给它。关于如何将环境信息(即解析状态)从外部解析器传递到内部解析器的精确细节在很大程度上取决于内部数据结构的性质,所以我什至不打算冒险猜测。如果你所做的只是构建一个 AST(这几乎总是最好的解决方案,即使它乍一看似乎没有吸引力),那么除了让解析器 return AST 之外你不需要做任何事情当它成功解析一个文件时给它的调用者。

解析器(或其管理器)通常会创建一个新的 Lexer 对象来扫描提供的输入文件;由于 C++ 扫描器是完全可重入的,因此两个词法分析器的共存不会造成任何困难。这避免了使用缓冲区堆栈,并且通常是一个更简洁的解决方案。

这避免了在 bison/flex 解析器中处理 "includes" 的一个经典问题,即天真的解决方案允许句法上下文从包含文件泄漏回包含文件。如果包含的文件包含未终止的块(或未终止的注释),则该句法上下文可能会在包含的末尾继续处于活动状态,从而导致不直观且通常具有误导性的错误消息。递归策略会在包含文件的末尾触发语法错误,这也将使错误恢复更容易。

免责声明:我真的不喜欢由 flex 和 bison 生成的扫描器和解析器的 C++ 接口。也许有一天我会改变主意;我坦率地承认,这可能只是智力上的懒惰。无论如何,除了一些玩具,我构建的唯一解析器使用 C API,即使我用 C++ 编写操作(我经常这样做)。所以我这里不提供任何示例代码,但我认为这不是特别困难。