2017-01-08 1 views
1

Ich würde einen einfachen Lexer schreiben, der Wörter ohne Ziffern und Zahlen ignoriert whitespaces erkennt.Warum scheitert dieser einfache jparsec-Lexer?

final Parser<String> words = Patterns.isChar(CharPredicates.IS_ALPHA).many1().toScanner("word").source(); 
final Parser<String> nums = Patterns.isChar(CharPredicates.IS_DIGIT).many1().toScanner("num").source(); 
final Parser<Tokens.Fragment> tokenizer = Parsers.or(
     words.map(it -> Tokens.fragment(it, "WORD")), 
     nums.map(it -> Tokens.fragment(it, "NUM"))); 
final Parser<List<Token>> lexer = tokenizer.lexer(Scanners.WHITESPACES); 

Aber der folgende Test nicht mit der org.jparsec.error.ParserException: line 1, column 7: EOF expected, 1 encountered Ausnahme:

ich den folgenden Code verwenden jparsec v3.0 geschrieben. Mit der Zeichenfolge "abc cd 123" ist das Parsen erfolgreich.

final List<Token> got = lexer.parse("abc cd123"); 
final List<Token> expected = Arrays.asList(
     new Token(0, 3, Tokens.fragment("abc", "WORD")), 
     new Token(4, 2, Tokens.fragment("cd", "WORD")), 
     new Token(6, 3, Tokens.fragment("123", "NUM"))); 
assertEquals(expected, got); 

Was ist Ihrer Meinung nach falsch?

+0

wäre das Äquivalent zu Ihrer Token-Liste nicht '„abc cd 123“sein', da Sie lexing sind basierend auf Leerzeichen? – Aurora0001

+0

Gemäß der Dokumentation sollte 'Parser.lexer (...)' den Parser ('Tokenizer') laufen lassen, wobei er das vom Delimeter erkannte Muster (' WHITESPACES') vor und nach jedem Auftreten wiederholt ignoriert. Es ist nicht klar, ob das Trennzeichen optional ist, daher würde ich erwarten, dass der resultierende Lexer mit "abc" übereinstimmt, dann ignoriert er das Leerzeichen, stimmt dann mit "cd" überein und stimmt schließlich mit "123" überein. – maurocchi

Antwort

0

Das Problem, indem das Trennzeichen optional gelöst einfach ist:

tokenizer.lexer(Scanners.WHITESPACES.optional(null)) 
1

nächsten Test:

public class SOTest { 
    final Parser<String> words = Patterns.isChar(CharPredicates.IS_ALPHA).many1().toScanner("word").source(); 
    final Parser<String> nums = Patterns.isChar(CharPredicates.IS_DIGIT).many1().toScanner("num").source(); 
    final Parser<Tokens.Fragment> tokenizer = Parsers.or(
    words.map(it -> Tokens.fragment(it, "WORD")), 
    nums.map(it -> Tokens.fragment(it, "NUM"))); 
    final Parser<List<Token>> lexer = tokenizer.lexer(Scanners.WHITESPACES); 


    @Test public void test(){ 
    final List<Token> got = lexer.parse("abc cd 123"); 
    Asserts.assertArrayEquals(got.toArray(new Token[0]), 
     new Token(0, 3, Tokens.fragment("abc", "WORD")), 
     new Token(4, 2, Tokens.fragment("cd", "WORD")), 
     new Token(7, 3, Tokens.fragment("123", "NUM"))); 
    }  
} 

Ihre Token sind entweder nur ALPHA Zeichen oder nur DIGITS, daher ist es normal, nicht abc cd123 analysieren kann.

Die Tatsache, dass die Dokumentation sagt: „Trennzeichen vor oder nach jedem Vorkommen ignoriert werden“ sollte in dem Sinne interpretiert werden, die vor oder nach der Liste wird ignoriert analysiert Token s Begrenzungszeichen erscheinen. Aber Trennzeichen werden nicht ignoriert, um Token zu trennen, außer im Fall von Operatoren (siehe Terminals Klasse für weitere Informationen).

+0

Danke für die Klarstellung. Also habe ich die 'Parser.lexer' Methode missverstanden und sie sollte nicht auf diese Weise verwendet werden. Aber schließlich, wie man einen lexer einführt, der "abc cd123" und "abc cd 123" annimmt, die die gleiche Reihenfolge der Zeichen produzieren (ausgenommen offsets offensichtlich)? – maurocchi

Verwandte Themen