使用Grappa(Java PEG解析器)匹配或表达式

使用Grappa(Java PEG解析器)匹配或表达式,java,peg,parboiled,grappa,Java,Peg,Parboiled,Grappa,我不熟悉PEG解析,并尝试编写一个简单的解析器,将“term1或term2 anotherterm”这样的表达式解析为一个AST,它看起来像: OR -----------|--------- | | "term1" "term2 anotherterm" 我目前正在使用Grappa(),但它甚至不匹配更基本的表达式“term1或term2”。这就是我所拥有的: package grappa; import co

我不熟悉PEG解析,并尝试编写一个简单的解析器,将“term1或term2 anotherterm”这样的表达式解析为一个AST,它看起来像:

          OR
-----------|---------
|                    |
"term1"            "term2 anotherterm"
我目前正在使用Grappa(),但它甚至不匹配更基本的表达式“term1或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);
  }

}
package-grappa;
导入com.github.fge.grappa.annotations.Label;
导入com.github.fge.grappa.parsers.BaseParser;
导入com.github.fge.grappa.rules.Rule;
公共类ExprParser扩展BaseParser{
@标签(“expr”)
规则expr(){
返回序列(terms()、wsp()、字符串(“OR”)、wsp()、terms()、push(match());
}
@标签(“条款”)
规则术语(){
返回序列(空格(),
连接(term())。使用(wsp()).min(0),
空白();
}
@标签(“术语”)
规则术语(){
返回序列(一个或多个(character())、推送(match());
}
规则字符(){
返回任意一个(
"0123456789" +
“abcdefghijklmnopqrstuvwxyz”+
“ABCDEFGHIJKLMNOPQRSTUVWXYZ”+
"-_");
}
@标签(“空白”)
规则空白(){
返回联接(zeroOrMore(wsp())。使用(序列(可选)(cr()),lf()).min(0);
}
}
有人能给我指出正确的方向吗?

(这里是grappa的作者…)

好的,那么,您看起来想要的实际上是一个解析树

最近开发了grappa(2.0.x+)的扩展,可以满足您的需求:

默认情况下,Grappa仅“盲目”匹配文本,并有一个堆栈可供使用,因此您可以使用,例如:

public Rule oneOrOneOrEtc()
{
    return join(one(), push(match())).using(or()).min(1));
}
但是你所有的匹配都会在堆栈上。。。不太实用,但在某些情况下仍然可用(例如,请参见)

在你的情况下,你想要这个包裹。您可以使用它来执行此操作:

// 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);
    }
}
这里发生的情况是,如果您有一个字符串,则根节点在备选节点之前匹配:

a or b or c or d
然后根节点将匹配“整个序列”,它将有四个备选方案分别匹配a、b、c和d

首先想到这个想法,这里就有满分了

a or b or c or d