使用SWI Prolog的简单Tokenizer

时间:2016-04-19 17:49:13

标签: prolog tokenize lexer

我正在尝试实现简单的tokenizer。例如

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

会回来:

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

这就是我所拥有的。

lexer([Token | Tail]) -->
    lexem(Token),   //is this way to get tokens?
    lexer(Tail).
lexer([]) -->
    [].

lexem --> ?????

如果有任何建议如何开发它来制​​作一个有效的标记器,我将不胜感激。

1 个答案:

答案 0 :(得分:2)

你可以添加描述lexem是什么的DCG规则。例如:

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(:=) -->
   ":=".

您还可以为词法空间添加规则,例如:

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

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

使用这个最小的例子你可以查询一下:

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

标识符和数字有点棘手,因为您可能需要最长的输入匹配,例如"SUM"id('SUM')匹配,而不是id('S'), id('U'), id('M')。因此,编写标识符// 1使得它产生最长匹配作为第一解决方案并使用剪切不搜索进一步的解决方案是合适的。您可以使用内置谓词atom_chars / 2和number_chars / 2在原子/字符串和数字/字符串之间进行转换。其余的都是不言自明的:

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)}.

现在您可以查询上面的示例:

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