2016-04-27 4 views
2

Ich mag eine Lexer Regel erstellen, die ein Zeichenfolgenliteral, das seinen eigenen Begrenzer definiert (genauer gesagt, die Oracle-Zitat getrennte Zeichenfolge) lesen können:Wie schreibe ich eine Lexer-Regel, die auf ein Zeichen verweist?

q'!My string which can contain 'single quotes'!' 

wo die ! dient als Trennzeichen, aber in der Theorie kann Sei irgendein Charakter.

Ist es möglich, dies über eine Lexer-Regel zu tun, ohne eine Abhängigkeit von einem bestimmten Sprachziel einzuführen?

Antwort

3

Ist es möglich, dies über eine Lexer-Regel zu tun, ohne eine Abhängigkeit von einem bestimmten Sprachziel einzuführen?

Nein, für solch eine Sache wird ein zielabhängiger Code benötigt.

Gerade falls Sie oder jemand anderes dieses Q Lesen & A fragt sich, wie diese Zielcode ausgeführt werden kann mit, hier eine kurze Demo:

lexer grammar TLexer; 

@members { 
    boolean ahead(String text) { 
    for (int i = 0; i < text.length(); i++) { 
     if (_input.LA(i + 1) != text.charAt(i)) { 
     return false; 
     } 
    } 
    return true; 
    } 
} 

TEXT 
: [nN]? (['] ([']['] | ~['])* ['] 
     | [qQ] ['] QUOTED_TEXT ['] 
     ) 
; 

// Skip everything other than TEXT tokens 
OTHER 
: . -> skip 
; 

fragment QUOTED_TEXT 
: '[' ({!ahead("]'")}?      .)* ']' 
| '{' ({!ahead("}'")}?      .)* '}' 
| '<' ({!ahead(">'")}?      .)* '>' 
| '(' ({!ahead(")'")}?      .)* ')' 
| . ({!ahead(getText().charAt(0) + "'")}? .)* . 
; 

, die mit der Klasse getestet werden können:

public class Main { 

    static void test(String input) { 
     TLexer lexer = new TLexer(new ANTLRInputStream(input)); 
     CommonTokenStream tokenStream = new CommonTokenStream(lexer); 
     tokenStream.fill(); 

     System.out.printf("input: `%s`\n", input); 

     for (Token token : tokenStream.getTokens()) { 
      if (token.getType() != TLexer.EOF) { 
       System.out.printf(" token: -> %s\n", token.getText()); 
      } 
     } 

     System.out.println(); 
    } 

    public static void main(String[] args) throws Exception { 
     test("foo q'!My string which can contain 'single quotes'!' bar"); 
     test("foo q'(My string which can contain 'single quotes')' bar"); 
     test("foo 'My string which can contain ''single quotes' bar"); 
    } 
} 

, die gedruckt werden:

input: `foo q'!My string which can contain 'single quotes'!' bar` 
    token: -> q'!My string which can contain 'single quotes'!' 

input: `foo q'(My string which can contain 'single quotes')' bar` 
    token: -> q'(My string which can contain 'single quotes')' 

input: `foo 'My string which can contain ''single quotes' bar` 
    token: -> 'My string which can contain ''single quotes' 

Die . in den alternativen

| . ({!ahead(getText().charAt(0) + "'")}? .)* . 

vielleicht ein bisschen zu freizügig sein, aber dass es mit einem negierten oder regulärem Zeichensatz wird gezwickt kann durch den Austausch.

Verwandte Themen