我正在用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"); };
我现在可以在打开块时获取“类别”名称。但这是正确的还是最好的方法?
谢谢!
答案 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 );}
;
你可能更喜欢后者。