2012-10-15 4 views
5

jparsec를 사용하여 비교적 단순한 문법을 ​​정의하고 활용하려고 시도하고 있지만, 어떻게해야 할 지 혼란 스럽습니다. 나는 그것이 문제 공간에 대한 나의 부적절한 이해인지 또는 jparsec의 희박하고 유익하지 않은 문서인지에 관해서는이 시점에서 알지 못한다. 아니면 둘다. jparsec의 혼동

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

그래서 당신이 운영자 등 AND, OR, NOT, IN, =, <>을 지원 볼 수 있습니다

가 나는 문법 같은 것을 가지고있다. 또한 임의로 중첩 된 괄호를 지원하여 우선 순위를 지정합니다.

토큰 화와 상당히 거리가 있다고 생각합니다.

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 패스, 그래서 그것을 확인 일하고 생각 : 여기있는거야.

이제 구문을 나타내는 형식 계층 구조가 이미 있습니다. 예를 들어, Node, BinaryNode, FieldNode, LogicalAndNode, ConstantNode 등의 클래스가 있습니다. 그리고 내가하려는 것은 Parser을 만들어서 내 토큰을 받아서 Node을 뱉어 낸다. 그리고 이것은 내가 계속 붙어있는 곳입니다.

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

두 가지 수준의 "파서"를 혼합합니다. 문자열 수준 파서는 일명 파서입니다. 스캐너 또는 렉서 및 토큰 레벨 파서가 포함됩니다. 이것은 JParsec이 어휘 분석과 통사 분석의 전통적인 분리를 구현하는 방법입니다.

코드를 깔끔하게 컴파일하려면 파서의 정의가 끝날 때 .cast() 메서드에 대한 호출을 추가 할 수 있지만 다음 오류는 cannot run a character-level parser at token level 일 수 있으므로 문제가 해결되지는 않습니다. 이 문제는 .from()을 사용하여 암시 적으로 두 세계 사이의 경계를 설정하는 최상위 파서를 정의하는 데 있습니다.

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; 
    } 
} 

} I가 변경 무엇

은 다음과 같습니다 :

  • 내가 렉서를 만들 Terminals.caseSensitive 방법을 사용하여 다음

    은 파서 작업 구현 (및 단위 테스트를)입니다 터미널 (키워드, 운영자 및 식별자)에 대해서만.사용되는 식별자 렉서는 fieldNodeParser토큰 아닌 문자를 파싱 Terminals.fragment(...)를 사용
  • 나가 토크 나이와 .from() 방법을 사용하여 세퍼레이터와 같은 WHITESPACES 암시
  • 을 jParsec (예. Terminals.IDENTIFIER)에서 기본적으로 제공 한 것이다. 도움이

희망, 아르노