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

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

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 }

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:

确定