DCGs (Definite Clause Grammars) are a compact way to describe lists in Prolog.
DCGs (Definite Clause Grammars) are a compact way to describe lists in Prolog.
DCGs are usually associated with prolog, but similar languages such as mercury also include DCGs. They are called definite clause grammars because they represent a grammar as a set of definite clauses in first-order logic.
DCG primer by Markus Triska
Prolog and Natural-Language Analysis by Fernando C.N. Pereira and Stuart M. Shieber. code examples.
Learn Prolog Now! - Definite Clause Grammars and More Definite Clause Grammars
Some interesting contributions are available as SWI-Prolog packs, like
- dcg_util by Michael Hendricks
- dcgutils by Samer Abdallah
- dot_dcg by Lee Coomber
- pac by Kunaiki Mukai (advanced Prolog, not DCG only!)
- edgc by Peter Van Roy, Michael Hendricks
- and maybe some other.
I like to think of DCGs as Attribute Grammars made practical.
References:
DCGs provide a threading state abstraction: don't break it
Note: When using DCGs with SWI-Prolog be aware of The string type and its double quoted syntax
In other words many examples of DCGs here, in blogs and papers use the traditional Prolog definition for double quotes. If you take such code and use it with SWI-Prolog it will sometimes fail.
To avoid this problem there are Prolog flags for changing how double quotes and back quotes are defined.
Example of Prolog DCG that sets Prolog flags.
:- module(course,
[ courses//1,
parse_courses/2
]).
:- [library(dcg/basics)].
:- set_prolog_flag(double_quotes, string).
:- set_prolog_flag(back_quotes, codes).
courses([Course|Courses]) -->
course(Course),
courses(Courses), !.
courses([]) --> [].
course(course(Course,Students)) -->
string_without("\n", Course_codes),
{ string_codes(Course,Course_codes ) },
"\n",
students(Students),
(
empty_line
;
[]
).
students([Student|Students]) -->
student(Student),
students(Students).
students([]) --> [].
student(Student) -->
spaces_or_tabs_plus,
(
(
string_without("\n",Student_codes),
{ string_codes(Student,Student_codes) },
"\n"
)
;
remainder(Student_codes),
{ string_codes(Student,Student_codes) }
).
spaces_or_tabs_plus -->
space_or_tab,
spaces_or_tabs_star.
spaces_or_tabs_star -->
space_or_tab,
spaces_or_tabs_star.
spaces_or_tabs_star --> [].
space_or_tab -->
(
"\s"
|
"\t"
).
empty_line --> "\n".
parse_courses(Codes,Courses) :-
DCG = courses(Courses),
phrase(DCG,Codes,Rest),
assertion( Rest == [] ).
:- begin_tests(course).
:- set_prolog_flag(double_quotes, string).
:- set_prolog_flag(back_quotes, codes).
test(001) :-
Input = "\c
MATH2221\n\c
\t201000001\n\c
\t201000002\n\c
\n\c
MATH2251\n\c
\t201000002\n\c
\t201000003\n\c
\n\c
COMP2231\n\c
\t201000003\n\c
\t201000001\c
",
string_codes(Input,Codes),
parse_courses(Codes,Courses),
assertion( Courses ==
[
course("MATH2221",["201000001","201000002"]),
course("MATH2251",["201000002","201000003"]),
course("COMP2231",["201000003","201000001"])
]
).
:- end_tests(course).