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
SWI-Prolog and double quotes
Many examples of DCGs on SO, in blogs and papers use the traditional and ISO standard conforming definition for double quotes. If you take such code and use it directly with SWI-Prolog it will sometimes fail because SWI uses by default double quoted syntax for its string type.
?- phrase("abc","abc"). % succeeds in other Prologs
ERROR: Type error: `list' expected, found `"abc"' (a string)
To make the examples work in SWI-Prolog set Prolog flags in .swiplrc
or issue them directly on the top level.
:- set_prolog_flag(double_quotes, chars). % or codes
:- set_prolog_flag(back_quotes, string). % ISO conforming extension
Otherwise, to ensure the SWI-specific setting, proceed as in the following example.
:- module(course,
[ courses//1,
parse_courses/2
]).
:- [library(dcg/basics)].
:- set_prolog_flag(double_quotes, string). % SWI's default setting
:- set_prolog_flag(back_quotes, codes). % SWI's default setting
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).