В вашем предикате mygrammar/2
есть список нетерминалов и терминалов в первом аргументе и список терминалов во втором.Вероятно, это должно быть успешным, если второй аргумент имеет форму первого.Так что у вас есть мета-интерпретатор для DCG.Несколько предложений:
Ваш токенизатор в настоящее время производит [grammar('S',[a,'S',b]),grammar('S',[....]),..].
Позвольте ему вместо этого выдавать [grammar('S',[t(a),nt('S'),t(b)]),grammar('S',[....]),..]
.Таким образом, очевидно, что является терминалом, а что нетерминалом.И, о, уберите это!
myGrammar([], []).
myGrammar([t(T)|Rest], [T|Sentence]):-
myGrammar(Rest, Sentence).
myGrammar([nt(NT)|Rest], Sentence):-
grammar(NT, Rest1),
append(Rest1,Rest, NewRest),
myGrammar(NewRest, Sentence).
DCG, кстати, немного более общие, чем этот интерпретатор.
Фактическая классификация между нетерминалами и терминалами должна выполнятьсяtokenizer.
uppercasecode(C) :-
between(0'A,0'Z,C).
lowercasecode(C) :-
between(0'a,0'z,C).
Если вы используете символы (односимвольные атомы), вы будете использовать char_code(Char, Code)
для преобразования между ними.
Полная поддержка Юникода все еще находится в зачаточном состоянии.Это очень сложно из-за всех тех особых случаев для символов, как Ⓐ, который является заглавным, но все еще не может быть частью идентификатора.Но вот как вы можете сделать это в SWI на данный момент.
uppercasecode(C) :-
'$code_class'(C,upper),
'$code_class'(C,id_start).
lowercasecode(C) :-
'$code_class'(C,id_start),
'$code_class'(C,id_continue),
\+ '$code_class'(C,upper).
Обновление: тем временем для этой цели есть char_type/2
и code_type/2
.
uppercasecode(C) :-
code_class(C, upper),
code_class(C, prolog_var_start).