英文:
Accessing result of a golang yacc generated parser
问题
我正在尝试使用golang的yacc工具创建一个解析器。我发现nex可以简化创建词法分析器以供解析器使用。我的问题是生成的解析器没有提供访问解析结果的方法或字段。我可以将解析结果存储在全局变量中,但这似乎是不正确的。
目前,我在我的parser.y文件的顶部添加了以下内容作为初始尝试:
type ResultParser interface {
yyParser // 生成的解析器接口
Result() s.Expr // s.Expr是解析结果的接口
}
func (p *yyParserImpl) Result() s.Expr {
return p.stack[1].expr
}
func NewResultParser() ResultParser {
return &yyParserImpl{}
}
有没有更好的方法来获取解析器的结果?
(因为这感觉有点滥用生成器...)
英文:
I am trying to create a parser using golang's yacc tool. I found nex to simplify creating a lexer to give the parser. My problem now is that the generated parser has no method or field to give me access to the parsing result. I could just store the parse result in a global variable, but that seems wrong.
Currently I've added the following as an initial attempt to the top of my parser.y file:
type ResultParser interface {
yyParser // Generated parser interface
Result() s.Expr // s.Expr is an interface for the parsed result
}
func (p *yyParserImpl) Result() s.Expr {
return p.stack[1].expr
}
func NewResultParser() ResultParser {
return &yyParserImpl{}
}
Is there a recomended/better way of getting at the result from the parser?
(Since this feels like a bit of an abuse of the generator...)
答案1
得分: 6
不,访问stack[1]
不可靠。一旦堆栈需要增长到超过其初始大小16,它就不包含任何结果了(参见#16163)。
在yystack
标签后的if
语句中,创建了一个新的堆栈,并完全忘记了保存在yyParserImpl
中的堆栈。
我做了以下操作。
在词法分析器类型中添加一个result
字段:
type ShellLexer struct {
/* … */
result *ShellProgram
}
在语法的最开始处添加以下规则:
start : program {
shyylex.(*ShellLexer).result = $$
}
(这取决于Parse
方法的参数名(可以有自定义前缀),但我认为这没问题。)
英文:
No, accessing stack[1]
does not work reliably. It doesn’t contain any result as soon as the stack needs to grow beyond 16, its initial size. (See #16163.)
The if
statement after the yystack
label then creates a new stack and totally forgets about the one saved in yyParserImpl
.
I did the following.
Add a result
field to the lexer type:
type ShellLexer struct {
/* … */
result *ShellProgram
}
Extend the grammar by the following rule at the very beginning:
start : program {
shyylex.(*ShellLexer).result = $$
}
(This depends on the parameter name of the Parse
method (which can have a custom prefix), but I think that’s ok.)
答案2
得分: 1
替代方案:使用sed将额外的字段插入生成的解析器中。然后,在语法动作中赋值。
go tool yacc -o parser.go -p Filter parser.y
sed -i '/type FilterParserImpl struct/a tree *treeNode' parser.go
生成的解析器:
type FilterParserImpl struct {
tree *treeNode
lval FilterSymType
stack [FilterInitialStackSize]FilterSymType
char int
}
语法动作:
filter { Filterrcvr.tree = $1 }
英文:
Alternative solution: use sed to insert additional field into the generated parser. Then, in your grammar action, assign the value.
go tool yacc -o parser.go -p Filter parser.y
sed -i '/type FilterParserImpl struct/a tree *treeNode' parser.go
The generated parser:
type FilterParserImpl struct {
tree *treeNode
lval FilterSymType
stack [FilterInitialStackSize]FilterSymType
char int
}
Grammar action:
filter { Filterrcvr.tree = $1 }
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论