2

我是 PEG 解析的新手,并试图编写一个简单的解析器来解析一个表达式,例如:“term1 OR term2 anotherterm”,理想情况下,它看起来像一个 AST:

          OR
-----------|---------
|                    |
"term1"            "term2 anotherterm"

我目前正在使用 Grappa ( https://github.com/fge/grappa ),但它甚至不匹配更基本的表达式“term1 OR term2”。这就是我所拥有的:

package grappa;

import com.github.fge.grappa.annotations.Label;
import com.github.fge.grappa.parsers.BaseParser;
import com.github.fge.grappa.rules.Rule;

public class ExprParser extends BaseParser<Object> {

  @Label("expr")
  Rule expr() {
    return sequence(terms(), wsp(), string("OR"), wsp(), terms(), push(match()));
  }

  @Label("terms")
  Rule terms() {
    return sequence(whiteSpaces(),
        join(term()).using(wsp()).min(0),
        whiteSpaces());
  }

  @Label("term")
  Rule term() {
    return sequence(oneOrMore(character()), push(match()));
  }

  Rule character() {
    return anyOf(
        "0123456789" +
        "abcdefghijklmnopqrstuvwxyz" +
        "ABCDEFGHIJKLMNOPQRSTUVWXYZ" +
        "-_");
  }

  @Label("whiteSpaces")
  Rule whiteSpaces() {
    return join(zeroOrMore(wsp())).using(sequence(optional(cr()), lf())).min(0);
  }

}

谁能指出我正确的方向?

4

1 回答 1

6

(这里是格拉巴的作者……)

好的,所以,您似乎想要的实际上是一棵解析树。

最近开发了一个可以满足您需求的 grappa (2.0.x+) 扩展:https ://github.com/ChrisBrenton/grappa-parsetree 。

Grappa,默认情况下,只有“盲目”匹配文本并且有一个堆栈可供使用,所以你可以有,例如:

public Rule oneOrOneOrEtc()
{
    return join(one(), push(match())).using(or()).min(1));
}

但是你所有的比赛都会在堆栈上......不是很实用,但在某些情况下仍然可用(例如,参见sonar-sslr-grappa)。

在你的情况下,你想要这个包。你可以用它来做到这一点:

// define your root node
public final class Root
    extends ParseNode
{
    public Root(final String match, final List<ParseNode> children)
    {
        super(match, children);
    }
}

// define your parse node
public final class Alternative
    extends ParseNode
{
    public Alternative(final String match, final List<ParseNode> children)
    {
        super(match, children);
    }
}

那是最小的实现。然后你的解析器看起来像这样:

@GenerateNode(Alternative.class)
public Rule alternative() // or whatever
{
    return // whatever an alternative is
}

@GenerateNode(Root.class)
public Rule root
{
    return join(alternative())
        .using(or())
        .min(1);
}

这里发生的事情是因为根节点在替代之前匹配,如果你有一个字符串:

a or b or c or d

那么根节点将匹配“整个序列”,并且它将有四个备选方案匹配每个 a、b、c 和 d。

这里的全部功劳归于克里斯托弗·布伦顿,因为他首先提出了这个想法!

于 2016-03-21T16:19:39.693 回答