2012-10-15 16 views
5

私は非常に単純な文法を定義して利用するためにjparsecを使用しようとしていますが、それについては完全に混乱しています。私はこの時点で、問題空間の理解が不十分であるのか、jparsecの疎外的で非情報的な文書なのか分かりません。または両方。jparsecの混乱

私はこのような文法何か持っている:

foo='abc' AND bar<>'def' OR (biz IN ['a', 'b', 'c'] AND NOT baz = 'foo') 

ですから、そのようなANDORNOTIN=<>などの演算子をサポートして見ることができます。優先順位を決定するために任意にネストされたかっこもサポートしています。

私はかなりトークン化していると思います。

public final class NewParser { 
    // lexing 
    private static final Terminals OPERATORS = Terminals.operators("=", "OR", "AND", "NOT", "(", ")", "IN", "[", "]", ",", "<>"); 
    private static final Parser<?> WHITESPACE = Scanners.WHITESPACES; 
    private static final Parser<?> FIELD_NAME_TOKENIZER = Terminals.Identifier.TOKENIZER; 
    private static final Parser<?> QUOTED_STRING_TOKENIZER = Terminals.StringLiteral.SINGLE_QUOTE_TOKENIZER.or(Terminals.StringLiteral.DOUBLE_QUOTE_TOKENIZER); 
    private static final Parser<?> IGNORED = Parsers.or(Scanners.WHITESPACES).skipMany(); 
    private static final Parser<?> TOKENIZER = Parsers.or(OPERATORS.tokenizer(), WHITESPACE, FIELD_NAME_TOKENIZER, QUOTED_STRING_TOKENIZER).many(); 

    @Test 
    public void test_tokenizer() { 
     Object result = TOKENIZER.parse("foo='abc' AND bar<>'def' OR (biz IN ['a', 'b', 'c'] AND NOT baz = 'foo')"); 
     Assert.assertEquals("[foo, =, abc, null, AND, null, bar, <>, def, null, OR, null, (, biz, null, IN, null, [, a, ,, null, b, ,, null, c, ], null, AND, null, NOT, null, baz, null, =, null, foo,)]", result.toString()); 
    } 
} 

test_tokenizer通るので、私はそれがOK働いて思い:ここに私が持っているものです。

ここでは、すでに構文を表す型階層があります。例えば、Node,BinaryNode,FieldNode,LogicalAndNode,ConstantNodeなどと呼ばれるクラスがあります。私がしようとしているのはを吐き出して吐き出すParserです。そして、これは私が立ち往生し続けるところです。

public static Parser<Node> parser = fieldNodeParser.from(TOKENIZER); 

しかし、それは私のコンパイルエラーを与える:私はこれを行うことができるだろうと思った

private static Parser<FieldNode> fieldNodeParser = 
    Parsers.sequence(FIELD_NAME_TOKENIZER) 
    .map(new Map<Object, FieldNode>() { 
     @Override 
     public FieldNode map(Object from) { 
      Fragment fragment = (Fragment)from; 
      return new FieldNode(fragment.text()); 
     } 
    }); 

は、私はこのような本当に単純なもので始めたいと思いました:

The method from(Parser<? extends Collection<Token>>) in the type Parser<FieldNode> is not applicable for the arguments (Parser<capture#6-of ?>) 

私のジェネリック医薬品はどこかにありますが、どこでどのように修正するかはわかりません。私はこのことについて正しいことをするつもりはないと確信しています。誰も私を啓発することはできますか?

答えて

6

2つの異なるレベルの「パーサー」を混在させています。文字列レベルのパーサーは別名です。スキャナまたはレクサー、およびトークンレベルのパーサーが含まれます。これは、JParsecが従来のレキシカル分析と構文解析の分離をどのように実装しているかを示しています。

コードをきれいにコンパイルするには、パーサーの定義の最後に.cast()メソッドへの呼び出しを追加できますが、次のエラーはcannot run a character-level parser at token levelのようになります。この問題は、.from()を使用して、2つの世界の境界を暗黙的に設定するトップレベルのパーサを定義することに由来します。ここで

は、あなたのパーサーの作業の実装(およびユニットテスト)である:

私は何が変わった
public class SampleTest { 


private static Parser<FieldNode> fieldNodeParser = Parsers.sequence(Terminals.fragment(Tokens.Tag.IDENTIFIER).map(new Map<String, FieldNode>() { 
      @Override 
      public FieldNode map(String from) { 
       String fragment = from; 
       return new FieldNode(fragment); 
      } 
     })).cast(); 

public static Parser<FieldNode> parser = fieldNodeParser.from(NewParser.TOKENIZER, Scanners.WHITESPACES); 


@Test 
public void test_tokenizer() { 
    Object result = Parsers.or(NewParser.TOKENIZER, Scanners.WHITESPACES.cast()).many().parse("foo='abc' AND bar<>'def' OR (biz IN ['a', 'b', 'c'] AND NOT baz = 'foo')"); 
    Assert.assertEquals("[foo, =, abc, null, AND, null, bar, <>, def, null, OR, null, (, biz, null, IN, null, [, a, ,, null, b, ,, null, c, ], null, AND, null, NOT, null, baz, null, =, null, foo,)]", result.toString()); 
} 

@Test 
public void test_parser() throws Exception { 
    FieldNode foo = parser.parse("foo"); 
    assertEquals(foo.text, "foo"); 
} 

public static final class NewParser { 
    // lexing 
    static final Terminals OPERATORS = Terminals.operators("=", "OR", "AND", "NOT", "(", ")", "IN", "[", "]", ",", "<>"); 
    static final Parser<String> FIELD_NAME_TOKENIZER = Terminals.Identifier.TOKENIZER.source(); 
    static final Parser<?> QUOTED_STRING_TOKENIZER = Terminals.StringLiteral.SINGLE_QUOTE_TOKENIZER.or(Terminals.StringLiteral.DOUBLE_QUOTE_TOKENIZER); 
    static final Terminals TERMINALS = Terminals.caseSensitive(new String[] { "=", "(", ")", "[", "]", ",", "<>" }, new String[] { "OR", "AND", "NOT", "IN" }); 
    static final Parser<?> TOKENIZER = Parsers.or(TERMINALS.tokenizer(), QUOTED_STRING_TOKENIZER); 
} 

private static class FieldNode { 
    final String text; 

    public FieldNode(String text) { 

     this.text = text; 
    } 
} 

}

です:

私はレクサーを作成するために Terminals.caseSensitiveメソッドを使用し
  • 端末(キーワード、演算子、識別子)のみ。使用される識別子レクサーは、fieldNodeParserトークンなく文字を解析するTerminals.fragment(...)を使用して、
  • 私はトークナイザと .from()方法を使用し、セパレータとして WHITESPACES、暗黙
  • をjParsec(例えばTerminals.IDENTIFIER)によってネイティブに提供されるものです。

希望に役立ち、 アルノー