Вы можете добавить 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.
Я предполагаю, что на 'ЛЕКС (Tail)' 'вы имеете в виду лексического анализатора (Tail)'. И 'lexem -> ?????' должен быть 'lexem (Token) -> ?????'. '?????' описывает, как выглядит токен. Входной поток в ваш DCG будет вашей строкой, по одному символу за раз. Итак, начните оттуда, зная, как вы видели целый токен, характер по характеру. – lurker
Да, это была моя ошибка. К сожалению, я не могу заставить его работать. Не могли бы вы дать мне короткий пример, например, как lexem (Token) -> ????? будет генерировать [sep (;)]? – Dago
см. [Это] (http://stackoverflow.com/a/29048653/874024) ответ – CapelliC