2012-10-15 24 views
5

Ben oldukça basit bir dilbilgisi tanımlamak ve kullanmak için jparsec kullanmaya çalışıyorum, ama bu konuda nasıl gidileceği hakkında tamamen kafam karıştı. Bu noktada, problem alanımın yeterince anlaşılmamasının ya da jparsec'in seyrek ve bilgisiz belgelerinin olup olmadığını bilmiyorum. Ya da her ikisi de. jparsec de karışıklık

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

Yani onu operatörleri gibi AND, OR, NOT, IN, =, <> destekler görebilirsiniz:

bir gramer böyle bir şey var. Önceliği belirlemek için keyfi olarak yuvalanmış parantezleri de destekler.

Sanırım tokenizasyon konusunda epey uzaktayım.

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 geçtiği, bu yüzden tamam çalışıyor düşünüyorum : İşte ne var.

Şimdi, sözdizimini temsil eden bir tür hiyerarşim var. Örneğin, Node, BinaryNode, FieldNode, LogicalAndNode, ConstantNode ve cetera isimli sınıflarım var. Yapmaya çalıştığım şey, belirteçlerimi alan ve Node numaralı tükürük olan bir Parser oluşturmaktır. Ve burası sıkışıp kalmaya devam ediyor.

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

Ama bu beni derleme hatası verir: Ben bunu yapmak mümkün olacağını düşündüm

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

:

ben böyle gerçekten basit bir şey ile başlamak düşündüm: benim jenerik bir yere scewed gibi

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

Yani görünüyor, ama ben bunu düzeltmek ya da ne kadar hiçbir fikrim yok. Doğru modaya baktığımdan bile emin değilim. Beni aydınlatabilecek kimse var mı?

cevap

6

İki farklı "ayrıştırıcı" düzeyini karıştırıyorsunuz: Dize düzeyi ayrıştırıcıları aka. tarayıcılar veya lexers ve simge düzeyindeki ayrıştırıcılar. Bu, JParsec'in sözcüksel ve sözdizimsel analizlerin geleneksel ayrışmasını nasıl uyguladığıdır.

Eğer çözümleyici işleme tanımının sonunda .cast() yöntemi çağrısı ekleyebilir, kodunuz temiz derlemek yapmak için, ama bu cannot run a character-level parser at token level gibi bir şey olacak olacak sonraki hata olarak sorunu çözmek olmaz. Bu sorun, iki dünya arasındaki sınırı kesin olarak belirleyen üst düzey ayrıştırıcınızı tanımlamak için .from() kullanımından kaynaklanır.

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

} Değiştim Ne

geçerli::

  • Bir lexer oluşturmak için Terminals.caseSensitive yöntemi kullanmak Burada

    sizin ayrıştırıcı için bir çalışma uygulamasını (ve birim testleri) 'dir sadece terminaller için (anahtar kelimeler, operatörler ve tanımlayıcılar).kullanılan tanımlayıcı lexer fieldNodeParserbelirteçleri olup karakter ayrıştırmak için Terminals.fragment(...) kullanır
  • I dizgeciklerini ile .from() yöntemi kullanmak ve ayırıcı olarak WHITESPACES, dolaylı
  • jParsec (örn. Terminals.IDENTIFIER) tarafından yerel olarak temin biridir. yardımcı olur

Umut, Arnaud