处理yacc中的块

时间:2017-03-14 23:59:41

标签: c yacc

我正在用lex + yacc构建一个解析器,用于以下简单语言:

lines are parsed ok

foo {
   lines of the "foo" category come here
} # closing this block

我的语法中的块的以下定义有效:

item : block
     | lines; /* lines without a block */

block: WORD BRACE_OPEN NL lines BRACE_CLOSE
     { printf("category: %s\n", $1 );}

问题是printf在块解析后发生了,但我需要获取类别名称(示例中为“foo”)作为解析行的信息在街区内。

我提出了一个解决方案,但它似乎并不优雅:

item : line
     | block_open
     | block_close;

block_open : WORD BRACE_OPEN { printf("%s {\n", $1); };

block_close : BRACE_CLOSE { printf("}\n"); };

我现在可以在打开块时获取“类别”名称。但这是正确的还是最好的方法?

谢谢!

2 个答案:

答案 0 :(得分:1)

  

问题是printf在解析了块之后发生了

这是因为yacc是一个自下而上的解析器。 AST的叶子是在中间节点之前构建的。

如果您希望块的类型影响其中的解析,则自上而下的方法(如递归下降解析器)可能更自然。

  

但我需要获取类别名称(示例中的“foo”)作为解析块内行的信息。

我认为最直接的方法是为每种块设置不同的语法规则,而不是使用通用的“块”规则。例如:

foo_block: FOO BRACE_OPEN foo_lines BRACE_CLOSE;

bar_block: BAR BRACE_OPEN bar_lines BRACE_CLOSE;

baz_block: BAZ BRACE_OPEN baz_lines BRACE_CLOSE;

这假设“foo”,“bar”和“baz”是词法分析者所知道的关键词,而不仅仅是通用词。

答案 1 :(得分:1)

block: WORD BRACE_OPEN NL lines BRACE_CLOSE
    { printf("category: %s\n", $1 );}

您可以在任何地方执行操作(尽管可能会导致s / r冲突):

block
    : WORD
        { printf("category: %s\n", $1 );}
      BRACE_OPEN NL lines BRACE_CLOSE
    ;

相当于

block
    : category BRACE_OPEN NL lines BRACE_CLOSE
    ;
category
    : WORD
        { printf("category: %s\n", $1 );}
    ;

你可能更喜欢后者。