访问由golang yacc生成的解析器的结果。

huangapple go评论152阅读模式
英文:

Accessing result of a golang yacc generated parser

问题

我正在尝试使用golang的yacc工具创建一个解析器。我发现nex可以简化创建词法分析器以供解析器使用。我的问题是生成的解析器没有提供访问解析结果的方法或字段。我可以将解析结果存储在全局变量中,但这似乎是不正确的。

目前,我在我的parser.y文件的顶部添加了以下内容作为初始尝试:

  1. type ResultParser interface {
  2. yyParser // 生成的解析器接口
  3. Result() s.Expr // s.Expr是解析结果的接口
  4. }
  5. func (p *yyParserImpl) Result() s.Expr {
  6. return p.stack[1].expr
  7. }
  8. func NewResultParser() ResultParser {
  9. return &yyParserImpl{}
  10. }

有没有更好的方法来获取解析器的结果?
(因为这感觉有点滥用生成器...)

英文:

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:

  1. type ResultParser interface {
  2. yyParser // Generated parser interface
  3. Result() s.Expr // s.Expr is an interface for the parsed result
  4. }
  5. func (p *yyParserImpl) Result() s.Expr {
  6. return p.stack[1].expr
  7. }
  8. func NewResultParser() ResultParser {
  9. return &yyParserImpl{}
  10. }

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字段:

  1. type ShellLexer struct {
  2. /* … */
  3. result *ShellProgram
  4. }

在语法的最开始处添加以下规则:

  1. start : program {
  2. shyylex.(*ShellLexer).result = $$
  3. }

(这取决于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:

  1. type ShellLexer struct {
  2. /* … */
  3. result *ShellProgram
  4. }

Extend the grammar by the following rule at the very beginning:

  1. start : program {
  2. shyylex.(*ShellLexer).result = $$
  3. }

(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将额外的字段插入生成的解析器中。然后,在语法动作中赋值。

  1. go tool yacc -o parser.go -p Filter parser.y
  2. sed -i '/type FilterParserImpl struct/a tree *treeNode' parser.go

生成的解析器:

  1. type FilterParserImpl struct {
  2. tree *treeNode
  3. lval FilterSymType
  4. stack [FilterInitialStackSize]FilterSymType
  5. char int
  6. }

语法动作:

  1. filter { Filterrcvr.tree = $1 }
英文:

Alternative solution: use sed to insert additional field into the generated parser. Then, in your grammar action, assign the value.

  1. go tool yacc -o parser.go -p Filter parser.y
  2. sed -i '/type FilterParserImpl struct/a tree *treeNode' parser.go

The generated parser:

  1. type FilterParserImpl struct {
  2. tree *treeNode
  3. lval FilterSymType
  4. stack [FilterInitialStackSize]FilterSymType
  5. char int
  6. }

Grammar action:

  1. filter { Filterrcvr.tree = $1 }

huangapple
  • 本文由 发表于 2016年4月24日 19:49:12
  • 转载请务必保留本文链接:https://go.coder-hub.com/36822702.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定