Definite Clause Grammars
Mit DCG (-->) beschreibt man Grammatiken. Prolog übersetzt sie in Prädikate über Listen:
satz --> nominalphrase, verbalphrase.
nominalphrase --> artikel, nomen.
verbalphrase --> verb, nominalphrase.
verbalphrase --> verb.
artikel --> [der].
artikel --> [die].
nomen --> [hund].
nomen --> [katze].
verb --> [sieht].
verb --> [schlaeft].
main :-
( phrase(satz, [der, hund, sieht, die, katze]) -> writeln(gueltig) ; writeln(ungueltig) ),
( phrase(satz, [hund, der, sieht]) -> writeln(gueltig) ; writeln(ungueltig) ),
findall(S, (phrase(satz, S), length(S, L), L =< 3), Saetze), writeln(Saetze).gueltig ungueltig [[der,hund,sieht],[der,hund,schlaeft],[der,katze,sieht],[der,katze,schlaeft],[die,hund,sieht],[die,hund,schlaeft],[die,katze,sieht],[die,katze,schlaeft]]
Zahlen parsen
DCGs eignen sich gut zum Zerlegen von Text:
:- use_module(library(dcg/basics)).
zahlenliste([Z|Rest]) --> integer(Z), ( "," -> zahlenliste(Rest) ; { Rest = [] } ).
ausdruck(W) --> term(T), ausdruck_rest(T, W).
ausdruck_rest(Acc, W) --> "+", term(T), { A1 is Acc + T }, ausdruck_rest(A1, W).
ausdruck_rest(Acc, W) --> "-", term(T), { A1 is Acc - T }, ausdruck_rest(A1, W).
ausdruck_rest(W, W) --> [].
term(W) --> faktor(F), term_rest(F, W).
term_rest(Acc, W) --> "*", faktor(F), { A1 is Acc * F }, term_rest(A1, W).
term_rest(W, W) --> [].
faktor(W) --> integer(W).
faktor(W) --> "(", ausdruck(W), ")".
main :-
phrase(zahlenliste(L), `1,22,333`), writeln(L),
phrase(ausdruck(W), `2+3*(4-1)`), writeln(W),
( phrase(ausdruck(_), `2+*3`) -> writeln(ok) ; writeln('Syntaxfehler') ).[1,22,333] 11 Syntaxfehler
Mit Argumenten und Parsebäumen
satz(s(NP, VP)) --> np(NP), vp(VP).
np(np(Art, N)) --> art(Art), n(N).
vp(vp(V, NP)) --> v(V), np(NP).
art(art(der)) --> [der].
art(art(die)) --> [die].
n(n(hund)) --> [hund].
n(n(katze)) --> [katze].
v(v(jagt)) --> [jagt].
main :-
phrase(satz(Baum), [der, hund, jagt, die, katze]),
print(Baum), nl,
findall(S, phrase(satz(_), S), Alle),
length(Alle, N), format("~d mögliche Sätze~n", [N]).s(np(art(der),n(hund)),vp(v(jagt),np(art(die),n(katze)))) 16 mögliche Sätze
Operatoren und eigene Syntax
Prolog erlaubt eigene Operatoren, mit denen Programme wie Fachsprachen lesen:
:- op(700, xfx, ist_groesser_als).
:- op(200, xfy, und).
mia ist_groesser_als tom.
tom ist_groesser_als ben.
transitiv(A, B) :- A ist_groesser_als B.
transitiv(A, C) :- A ist_groesser_als B, transitiv(B, C).
main :-
( transitiv(mia, ben) -> writeln('mia ist größer als ben') ; true ),
X = (a und b und c), writeln(X),
X =.. Liste, writeln(Liste),
functor(f(a, b), Name, Stelligkeit), writeln(Name/Stelligkeit),
T =.. [punkt, 1, 2], writeln(T),
arg(2, T, Zweites), writeln(Zweites).mia ist größer als ben a und b und c [und,a,b und c] f/2 punkt(1,2) 2
Merke
- DCG-Regeln (
-->) beschreiben Grammatiken;phrase/2startet das Parsen - Argumente in DCGs bauen Parsebäume oder berechnen Werte
library(dcg/basics)bietetinteger//1,blanks//0,string//1und mehr- Eigene Operatoren (
op/3) und=..erlauben meta-programmierung
Aufgabe
Erweitere den Ausdrucksparser um Division und Leerzeichen.