2013-05-11 22 views
9

Jak dopasować dowolny tekst w ANTLRv4? Mam na myśli tekst, który jest nieznany w czasie pisania gramatyki?Dopasowanie dowolnego tekstu (zarówno symboli, jak i spacji) za pomocą ANTLR?

Moja gramatyka jest następujący:

grammar Anytext; 

line : 
    comment; 

comment : '#' anytext; 

anytext: ANY*; 

WS : [ \t\r\n]+; 

ANY : .; 

A mój kod jest następujący:

String line = "# This_is_a_comment"; 

    ANTLRInputStream input = new ANTLRInputStream(line); 

    AnytextLexer lexer = new AnytextLexer(input); 

    CommonTokenStream tokens = new CommonTokenStream(lexer); 

    AnytextParser parser = new AnytextParser(tokens); 

    ParseTree tree = parser.comment(); 

    System.out.println(tree.toStringTree(parser)); // print LISP-style tree 

Wyjście następująco:

line 1:1 extraneous input ' ' expecting {<EOF>, ANY} 
(comment # (anytext T h i s _ i s _ a _ c o m m e n t)) 

Jeśli zmienię ANY reguła

ANY : [ \t\r\n.]; 

przestaje rozpoznawać dowolny symbol.

UPDATE1

nie mam charakter linii końcowej na końcu.

UPDATE 2

Tak, zrozumiałem, że jest to niemożliwe, aby dopasować dowolny tekst z lexer lexer ponieważ nie może pozwolić wielu klas. Jeśli zdefiniuję regułę lexera dla dowolnego symbolu, to albo ukryję wszystkie inne reguły, albo nie zadziała.

Ale pytanie nie ustępuje.

Jak dopasować wszystkie symbole na poziomie parsera?

Załóżmy, że mam dane w kształcie tabeli i nie chcę przetwarzać niektórych pól i ignorować innych. Gdybym miał anytext regułę, chciałbym napisać

infoline : 
    (codepoint WS 'field1' WS field1Value) | 
    (codepoint WS 'field2' WS field2Value) | 
    (codepoint WS anytext); 

ja tu analizowania wierszy jeśli Kolumna 2 zawiera field1 i field2 wartości i ignorować wiersze inaczej.

Jak osiągnąć to podejście?

Odpowiedz

1

użyć poniższy przepis na komentarze liniowych:

LINE_COMMENT 
    : '#' ~('\n'|'\r')* '\r'? '\n' {$channel=HIDDEN;} 
    ; 

Pasuje „#” i dowolny symbol, dopóki nie dojdzie do końca linii (przerwy UNIX/linia okien).

Edycja przez 280Z28: tutaj jest dokładnie taka sama zasada w ANTLR 4 składnią:

LINE_COMMENT 
    : '#' ~[\r\n]* '\r'? '\n' -> channel(HIDDEN) 
    ; 
+0

Edytowałem twój post, aby podać dokładnie tę samą regułę w składni ANTLR 4. W oddzielnej notatce polecam * nie *, w tym '' \ r '? Terminator "\ n" w ramach samej reguły "LINE_COMMENT" (spraw, aby zużywał znaki do, ale nie wliczając końca wiersza). Jest kilka powodów, dla których polecam to, ale największy jest fakt, że w obecnej formie "LINE_COMMENT" nie będzie pasować do komentarza na ostatnim wierszu pliku, jeśli nie następuje jednoznaczne zakończenie linii. –

+0

tak, to było dla ANTLR 3, dziękuję za edycje – hoaz

+0

Dlaczego to jest takie skomplikowane? Czy można pisać łatwiej? Dlaczego moja zasada nie działa? –

7

Ważne jest, aby pamiętać, że ANTLR złamie swój pełny wkład na tokeny przed parser kiedykolwiek widzi pierwszy token (w przynajmniej zachowuje się w ten sposób). Twoja gramatyka leksykonu wygląda następująco.

T__0 : '#'; // implicit token created due to the use of '#' in parser rule comment 

WS : [ \t\r\n]+; 

ANY : .; 

Dla wejściowych, przy czym znaczniki są następujące:

  1. # (typ T__0)
  2. [przestrzeń] (typ WS)
  3. T (typ ANY)
  4. h (wpisz ANY)
  5. i (typ ANY)
  6. s (typ ANY)
  7. _ (typ ANY)
  8. i (typ ANY)
  9. s (typ ANY)
  10. _ (typ ANY)
  11. a (typ ANY)
  12. _ (typ ANY)
  13. c (typ ANY)
  14. o (typ ANY)
  15. m (typ ANY)
  16. m (typ ANY)
  17. e (typ ANY)
  18. n (typ ANY)
  19. t (typ ANY)

Aktualna gramatyka nie trafia do analizowania ponieważ WS tokena jest niedozwolone w regule comment. Byłoby analizowania ten wejście (ale może napotkasz problemy, jak rozwinąć swoją gramatykę), jeśli używany to:

// remember that '#' is its own token 
anytext: (ANY | WS | '#')*; 

Co można zrobić, to zmienić comment być regułą lexer, który zużywa charakter # wzdłuż niezależnie od tego, co następuje (w tym przypadku do końca linii):

grammar Anytext; 

line : COMMENT; 

COMMENT : '#' ~[\r\n]*; 

WS : [ \t\r\n]+; 

ANY : .; 
+0

Nie rozumiem, dlaczego napisałeś '[spacja] (type WS)'. Z mojego punktu widzenia jest również "KAŻDY"? Dlaczego nie? –

+2

@SuzanCioc ANTLR nigdy nie przypisuje więcej niż jednego typu do tokena. Znak spacji jest zgodny z regułą 'WS' i' ANY'. Aby rozwiązać niejednoznaczność, ponieważ 'WS' pojawia się przed' ANY' w gramatyce, tokenowi przypisuje się typ 'WS'. Niejednoznaczność została rozwiązana, a typ tokena został przypisany, zanim parser zobaczy token, więc analizator składni nigdy nie zobaczy żetonu znaków spacji o typie "DOWOLNY". –

+0

A co z drzewami? Są również zabronione w lexer? Co jeśli napiszę 'WS: [\ t \ r \ n]; WSZELKIE: WS | . "? Czy spacja będzie oznaczona zarówno słowem "DOWOLNY" i "WS"? –