在 yacc 中处理块
Dealing with blocks in 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", );}
问题是 printf
发生在 在 块被解析之后,但我需要获取类别名称(示例中的 "foo" ) 作为解析块内行的信息。
我想出了一个解决方案,但它似乎不是很优雅:
item : line
| block_open
| block_close;
block_open : WORD BRACE_OPEN { printf("%s {\n", ); };
block_close : BRACE_CLOSE { printf("}\n"); };
我现在可以在打开块时获取 "category" 名称。但这是正确的还是最好的方法?
谢谢!
The problem is that the printf happens after the block has been parsed
这是因为 yacc 是一个自下而上的解析器。 AST 的叶子在中间节点之前构建。
如果您希望块的类型影响其中的解析,自上而下的方法(如递归下降解析器)可能更自然。
but I need to get the category name ("foo" in the example) as an information to parse lines within the block.
我认为最直接的方法是为每种块使用不同的语法规则,而不是使用通用的 "block" 规则。例如:
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" 是词法分析器知道的关键字,而不仅仅是通用的 WORD。
block: WORD BRACE_OPEN NL lines BRACE_CLOSE
{ printf("category: %s\n", );}
您可以在任何地方放置一个动作(尽管它可能会导致 s/r 冲突):
block
: WORD
{ printf("category: %s\n", );}
BRACE_OPEN NL lines BRACE_CLOSE
;
相当于
block
: category BRACE_OPEN NL lines BRACE_CLOSE
;
category
: WORD
{ printf("category: %s\n", );}
;
你可能更喜欢后者。
我正在使用 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", );}
问题是 printf
发生在 在 块被解析之后,但我需要获取类别名称(示例中的 "foo" ) 作为解析块内行的信息。
我想出了一个解决方案,但它似乎不是很优雅:
item : line
| block_open
| block_close;
block_open : WORD BRACE_OPEN { printf("%s {\n", ); };
block_close : BRACE_CLOSE { printf("}\n"); };
我现在可以在打开块时获取 "category" 名称。但这是正确的还是最好的方法?
谢谢!
The problem is that the printf happens after the block has been parsed
这是因为 yacc 是一个自下而上的解析器。 AST 的叶子在中间节点之前构建。
如果您希望块的类型影响其中的解析,自上而下的方法(如递归下降解析器)可能更自然。
but I need to get the category name ("foo" in the example) as an information to parse lines within the block.
我认为最直接的方法是为每种块使用不同的语法规则,而不是使用通用的 "block" 规则。例如:
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" 是词法分析器知道的关键字,而不仅仅是通用的 WORD。
block: WORD BRACE_OPEN NL lines BRACE_CLOSE
{ printf("category: %s\n", );}
您可以在任何地方放置一个动作(尽管它可能会导致 s/r 冲突):
block
: WORD
{ printf("category: %s\n", );}
BRACE_OPEN NL lines BRACE_CLOSE
;
相当于
block
: category BRACE_OPEN NL lines BRACE_CLOSE
;
category
: WORD
{ printf("category: %s\n", );}
;
你可能更喜欢后者。