I was going through this example on DCG
integer(I) -->
digit(D0),
digits(D),
{ number_codes(I, [D0|D])
}.
digits([D|T]) -->
digit(D), !,
digits(T).
digits([]) -->
[].
digit(D) -->
[D],
{ code_type(D, digit)
}.
But this example parses an integer only if it's in the beginning of the string (because digit(D0) fails is D0 is not a number code).
How do I go about parsing an integer anywhere in the string, e.g. "abc123def"?
You might add something like this:
non_digits--> [D], {not(code_type(D, digit))}, !, non_digits.
non_digits-->[].
and then add a call to non_digits to skip non digits, e.g.:
integer_skip(I) -->
non_digits,
digit(D0),
digits(D),
{
number_codes(I, [D0|D])
},
non_digits.
Related
I created a simple parser for subset of Clojure language. For some reason it returns me a list in format [a,b,c|d], not in format [a,b,c,d]. Morover member(X, List) doesn't work with such format of list properly, i.e.
member(X, [a,b,c|d]).
X = a ;
X = b ;
X = c.
The question is how should I improve my code to fix this problem and get list in usual format ? Or maybe there is a way to transform [a,b,c|d] -> [a,b,c,d] ?
You can call e.g.
main.
[(concat x) (lambda x (inc (inc x)))]
And get:
expr([expr([expr(at(id([c,o,n,c,a,t])))|expr(at(id([x])))])|expr([expr(at(id([l,a,m,b,d,a]))),expr(at(id([x])))|expr([expr(at(id([i,n,c])))|expr([expr(at(id([i,n,c])))|expr(at(id([x])))])])])])
Code:
mydelimiter --> delimiter.
mydelimiter --> delimiter, mydelimiter.
delimiter --> [','].
delimiter --> ['\n'].
delimiter --> ['\t'].
delimiter --> ['\s'].
specsymbol('+') --> ['+'].
specsymbol('-') --> ['-'].
specsymbol('>') --> ['>'].
specsymbol('<') --> ['<'].
specsymbol('=') --> ['='].
specsymbol('*') --> ['*'].
specsymbol('_') --> ['_'].
snum(0) --> ['0'].
snum(1) --> ['1'].
snum(2) --> ['2'].
snum(3) --> ['3'].
snum(4) --> ['4'].
snum(5) --> ['5'].
snum(6) --> ['6'].
snum(7) --> ['7'].
snum(8) --> ['8'].
snum(9) --> ['9'].
numb([A]) --> snum(A).
numb([A|B]) --> snum(A), numb(B).
mynumber(num(X)) --> numb(X).
mystring(str([])) --> quotesymbol, quotesymbol.
mystring(str(S)) --> quotesymbol, anychars(S), quotesymbol.
quotesymbol --> ['\"'].
anychar(A) --> [A], {A \== '\"'}.
anychars([A]) --> anychar(A).
anychars([A|B]) --> anychar(A), anychars(B).
identifier(id(I)) --> id_start_spec(I); id_start_letter(I).
letter(L) --> [L], {is_alpha(L)}.
id_start_letter([L]) --> letter(L).
id_start_letter([L|I]) --> letter(L), ids_l(I).
ids_l([I]) --> letter(I); snum(I); specsymbol(I).
ids_l([I|Is]) --> (letter(I); snum(I); specsymbol(I)), ids_l(Is).
id_start_spec([S]) --> specsymbol(S).
id_start_spec([S|I]) --> specsymbol(S), ids_s(I).
ids_s([I]) --> snum(I); specsymbol(I).
ids_s([I|Is]) --> (snum(I); specsymbol(I)), ids_s(Is).
keyword(kw([C|K])) --> mycolonsymbol(C), id_start_letter(K).
mycolonsymbol(':') --> [':'].
myatom(at(A)) --> mynumber(A); mystring(A); identifier(A); keyword(A).
expression(expr(S)) --> myatom(S).
expression(expr(S)) --> r_br_expression(S).
expression(expr(S)) --> s_br_expression(S).
expression(expr(S)) --> f_br_expression(S).
r_br_expression(S) --> r_openbracketsymbol, expressions(S), r_closedbracketsymbol.
expressions(S) --> expression(S).
expressions([S|SS]) --> expression(S), mydelimiter, expressions(SS).
r_openbracketsymbol --> ['('].
r_closedbracketsymbol --> [')'].
s_br_expression(S) --> s_openbracketsymbol, expressions(S), s_closedbracketsymbol.
s_openbracketsymbol --> ['['].
s_closedbracketsymbol --> [']'].
f_br_expression(S) --> f_openbracketsymbol, expressions(S), f_closedbracketsymbol.
f_openbracketsymbol --> ['{'].
f_closedbracketsymbol --> ['}'].
main :-
read_string(user_input, "\n", "", _, StrIn),
atom_chars(StrIn, L),
phrase(expression(T), L),
writeln(T),
!.
First of all, use a better readable syntax, by setting the following directive in front of your code:
:- set_prolog_flag(double_quotes, chars).
Now you can write in stead of ['}'] the more compact "}", instead of ['\s'] the standard " ". Or specsymbol(+) --> "+". instead.
Second, define letter//1 and anychar//1 like so:
letter(L) --> [L], {char_type(L,alpha)}.
anychar(A) --> [A], {dif(A, '\"')}.
With this you can start to debug, best by using smaller test cases.
Also note that Prolog has a top level (prolog-toplevel), so there is no need to define main at all. Instead, you can type your query directly, or even better, consider a simpler case first:
?- phrase(expression(T),"(inc x)").
T = expr([expr(at(id("inc")))|expr(at(id("x")))]).
?- phrase(expression(T),"(x)").
T = expr(expr(at(id("x")))).
So in the first case there is an odd instance of a partial list and in the second there is no list at all. Instead, both should be (well formed) lists. The culprit is expressions//1 which should rather read:
expressions([S]) --> expression(S).
expressions([S|Ss]) -->
{Ss = [_|_]}, % redundant goal for termination
expression(S), mydelimiter, expressions(Ss).
Note that also
?- phrase(expression(T),"(inc,,,x)").
succeeds, and I am not sure that this is intended.
Graphic tokens can serve as Prolog operators that don't require single quotes.
A translation of ISO/IEC 13211-1:1995, 6.4.2 "Syntax.Tokens.Names" is:
graphic_token --> kleene_plus(graphic_token_char).
graphic_token_char --> member("#$&*+-./:<=>?#^~\\").
% some auxiliary code
kleene_plus(NT) --> NT, kleene_star(NT).
kleene_star(NT) --> "" | kleene_plus(NT).
member(Xs) --> [X], { member(X,Xs) }.
Subsection 6.4.1 "Syntax.Tokens.Layout Text" adds the following constraint:
A graphic token shall not begin with the character sequence comment open (i.e., "/*").
Enforcing that restriction in the DCG is no big deal...
graphic_token --> graphic_token_char. % 1 char
graphic_token --> % 2+ chars
[C1,C2],
{ phrase((graphic_token_char,graphic_token_char), [C1,C2]) },
{ dif([C1,C2], "/*") },
kleene_star(graphic_token_char).
... but quite ugly!
How do I make it pretty again (and keep it bidirectional)?
I'm not sure this is prettier, but maybe something like this:
graphic_token --> kleene_plus_member("#$&*+-.:<=>?#^~\\",0'/).
graphic_token --> "/", kleene_star_member("#$&+-./:<=>?#^~\\", 0'*).
kleene_plus_member(Xs, Code) --> member(Xs), kleene_star(member([Code|Xs])).
kleene_star_member(Xs, Code) --> "" | member(Xs), kleene_star(member([Code|Xs])).
The first clause of graphic_token parses a graphic token that does not begin with / and the second clause the one which starts with it.
I have defined a DFG grammar in Prolog which is something like this:
start --> subject, verb, object.
subject --> ([i]; [you]).
verb --> ([like]; [need]).
object --> article, noun.
article --> ([my];[your]).
noun --> ([car] ; [bike]).
Now, I would like to have a predicate that returned me the object part of a phrase accepted by this DFG.
For example, objectPart([i, like, my, car], X) should return X = [my, car].
How can I do this?
This can be done:
start(O) --> subject, verb, my_object(O).
subject --> ([i]; [you]).
verb --> ([like]; [need]).
my_object(L) --> article(A), noun(N), {L = [A,N]}.
article(A) --> ([my],{A=my};[your],{A=your}).
noun(N) --> ([car],{N=car} ; [bike],{N=bike}).
objectPart(Lst, R) :-
phrase(start(R), Lst).
Result :
?- objectPart([i, like, your, car], Z).
Z = [your, car] .
EDIT I change object in my_object because SWI-Prolog use object for XPCE.
I have written the DCG (Adjective phrase and prepositional phrase) in prolog, when I tried to run it, by entering ip([every,boy,loved,some,girl]), it shows out of local stack. I realised there is something wrong with the nbar. Can someone help me out? Many thanks.
%tree
treeP(Term):-
% Print the tree assuming indentation 0
treeP(0,Term),
% Tidy up with linefeed
nl.
treeP(_N,Tree):-
% Tree is just a variable
var(Tree),!,
write(Tree).
treeP(N,[Tree|Trees]):-
proper_list([Tree|Trees]),!,
write('['),
N1 is N+1,
treePNEL(N1,[Tree|Trees]),
write(']').
treeP(N,Tree):-
% Nonatomic case
Tree=..[Functor,Argument|Arguments],
!,
% Write the functor and opening parenthesis
write(Functor),write('('),
% Set N1 to new indentation for arguments
atom_length(Functor,M), N1 is N+M+1,
% Pretty-print the arguments
treePNEL(N1,[Argument|Arguments]),
% Write right parenthesis
write(')').
treeP(_N,Tree):-
% Noncompound case
write(Tree).
treePNEL(N,[Tree1,Tree2|Trees]):-
treeP(N,Tree1),
% Go to correct position for further printing
nl, tab(N),
treePNEL(N,[Tree2|Trees]).
treePNEL(N,[Tree]):-
treeP(N,Tree).
ip(Sentence):-
setof(IP,
ip(IP,Sentence,[]),
IP),
treeP(IP).
ip(SSem) --> np(NPSem), ibar(IbarSem),
{var_replace(NPSem,NPSem1),
beta(NPSem1#IbarSem,SSem)}.
ibar(VPSem) --> i(MvdVbL),vp(VPSem,MvdVbL).
i([]) --> [].
i([]) --> [Aux],{isAux(Aux)}.
i([Verb]) --> [InflVerb],{pastInfl(Verb,InflVerb),isVerb(Verb)}.
pastInfl(see,saw).
pastInfl(love,loved).
vp(VbarSem,MvdVbL) --> vbar(VbarSem,MvdVbL).
vbar(VbarSem,MvdVbL) --> v(VSem,MvdVbL), np(NPSem),
{var_replace(VSem,VSem1),
beta(VSem1#NPSem,VbarSem)}.
v(lbd(s, lbd(x,s#lbd(y,Fla))),[]) --> [Verb],
{isVerb(Verb),Fla=..[Verb,x,y]}.
v(lbd(s,lbd(x,s#lbd(y,Fla))),[MvdVb])--> [],
{Fla=..[MvdVb,x,y]}.
np(NbarSem) --> nbar(NbarSem).
nbar(NbarSem) --> adj(AdjSem),nbar(NbarSem1),
{var_replace(AdjSem,AdjSem1),beta(AdjSem1#NbarSem1,NbarSem)}.
nbar(NbarSem) --> det(DetSem),nbar(NbarSem1),
{var_replace(DetSem,DetSem1),beta(DetSem1#NbarSem1,NbarSem)}.
nbar(NSem) --> n(NSem).
nbar(NbarSem) --> nbar(NbarSem1),pp(PPSem),
{var_replace(PPSem,PPSem1),beta(PPSem1#NbarSem1,NbarSem)}.
nbar(NSem) --> n(NSem).
pp(PPSem) --> pbar(PPSem).
pbar(NbarSem) --> po(PPSem),np(NbarSem1),
{var_replace(PPSem,PPSem1),beta(PPSem1#NbarSem1,NbarSem)}.
isVerb(love).
n(lbd(x,boy(x))) --> [boy].
n(lbd(x,girl(x))) --> [girl].
det(lbd(q,lbd(p,exists(x,(q#x & p#x))))) --> [some].
det(lbd(q,lbd(p,forall(x,(q#x -> p#x))))) --> [every].
nbar(NbarSem) --> adj(AdjSem),nbar(NbarSem1)
nbar(NbarSem) --> det(DetSem),nbar(NbarSem1)
nbar(NbarSem) --> nbar(NbarSem1),pp(PPSem)
Tabling is implemented in recent versions of SWI-Prolog. By declaring the predicates (or non-terminals) using left-recursion as tabled predicates (or non-terminals), you can keep their definitions. For details, consult:
http://www.swi-prolog.org/pldoc/man?section=tabling
I have the following context free grammar in a text file 'grammar.txt'
S ::= a S b
S ::= []
I'm opening this file and able to read each line in prolog.
Now i want to tokenize each line and generate a list such as
L=[['S','::=','a','S','b'],['S','::=','#']] ('#' represents empty)
How can i do this?
Write the specification in a DCG. I give you the basic (untested), you'll need to refine it.
parse_grammar([Rule|Rules]) -->
parse_rule(Rule),
parse_grammar(Rules).
parse_grammar([]) --> [].
parse_rule([NT, '::=' | Body]) -->
parse_symbol(NT),
skip_space,
"::=",
skip_space,
parse_symbols(Body),
skip_space, !. % the cut is required if you use findall/3 (see below)
parse_symbols([S|Rest]) -->
parse_symbol(S),
skip_space,
parse_symbols(Rest).
parse_symbols([]) --> [].
parse_symbol(S) -->
[C], {code_type(C, alpha), atom_codes(S, [C])}.
skip_space -->
[C], {code_type(C, space)}, skip_space.
skip_space --> [].
This parse the whole file, using this toplevel:
...,
read_file_to_codes('grammar.txt', Codes),
phrase(parse_grammar(Grammar), Codes, [])).
You say you read the file 1 line at time: then use
...
findall(R, (get_line(L), phrase(parse_rule(R), L, [])), Grammar).
HTH