2016-04-19 8 views
0

Ich versuche, einen einfachen Tokenizer zu implementieren. Zum BeispielEinfacher Tokenizer mit SWI Prolog

phrase(lexer(L), "read N; SUM := 0; "), write(L). 

Würde zurück:

[key(read),id(N),sep(;),id(SUM),sep(:=), int(0)] 

Dies ist, was ich habe.

Ich wäre dankbar für jeden Rat, wie man es entwickelt, um einen funktionierenden Tokenizer zu machen.

+0

Ich gehe davon durch 'lex (Schwanz)' Sie meinen 'Lexer (Schwanz)'. Und 'lexem -> ?????' sollte 'lexem (Token) -> ?????' sein. '?????' beschreibt, wie ein Token aussieht. Der Eingabestream für Ihre DCG wird Ihre Zeichenfolge sein, ein Zeichen nach dem anderen. Fang also von dort an, denn du weißt, wie du ein ganzes Zeichen Charakter für Charakter gesehen hast. – lurker

+0

Ja, das war mein Fehler. Leider kann ich es nicht erfolgreich machen. Könnten Sie mir bitte ein kurzes Beispiel geben, zum Beispiel wie lexem (Token) -> ????? würde generete [sep (;)]? – Dago

+1

siehe [diese] (http://stackoverflow.com/a/29048653/874024) antwort – CapelliC

Antwort

2

Sie könnten DCG-Regeln hinzufügen, die beschreiben, was ein Lexem ist. Zum Beispiel:

lexem(key(K)) --> % key(K) is a lexem 
    key(K).   % if K is a key 
lexem(sep(S)) --> % sep(S) is a lexem 
    sep(S).   % if S is a separator 

% rules for your keywords here 
key(read) --> 
    "read". 
key(write) --> 
    "write". 

% rules for your seperators 
sep(;) --> 
    ";". 
sep(:=) --> 
    ":=". 

Sie könnten auch Regeln gerne Ihre Lexer für Leerzeichen, zB hinzufügen:

lexer(Ts) --> 
    whitespace,   % whitespace is ignored 
    lexer(Ts). 

whitespace --> 
    [W], 
    {char_type(W,space)}. % space is whitespace 

Mit diesem minimal Beispiel Sie bereits ein wenig abfragen kann:

?- phrase(lexer(L), "read ; write"). 
L = [key(read),sep(;),key(write)] ? ; 
no 

Die Bezeichner und die Nummer sind etwas kniffliger, da Sie wahrscheinlich die längste Eingabeübereinstimmung wünschen, z "SUM" als id('SUM') anstelle von id('S'), id('U'), id('M') zugeordnet. Daher ist es angebracht, den Bezeichner // 1 so zu schreiben, dass er die längste Übereinstimmung als erste Lösung erzeugt und den Schnitt verwendet, um nicht nach weiteren Lösungen zu suchen. Sie können die integrierten Prädikate atom_chars/2 und number_chars/2 verwenden, um zwischen Atomen/Strings und Zahlen/Strings zu konvertieren. Der Rest ist selbsterklärend:

lexem(id(IA)) --> 
    identifier(I), 
    !,      % longest input match 
    {atom_chars(IA,I)}. 
lexem(int(NA)) --> 
    number(A), 
    !,      % longest input match 
    {number_chars(NA,A)}. 

identifier([C|Cs]) --> % identifiers are 
    capital(C),   % capital letters 
    ident(Cs).    % followed by other cl's 

ident([C|Cs]) --> 
    capital(C), 
    ident(Cs). 
ident([]) --> 
    []. 

capital(C) --> 
    [C],     % capitals are 
    {char_type(C,upper)}. % uppercase letters 

number([D|Ds]) -->  % numbers are 
    digit(D),    % a digit followed 
    digits(Ds).   % by other digits 

digits([D|Ds]) --> 
    digit(D), 
    digits(Ds). 
digits([]) --> 
    []. 

digit(D) -->    % a single digit 
    [D], 
    {char_type(D,digit)}. 

Jetzt können Sie für Ihre obigen Beispiel abfragen:

?- phrase(lexer(L), "read N; SUM := 0; "). 
L = [key(read), id('N'), sep(;), id('SUM'), sep(:=), int('0'), sep(;)] ; 
false. 
+0

ich habe versucht, ex explenation aber für gegebenes Beispiel bekomme ich nur falsch;/ – Dago

+0

ok es funktioniert jetzt aber ich habe sep ((;)) statt sep (;). Warum das? – Dago

+0

@Dago: Vermutlich haben Sie zufällig einige zusätzliche Klammern hinzugefügt. Überprüfen Sie die Köpfe der Regeln. Übrigens, ich habe meine Antwort aktualisiert, um die Zahlen und Identifikatoren in Ihrem obigen Beispiel zu finden. – tas