%%% Grammar E1, a trivial fragment of English s --> np, vp. % A sentence (s) is a noun phrase (np) plus a verb phrase np --> det, n. % A noun phrase is a determiner plus a noun np --> n. % ... or just a noun. vp --> v, np. % A verb phrase is a verb and its direct object, an np vp --> v. % ... or just the verb (for intransitives). n --> [mary]. % 'mary', 'john', 'woman, 'man', 'apple' are nouns. n --> [john]. n --> [woman]. n --> [man]. n --> [apple]. det --> [the]. % 'the' is a determiner v --> [loves]. % 'loves', 'eats', and 'sings' are verbs. v --> [eats]. v --> [sings].This grammar generates sentences like “John loves Mary” and “The man sings” and “The woman eats the apple”, as well as the somewhat less plausible “The apple sings the Mary.”
?- listing([s,np,vp,n,det,v]).
s(A, B) :-
np(A, C),
vp(C, B).
np(A, B) :-
det(A, C),
n(C, B).
np(A, B) :-
n(A, B).
vp(A, B) :-
v(A, C),
np(C, B).
vp(A, B) :-
v(A, B).
n([mary|A], A).
n([john|A], A).
n([woman|A], A).
n([man|A], A).
n([apple|A], A).
det([the|A], A).
v([loves|A], A).
v([eats|A], A).
v([sings|A], A).
Yes
?-
?- s([john,loves,mary],[]). Yes ?- s([the,woman,eats,the,apple],[]). Yes ?- s([the,man,sings],[]). Yes ?- s([apple,eats,woman,the],[]). No ?- s([apple,sings,the,mary],[]). Yes ?-
?- s([the,woman,eats,the,apple],Remainder). Remainder = [] ; Remainder = [the, apple] ; No ?-In one parse, the entire input is parsed as a sentence, and the remainder is the empty list. An alternative parse, however, is just to take [the,woman,eats] as a sentence, leaving [the,apple] as the remainder.
s(
np(
pn(john)
),
vp(
v(loves),
np(
pn(mary)
)
)
)
On some productions, a second parameter is used to enforce
agreement in number between subject and verb and between
determiner and noun.
%%% E2: a trivial attribute grammar for a fragment of
%%% English, with a synthesized attribute for structural description
%%% and enforcement of number agreement.
s(s(S,P)) --> np(S,Num), vp(P,Num).
np(np(D,N),Num) --> det(D,Num), n(N,Num).
np(np(N),pl) --> n(N,pl).
np(np(N),sg) --> pn(N,sg).
vp(vp(V,O),Num) --> v(V,Num), np(O,_).
vp(vp(V),Num) --> v(V,Num).
n(n(L),Num) --> [L], { lex(L,n,Num) }.
pn(pn(L),Num) --> [L], { lex(L,pn,Num) }.
v(v(L),Num) --> [L], { lex(L,v,Num) }.
det(det(L),Num) --> [L], { lex(L,det,Num) }.
lex(mary,pn,sg).
lex(john,pn,sg).
lex(woman,n,sg).
lex(women,n,pl).
lex(man,n,sg).
lex(men,n,pl).
lex(apple,n,sg).
lex(apples,n,pl).
lex(the,det,_).
lex(some,det,pl).
lex(one,det,sg).
lex(loves,v,sg).
lex(love,v,pl).
lex(eats,v,sg).
lex(eat,v,pl).
lex(sings,v,sg).
lex(sing,v,pl).
n(n(L),Num) --> [L], { lex(L,n,Num)}.
These Prolog clauses express constraints on the grammatical
construction which are not themselves grammatical constituents. They
are sometimes called ‘guards’ (e.g. by [Brown/Blair 1990]); they correspond directly to
the ‘semantic conditions’ which are a constituent
part of attribute grammars as described by [Alblas 1991]. With the guard, this rule can be paraphrased as
saying “A noun (an n), has the structure
n(L) and the grammatical number Num,
if (a) L (for ‘lexical
form’) is a single item in the input list [L],
and (b) the relation lex contains the triple
(L,n,Num).”?- s(Struc,[john,loves,mary],[]). Struc = s(np(pn(john)), vp(v(loves), np(pn(mary)))) Yes ?- s(S,[the,woman,eats,the,apple],[]). S = s(np(det(the), n(woman)), vp(v(eats), np(det(the), n(apple)))) Yes ?- s(S,[the,man,sings],[]). S = s(np(det(the), n(man)), vp(v(sings))) Yes ?- s(S,[apple,sings,the,mary],[]). No ?- s(S,[the,apple,sings,mary],[]). S = s(np(det(the), n(apple)), vp(v(sings), np(pn(mary)))) Yes ?-
[element('http://www.example.com/PO1':purchaseOrder,
[xmlns:apo='http://www.example.com/PO1',
orderDate='1999-10-20'],
[element(shipTo,
[country='US'],
[element(name, [], ['Alice Smith']),
element(street, [], ['123 Maple Street']),
element(city, [], ['Mill Valley']),
element(state, [], ['CA']),
element(zip, [], ['90952'])
]),
element(billTo,
[country='US'],
[element(name, [], ['Robert Smith']),
element(street, [], ['8 Oak Avenue']),
element(city, [], ['Old Town']),
element(state, [], ['PA']),
element(zip, [], ['95819'])
]),
element('http://www.example.com/PO1':comment,
[],
['Hurry, my lawn is going wild!']
),
element(items, [],
[element(item,
[partNum='872-AA'],
[element(productName, [], ['Lawnmower']),
element(quantity, [], ['1']),
element('USPrice', [], ['148.95']),
element('http://www.example.com/PO1':comment,
[],
['Confirm this is electric']
)
]),
element(item,
[partNum='926-AA'],
[element(productName, [], ['Baby Monitor']),
element(quantity, [], ['1']),
element('USPrice', [], ['39.98']),
element(shipDate, [], ['1999-05-21'])
])
])
])
]
/* Definite-clause grammar for the XML Schema represented in po.xsd.
*
* This DCG was generated by a literate programming system; if
* maintenance is necessary, make changes to the source (dctgnotes.xml),
* not to this output file.
*/
purchaseOrder --> [element('http://www.example.com/PO1':purchaseOrder,
Attributes,Content)],
{
purchaseOrderType_atts(Attributes,[]),
purchaseOrderType_cont(Content,[])
}.
shipTo --> [element(shipTo,Attributes,Content)],
{
usAddress_atts(Attributes,[]),
usAddress_cont(Content,[])
}.
billTo --> [element(billTo,Attributes,Content)],
{
usAddress_atts(Attributes,[]),
usAddress_cont(Content,[])
}.
items --> [element(items,Attributes,Content)],
{
t_items_atts(Attributes,[]),
t_items_cont(Content,[])
}.
item --> [element(item,Attributes,Content)],
{
t_item_atts(Attributes,[]),
t_item_cont(Content,[])
}.
comment --> [element('http://www.example.com/PO1':comment,
Attributes,Content)],
{
xsd_string_atts(Attributes,[]),
xsd_string_cont(Content,[])
}.
But we know that the xsd:string type does not have
any attributes declared, so Attributes must be the
empty list. We can therefore define these elements this way
instead:
comment --> [element('http://www.example.com/PO1':comment,
[],Content)],
{
xsd_string_cont(Content,[])
}.
poname --> [element(name,[],Content)], { xsd_string_cont(Content,[]) }.
street --> [element(street,[],Content)], { xsd_string_cont(Content,[]) }.
city --> [element(city,[],Content)], { xsd_string_cont(Content,[]) }.
state --> [element(state,[],Content)], { xsd_string_cont(Content,[]) }.
zip --> [element(zip,[],Content)], { xsd_decimal_cont(Content,[]) }.
productName --> [element(productName,[],Content)],
{ xsd_string_cont(Content,[]) }.
quantity --> [element(quantity,[],Content)],
{ xsd_integer_cont(Content,[]) }.
'USPrice' --> [element('USPrice',[],Content)],
{ xsd_decimal_cont(Content,[]) }.
shipDate --> [element(shipDate,[],Content)],
{ xsd_date_cont(Content,[]) }.
purchaseOrderType_atts --> []. purchaseOrderType_atts --> purchaseOrderType_att, purchaseOrderType_atts. purchaseOrderType_att --> [orderDate=Date]. usAddress_atts --> []. usAddress_atts --> usAddress_att, usAddress_atts. usAddress_att --> [country='US']. /* note: fixed value! */ t_items_atts --> []. t_items_atts --> t_items_att, t_items_atts. t_items_att --> no_such_attribute. /* note that t_items_att is undefined, since there * are no attributes for the Items type */ t_item_atts --> []. t_item_atts --> t_item_att, t_item_atts. t_item_att --> [partNum=SKU].
purchaseOrderType_cont --> shipTo, billTo, opt_comment, items. opt_comment --> []. opt_comment --> comment, opt_comment. usAddress_cont --> poname, street, city, state, zip. t_items_cont --> star_item. star_item --> []. star_item --> item, star_item. t_item_cont --> productName, quantity, 'USPrice', opt_comment, opt_shipDate. opt_shipDate --> []. opt_shipDate --> shipDate.
/* In our representation of XML, character data is represented * as atoms. Need to check on handling of non-ASCII characters */ xsd_string_cont([H|T],T) :- xsd_string_value(H). xsd_string_value(LF) :- atom(LF).
/* We'll accept anything as a decimal number if we can convert * the atom to a list of character codes which can in turn be * converted to a number. */ xsd_decimal_cont([H|T],T) :- xsd_decimal_value(H). xsd_decimal_value(LF) :- atom_codes(LF,L), number_codes(N,L). xsd_integer_cont([H|T],T) :- xsd_integer_value(H). xsd_integer_value(LF) :- atom_codes(LF,L), number_codes(N,L), integer(N).
xsd_date_cont([H|T],T) :- xsd_date_value(H). xsd_date_value(LF) :- atom(LF). /* well, we really need to check this ... */
purchaseOrderType_atts --> [].
purchaseOrderType_atts --> purchaseOrderType_att, purchaseOrderType_atts.
purchaseOrderType_att --> [orderDate=Date],
{ xsd_date_value(Date) }.
usAddress_atts --> [].
usAddress_atts --> usAddress_att, usAddress_atts.
usAddress_att --> [country='US']. /* note: fixed value! */
t_items_atts --> [].
t_items_atts --> t_items_att, t_items_atts.
t_items_att --> [this_will_never_match].
/* Since it has no equal sign or value, the rule for
* t_items_att will never match anything.
* Alternatively we could leave t_items_att undefined, since there
* are no attributes for the Items type.
*/
t_item_atts --> [].
t_item_atts --> t_item_att, t_item_atts.
t_item_att --> [partNum=SKU],
{ po_sku_value(SKU) }.
<xsd:simpleType name="SKU">
<xsd:restriction base="xsd:string">
<xsd:pattern value="\d{3}-[A-Z]{2}"/>
</xsd:restriction>
</xsd:simpleType>
The pattern can be translated readily into the following
grammar operating on the character sequence of the lexical
form:
po_sku_value(LF) :- atom_chars(LF,Charseq), sku_value(Charseq,[]). sku_value --> sku_decimal_part, hyphen, sku_alpha_part. sku_decimal_part --> digit, digit, digit. sku_alpha_part --> cap_a_z, cap_a_z.
digit --> [Char], { char_type(Char,digit) }.
hyphen --> ['-'].
cap_a_z --> [Char], { char_type(Char,upper) }.
t_item_atts --> [partNum=SKU], { po_sku_value(SKU) }.
Or we could even put the constraint into the top-level rule for
the item element:
item --> [element(item,[partNum=SKU],Content)],
{
po_sku_value(SKU),
t_item_cont(Content,[])
}.
In the general case, however, it is going to be simpler to
put checking for required, forbidden, and defaulted attributes
into a separate rule, which we will here call
t_item_att_check:t_item_att_check(LAVS) :- atts_present(LAVS,[partNum]).
t_item_att_check(LAVS,AugmentedLAVS) :- atts_present(LAVS,[partNum]), atts_absent(LAVS,[]), atts_defaulted(LAVS,[],AugmentedLAVS).
atts_present(LAVS,[]).Continued in < Utilities for checking required attributes 14 > , < Utilities for checking required attributes 15 > , < Utilities for checking forbidden attributes 16 > , < Utilities for checking forbidden attributes 17 > , < Utilities for checking defaulted attributes 18 >
atts_present(LAVS,[HRA|RequiredTail]) :- att_present(LAVS,HRA), atts_present(LAVS,RequiredTail).
att_present([Attname=Attval|Tail],Attname). att_present([AVS|Tail],Attname) :- att_present(Tail,Attname).
att_present([],Attname) :- ...We don't have a rule for the empty list, though, because if we have run through the list of attribute-value specifications without finding one for the attribute name we are seeking, we want the predicate to fail. If necessary to prevent later maintenance programmers, or ourselves, from supplying the ‘missing’ induction basis by mistake, we could write:
att_present([],Attname) :- !, fail.
atts_absent(LAVS,[]).
atts_absent(LAVS,[HFA|ForbiddenTail]) :- not(att_present(LAVS,HFA)), atts_absent(LAVS,ForbiddenTail).
atts_defaulted(LAVS,[],LAVS). atts_defaulted(LAVS,[AN=AV|Tail],AugmentedLAVS) :- att_present(LAVS,AN), atts_defaulted(LAVS,Tail,AugmentedLAVS). atts_defaulted(LAVS,[AN=AV|Tail],[AN=AV|AugmentedLAVS]) :- not(att_present(LAVS,AN)), atts_defaulted(LAVS,Tail,AugmentedLAVS).
purchaseOrderType_att --> magic_att. usAddress_att --> magic_att. t_items_att --> magic_att. t_item_att --> magic_att. magic_att --> [xmlns=NS]. magic_att --> [xmlns:Pre=NS]. magic_att --> ['http://www.w3.org/2001/XMLSchema-instance':Localname=Value].
<apo:comment>Hurry, my lawn is going wild!</apo:comment>
<apo:comment>I don't know how much longer I can hold out.</apo:comment>
This is an error in the grammar above, which has been retained to
illustrate the risks of hand-translation. Instead of opt_comment --> []. opt_comment --> comment, opt_comment.(which allows arbitrarily many comments), the rule for the optional comment element should read
opt_comment --> []. opt_comment --> comment.
<apo:purchaseOrder xmlns:apo="http://www.example.com/PO1"
orderDate="1999-10-19"
orderDate="1999-10-20">
<item partNum="926-AA">
<productName>Baby Monitor</productName>
<quantity>100</quantity>
<USPrice>39.98</USPrice>
<shipDate>1999-05-21</shipDate>
</item>
<item>
<productName>Baby Monitor</productName>
<quantity>1</quantity>
<USPrice>39.98</USPrice>
<shipDate>1999-05-21</shipDate>
</item>
<zip>OX2 6NN</zip>
<quantity>one</quantity>
<USPrice>USD 39.98</USPrice>
bit ::= '0'. bit ::= '1'. bitstring ::= '' /* nothing */. bitstring ::= bit, bitstring. number ::= bitstring, fraction. fraction ::= '.', bitstring. fraction ::= ''.We might wish to calculate the length and the (unsigned base-two) value of the bitstring as attributes. Using a yacc-like notation that might look like this. Notice that scale is a top-down attribute and value and fractionalvalue are bottom-up attributes.
bit ::= '0' { $0.bitvalue = 0; }.
bit ::= '1' { $0.bitvalue = power(2,$0.scale); }.
bitstring ::= '' {
$0.value = 0;
$0.length = 0;
/* scale doesn't matter here */
}.
bitstring ::= bit, bitstring {
$0.length = $2.length + 1;
$1.scale = $0.scale;
$2.scale = $0.scale - 1;
$0.value = $1.value + $2.value;
}.
number ::= bitstring, fraction {
$1.scale = $1.length - 1;
$0.value = $1.value + $2.fractionalvalue;
}.
fraction ::= '.', bitstring {
$2.scale = -1;
$0.fractionalvalue = $2.value;
}.
fraction ::= '' {
$0.fractionalvalue = 0;
}.
bit ::= [0]
<:> bitval(0,_).
bit ::= [1]
<:> bitval(V,Scale) ::- V is **(2,Scale).
bitstring ::= []
<:> length(0)
&& value(0,_).
bitstring ::= bit^^B, bitstring^^B1
<:> length(Length) ::-
B1 ^^ length(Length1),
Length is Length1 + 1
&& value(Value,ScaleB) ::-
B ^^ bitval(VB,ScaleB),
S1 is ScaleB - 1,
B1 ^^ value(V1,S1),
Value is VB + V1.
number ::= bitstring ^^ B, fraction ^^ F
<:> value(V) ::-
B ^^ length(Length),
S is Length-1,
B ^^ value(VB,S),
F ^^ fractional_value(VF),
V is VB + VF.
fraction ::= ['.'], bitstring ^^ B
<:> fractional_value(V) ::-
S is -1,
B ^^ value(V,S).
fraction ::= []
<:> fractional_value(0).
grammar ::= rule*
rule ::= lhs '::=' rhs ('<:>' att-spec ('&&' att-spec)*)?
lhs ::= term
rhs ::= term (',' term)*
attspec ::= compound-term ('::-' goal (',' goal)*)?
compound-term ::= ATOM '(' term (',' term)* ')'
%%% E1 (trivial context-free grammar for a fragment of English) %%% in DCTG notation. s ::= np, vp. np ::= det, n. np ::= n. vp ::= v, np. vp ::= v. n ::= [mary]. n ::= [john]. n ::= [woman]. n ::= [man]. n ::= [apple]. det ::= [the]. v ::= [loves]. v ::= [eats]. v ::= [sings].
?- dctg_reconsult('ks81dctg.pl').
Yes
?- listing([s,np,vp,n,det,v]).
:- dynamic s/3.
s(node(s, [A, B], []), C, D) :-
np(A, C, E),
vp(B, E, D).
:- dynamic np/3.
np(node(np, [A, B], []), C, D) :-
det(A, C, E),
n(B, E, D).
np(node(np, [A], []), B, C) :-
n(A, B, C).
:- dynamic vp/3.
vp(node(vp, [A, B], []), C, D) :-
v(A, C, E),
np(B, E, D).
vp(node(vp, [A], []), B, C) :-
v(A, B, C).
:- dynamic n/3.
n(node(n, [[mary]], []), A, B) :-
c(A, mary, B).
n(node(n, [[john]], []), A, B) :-
c(A, john, B).
n(node(n, [[woman]], []), A, B) :-
c(A, woman, B).
n(node(n, [[man]], []), A, B) :-
c(A, man, B).
n(node(n, [[apple]], []), A, B) :-
c(A, apple, B).
:- dynamic det/3.
det(node(det, [[the]], []), A, B) :-
c(A, the, B).
:- dynamic v/3.
v(node(v, [[loves]], []), A, B) :-
c(A, loves, B).
v(node(v, [[eats]], []), A, B) :-
c(A, eats, B).
v(node(v, [[sings]], []), A, B) :-
c(A, sings, B).
Yes
?-
The predicate dctg_reconsult(File) is used to
translate a DCTG grammar into Prolog clauses and load them;
it is provided by [Abramson/Dahl/Paine 1990] and
is available from a variety of sources on the net.[10]?- s(S,[john,loves,mary],[]), write(S).
node(s,
[node(np,
[node(n, [[john]], [])],
[]),
node(vp,
[node(v, [[loves]], []),
node(np,
[node(n, [[mary]], [])],
[])],
[])],
[])
S = node(s, [node(np, [node(n, [[john]], [])], []),
node(vp, [node(v, [[loves]], []), node(np, [node(n,
[...], [])], [])], [])], [])
Yes
?- s(S,[the,woman,eats,the,apple],[]), write(S).
node(s,
[node(np,
[node(det, [[the]], []),
node(n, [[woman]], [])],
[]),
node(vp,
[node(v, [[eats]], []),
node(np,
[node(det, [[the]], []),
node(n, [[apple]], [])],
[])],
[])],
[])
S = node(s, [node(np, [node(det, [[the]], []), node(n,
[[woman]], [])], []), node(vp, [node(v, [[eats]], []),
node(np, [node(det, [...], []), node(..., ..., ...)],
[])], [])], [])
Yes
?- s(S,[the,man,sings],[]), write(S).
node(s,
[node(np,
[node(det, [[the]], []),
node(n, [[man]], [])],
[]),
node(vp,
[node(v, [[sings]], [])],
[])],
[])
S = node(s, [node(np, [node(det, [[the]], []),
node(n, [[man]], [])], []), node(vp, [node(v,
[[sings]], [])], [])], [])
Yes
?-
s ::= np^^S, vp^^P,
{ S^^number(Num), P^^number(Num) }
<:> {Attributes for non-terminal s 20}
Continued in < NP rules 21 > , < VP rules 26 > , < Pre-terminal rules 29 > , < Lexicon 30 > structure(s(Sstr,Pstr)) ::- S^^structure(Sstr), P^^structure(Pstr).
np ::= det^^D, n^^N,
{ D^^number(Num), N^^number(Num) }
<:> {NP structure attribute (for DET+N) 22}
&& {NP number attribute (for DET+N) 23}
Continued in < NP rules, cont'd 24 > , < NP rules, cont'd 25 > structure(np(Dstr,Nstr)) ::- D^^structure(Dstr), N^^structure(Nstr)
np ::= n^^N, { N^^number(pl) }
<:> structure(np(Nstr)) ::-
N^^structure(Nstr)
&& number(pl).
np ::= pn^^N, { N^^number(sg) }
<:> structure(np(Nstr)) ::-
N^^structure(Nstr)
&& number(sg).
vp ::= v^^V, np^^O
<:> structure(vp(Vs,Os)) ::-
V^^structure(Vs),
O^^structure(Os)
&& {Number attribute for VP 28}
Continued in < VP rules, cont'd 27 >
vp ::= v^^V
<:> structure(vp(Vs)) ::-
V^^structure(Vs)
&& {Number attribute for VP 28}
number(Num) ::- V^^number(Num).
n ::= [L], { lex(L,n,Num) }
<:> structure(n(L))
&& number(Num).
pn ::= [L], { lex(L,pn,Num) }
<:> structure(pn(L))
&& number(Num).
v ::= [L], { lex(L,v,Num) }
<:> structure(v(L))
&& number(Num).
det ::= [L], { lex(L,det,Num) }
<:> structure(det(L))
&& number(Num).
lex(mary,pn,sg). lex(john,pn,sg). lex(woman,n,sg). lex(women,n,pl). lex(man,n,sg). lex(men,n,pl). lex(apple,n,sg). lex(apples,n,pl). lex(the,det,_). lex(some,det,pl). lex(one,det,sg). lex(loves,v,sg). lex(love,v,pl). lex(eats,v,sg). lex(eat,v,pl). lex(sings,v,sg). lex(sing,v,pl).
?- s(S,[john,loves,mary],[]), write(S).
node(s,
[node(np,
[node(pn,
[[john]],
[structure(pn(john)),
(number(sg)::-lex(john, pn, sg))])],
[ (structure(np(_G292))::-
node(pn,
[[john]],
[structure(pn(john)),
(number(sg)::-lex(john, pn, sg))])^^structure(_G292)),
number(sg)]),
node(vp,
[node(v,
[[loves]],
[structure(v(loves)),
(number(sg)::-lex(loves, v, sg))]),
node(np,
[node(pn,
[[mary]],
[structure(pn(mary)),
(number(sg)::-lex(mary, pn, sg))])],
[(structure(np(_G424))::-
node(pn, [[mary]],
[structure(pn(mary)),
(number(sg)::-lex(mary, pn, sg))])
^^structure(_G424)),
number(sg)])],
[ (structure(vp(_G351, _G352))::-
node(v, [[loves]],
[structure(v(loves)),
(number(sg)::-lex(loves, v, sg))])^^structure(_G351),
node(np,
[node(pn, [[mary]],
[structure(pn(mary)),
(number(sg)::-lex(mary, pn, sg))])],
[(structure(np(_G424))::-
node(pn, [[mary]],
[structure(pn(mary)),
(number(sg)::-lex(mary, pn, sg))])
^^structure(_G424)),
number(sg)])^^structure(_G352)),
(number(_G373)::-
node(v, [[loves]],
[structure(v(loves)),
(number(sg)::-lex(loves, v, sg))])^^number(_G373))])],
[(structure(s(_G261, _G262))::-
node(np,
[node(pn, [[john]],
[structure(pn(john)),
(number(sg)::-lex(john, pn, sg))])],
[(structure(np(_G292))::-
node(pn, [[john]],
[structure(pn(john)),
(number(sg)::-lex(john, pn, sg))])^^structure(_G292)),
number(sg)])^^structure(_G261),
node(vp, [node(v, [[loves]],
[structure(v(loves)),
(number(sg)::-lex(loves, v, sg))]),
node(np,
[node(pn, [[mary]],
[structure(pn(mary)),
(number(sg)::-lex(mary, pn, sg))])],
[(structure(np(_G424))::-
node(pn, [[mary]],
[structure(pn(mary)),
(number(sg)::-lex(mary, pn, sg))])
^^structure(_G424)),
number(sg)])],
[(structure(vp(_G351, _G352))::-
node(v, [[loves]],
[structure(v(loves)),
(number(sg)::-lex(loves, v, sg))])
^^structure(_G351),
node(np, [node(pn, [[mary]],
[structure(pn(mary)),
(number(sg)::-lex(mary, pn, sg))])],
[(structure(np(_G424))::-
node(pn, [[mary]],
[structure(pn(mary)),
(number(sg)::-lex(mary, pn, sg))])
^^structure(_G424)),
number(sg)])^^structure(_G352)),
(number(_G373)::-
node(v, [[loves]],
[structure(v(loves)),
(number(sg)::-lex(loves, v, sg))])
^^number(_G373))])
^^structure(_G262))])
nt ::= [element(n:gi,Attributes,Content)],
{
ct_atts(A,NA,Attributes),
ct_cont(C,Content,[])
}
<:> attributes(A)
&& namespaceAttributes(NA)
&& children(C)
&& localName(gi)
&& namespacename(n).
Later, we will add further grammatical attributes.
e_purchaseOrder ::= [element('http://www.example.com/PO1':purchaseOrder,
Attributes,Content)],
{
t_PurchaseOrderType_atts(A,NA,Attributes),
t_PurchaseOrderType_cont(C,Content,[])
}
<:> localname(purchaseOrder)
{Common infoset properties for elements in po namespace 32}
.
e_shipTo ::= [element(shipTo,Attributes,Content)],
{
t_USAddress_atts(A,NA,Attributes),
t_USAddress_cont(C,Content,[])
}
<:> localname(shipTo)
{Common infoset properties for elements in po namespace 32}
.
e_billTo ::= [element(billTo,Attributes,Content)],
{
t_USAddress_atts(A,NA,Attributes),
t_USAddress_cont(C,Content,[])
}
<:> localname(billTo)
{Common infoset properties for elements in po namespace 32}
.
e_items ::= [element(items,Attributes,Content)],
{
t_Items_atts(A,NA,Attributes),
t_Items_cont(C,Content,[])
}
<:> localname(items)
{Common infoset properties for elements in po namespace 32}
.
e_item ::= [element(item,Attributes,Content)],
{
t_item_atts(A,NA,Attributes),
t_item_cont(C,Content,[])
}
<:> localname(item)
{Common infoset properties for elements in po namespace 32}
.
&& attributes(A)
&& namespaceattributes(NA)
&& children(C)
&& namespacename('http://www.example.com/PO1')
e_comment ::= [element('http://www.example.com/PO1':comment,Attributes,Content)],
{Guard to check attributes and content of strings 34}
<:> localname(comment)
{Common infoset properties for elements in po namespace 32}
.
e_name ::= [element(name,Attributes,Content)],
{Guard to check attributes and content of strings 34}
<:> localname(name)
{Common infoset properties for elements in po namespace 32}
.
e_street ::= [element(street,Attributes,Content)],
{Guard to check attributes and content of strings 34}
<:> localname(street)
{Common infoset properties for elements in po namespace 32}
.
e_city ::= [element(city,Attributes,Content)],
{Guard to check attributes and content of strings 34}
<:> localname(city)
{Common infoset properties for elements in po namespace 32}
.
e_state ::= [element(state,Attributes,Content)],
{Guard to check attributes and content of strings 34}
<:> localname(state)
{Common infoset properties for elements in po namespace 32}
.
e_zip ::= [element(zip,Attributes,Content)],
{
sT_atts(A,Attributes,[]),
xsd_decimal_cont(C,Content,[])
}
<:> localname(zip)
{Common infoset properties for elements in po namespace 32}
.
e_productName ::= [element(productName,
Attributes,Content)],
{Guard to check attributes and content of strings 34}
<:> localname(productName)
{Common infoset properties for elements in po namespace 32}
.
e_quantity ::= [element(quantity,
Attributes,Content)],
{
sT_atts(A,Attributes,[]),
t_quantity_cont(C,Content,[])
}
<:> localname(quantity)
{Common infoset properties for elements in po namespace 32}
.
e_USPrice ::= [element('USPrice',Attributes,Content)],
{
sT_atts(A,Attributes,[]),
xsd_decimal_cont(C,Content,[])
}
<:> localname('USPrice')
{Common infoset properties for elements in po namespace 32}
.
e_shipDate ::= [element(shipDate,Attributes,Content)],
{
sT_atts(A,Attributes,[]),
xsd_date_cont(C,Content,[])
}
<:> localname(shipDate)
{Common infoset properties for elements in po namespace 32}
.
{
sT_atts(A,Attributes,[]),
xsd_string_cont(C,Content,[])
}
dt_atts(Lpa,Lpna,Lavs) :- lavs_dt(LpaAll,Lavs,[]), /* parse against grammar of attributes */ partition(LpaAll,LpaPresent,Lpna), /* partition the result */ attocc_dt(LpaPresent,Lpa). /* check min, max occurrence rules */The logical variables have the following meanings:
lavs_dt ::= [].
lavs_dt ::= avs_dt, lavs_dt. /* declared attributes */
lavs_dt ::= avs_nsd, lavs_dt. /* namespace declarations */
lavs_dt ::= avs_xsi, lavs_dt. /* XSI attributes */
avs_dt ::= [an1=Av], { st1_value(Av) }.
avs_dt ::= [an2=Av], { st2_value(Av) }.
Simple types will, of course, have no declared attributes, and
the rules for declared attributes and occurrence-checking
(together with the rules for individual attributes) will be omitted.
Wildcard support can also be added here when needed.
avs_nsd ::= [xmlns=DefaultNS]
<:> localname(xmlns)
&& namespacename('http://www.w3.org/2000/xmlns/')
&& normalizedvalue(DefaultNS).
avs_nsd ::= [xmlns:Prefix=NSName]
<:> localname(Prefix)
&& namespacename('http://www.w3.org/2000/xmlns/')
&& normalizedvalue(NSName).
avs_xsi ::= ['http://www.w3.org/2001/XMLSchema-instance':Localname=Value]
<:> localname(Localname)
&& namespacename('http://www.w3.org/2001/XMLSchema-instance')
&& normalizedvalue(Value).
attocc_dt(LpaPres,LpaAll) :- atts_present(LpaPres,Lreq), atts_absent(LpaPres,Lnot), atts_defaulted(LpaPres,Ldft,LpaAll).
atts_present(LAVS,[]). atts_present(LAVS,[HRA|RequiredTail]) :- att_present(LAVS,HRA), atts_present(LAVS,RequiredTail). /* An attribute name matches if namespace and local part match */ att_present([Pa|Lpa],NS:Attname) :- Pa^^localname(Attname), Pa^^namespacename(NS). att_present([Pa|Lpa],Attname) :- att_present(Lpa,Attname). /* no base step: if we reach att_present([],Attname) we want to fail. */
atts_absent(LAVS,[]). atts_absent(LAVS,[H|T]) :- not(att_present(LAVS,H)), atts_absent(LAVS,T).
atts_defaulted(Lpa,[],Lpa). atts_defaulted(Lpa,[Padft|Ldft],LpaAll) :- atts_defaulted(Lpa,Ldft,Lpa2), att_merge(Lpa2,Padft,LpaAll).Continued in < Utility for providing defaulted attributes 39 >
att_merge([],Padft,[Padft]).
att_merge([Pa|Lpa],Padft,[Pa|Lpa]) :-
nonvar(Pa), nonvar(Lpa), nonvar(Padft),
Pa^^namespacename(NS),
Padft^^namespacename(NS),
Pa^^localname(Lnm),
Padft^^localname(Lnm).
att_merge([Pa|Lpa],Padft,Lpa2) :-
nonvar(Pa), nonvar(Lpa), nonvar(Padft),
not( {Pa^^namespacename(NS),
Padft^^namespacename(NS),
Pa^^localname(Lnm),
Padft^^localname(Lnm) } ),
att_merge(Lpa,Padft,Lpa2).
t_PurchaseOrderType_atts(Lpa,Lpna,Lavs) :-
lavs_t_PurchaseOrderType(LpaAll,Lavs,[]),
partition(LpaAll,LpaPres,Lpna),
attocc_t_PurchaseOrderType(LpaPres,Lpa).
lavs_t_PurchaseOrderType ::= []
{Grammatical attributes for empty attribute list 48}
.
lavs_t_PurchaseOrderType ::= avs_t_PurchaseOrderType^^Pa,
lavs_t_PurchaseOrderType^^Lpa
{Grammatical attributes for attribute-list recursion 49}
.
lavs_t_PurchaseOrderType ::= avs_nsd^^Pa, lavs_t_PurchaseOrderType^^Lpa
{Grammatical attributes for attribute-list recursion 49}
.
lavs_t_PurchaseOrderType ::= avs_xsi^^Pa, lavs_t_PurchaseOrderType^^Lpa
{Grammatical attributes for attribute-list recursion 49}
.
avs_t_PurchaseOrderType ::= [orderDate=Value],
{ ws_normalize(collapse,Value,SNValue),
xsd_date_value(SNValue) }
{Properties for orderDate attribute 50}
.
/* Literally copying the pattern would give us this:
attocc_t_PurchaseOrderType(LpaPres,LpaAll) :-
atts_present(LpaPres,[]),
atts_absent(LpaPres,[]),
atts_defaulted(LpaPres,[],LpaAll).
but that's pointless. Instead, we'll do the equivalent: */
attocc_t_PurchaseOrderType(L,L).
ws_normalize(preserve,Atom,Atom).Continued in < Utility for whitespace normalization 44 > , < Utility for whitespace normalization 46 >
ws_normalize(replace,In,Out) :- atom_codes(In,Lcin), ws_blanks(Lcin,Lcout), atom_codes(Out,Lcout).
/* ws_blanks(A,B): where A has any whitespace, B has a blank */ ws_blanks([],[]). ws_blanks([9|T1],[32|T2]) :- ws_blanks(T1,T2). ws_blanks([10|T1],[32|T2]) :- ws_blanks(T1,T2). ws_blanks([13|T1],[32|T2]) :- ws_blanks(T1,T2). ws_blanks([H|T1],[H|T2]) :- not(member(H,[9,10,13])), ws_blanks(T1,T2).
ws_normalize(collapse,In,Out) :- ws_normalize(replace,In,Temp), atom_codes(Temp,Lctemp), ws_collapse(Lctemp,Lcout), atom_codes(Out,Lcout).Continued in < Utility to change whitespace characters to blanks 45 > , < Utility for collapsing whitespace 47 >
/* ws_collapse(A,B): B is like A, with all strings of blanks collapsed * to single blanks, and leading and trailing blanks stripped. * ws_collapse/2 strips leading blanks, then calls ws_collapse/3 */ ws_collapse([],[]). ws_collapse([32|T1],T2) :- ws_collapse(T1,T2). ws_collapse([H|T1],[H|T2]) :- not(H=32), ws_collapse(internal,T1,T2). /* ws_collapse/3 walks past non-blanks, and when it hits a string * of blanks, it drops all but the last one before a non-blank. */ ws_collapse(internal,[],[]). ws_collapse(internal,[32],[]). ws_collapse(internal,[H|T1],[H|T2]) :- not(H=32), ws_collapse(internal,T1,T2). ws_collapse(internal,[32,32|T1],T2) :- ws_collapse(internal,[32|T1],T2). ws_collapse(internal,[32,H|T1],[32,H|T2]) :- not(H=32), ws_collapse(internal,T1,T2).
<:> attributes([])
<:> attributes([Pa|L]) ::- Lpa^^attributes(L)
<:> localname('orderDate')
&& namespacename('')
&& normalizedvalue(SNValue)
t_USAddress_atts(Lpa,Lpna,Lavs) :-
lavs_t_USAddress(LpaAll,Lavs,[]),
partition(LpaAll,LpaPres,Lpna),
attocc_t_USAddress(LpaPres,Lpa).
lavs_t_USAddress ::= []
{Grammatical attributes for empty attribute list 48}
.
lavs_t_USAddress ::= avs_t_USAddress^^Pa,
lavs_t_USAddress^^Lpa
{Grammatical attributes for attribute-list recursion 49}
.
lavs_t_USAddress ::= avs_nsd^^Pa, lavs_t_USAddress^^Lpa
{Grammatical attributes for attribute-list recursion 49}
.
lavs_t_USAddress ::= avs_xsi^^Pa, lavs_t_USAddress^^Lpa
{Grammatical attributes for attribute-list recursion 49}
.
avs_t_USAddress ::= [country='US']
<:> localname('country')
&& namespacename('')
&& normalizedvalue('US')
.
Continued in < Attribute occurrence checking for USAddress 52 >
attocc_t_USAddress(LpaPresent,LpaAll) :-
CountryAtt = node(
attribute(country),
[],
[ (namespacename('')),
(localname('country')),
(normalizedvalue('US'))
]),
atts_defaulted(LpaPres,[CountryAtt],LpaAll).
t_Items_atts(Lpa,Lpna,Lavs) :-
lavs_t_Items(LpaAll,Lavs,[]),
partition(LpaAll,LpaPres,Lpna).
lavs_t_Items ::= []
{Grammatical attributes for empty attribute list 48}
.
lavs_t_Items ::= avs_nsd^^Pa, lavs_t_Items^^Lpa
{Grammatical attributes for attribute-list recursion 49}
.
lavs_t_Items ::= avs_xsi^^Pa, lavs_t_Items^^Lpa
{Grammatical attributes for attribute-list recursion 49}
.
t_item_atts(Lpa,Lpna,Lavs) :-
lavs_t_item(LpaAll,Lavs,[]),
partition(LpaAll,LpaPres,Lpna),
attocc_t_item(LpaPres,Lpa).
lavs_t_item ::= []
{Grammatical attributes for empty attribute list 48}
.
lavs_t_item ::= avs_t_item^^Pa,
lavs_t_item^^Lpa
{Grammatical attributes for attribute-list recursion 49}
.
lavs_t_item ::= avs_nsd^^Pa, lavs_t_item^^Lpa
{Grammatical attributes for attribute-list recursion 49}
.
lavs_t_item ::= avs_xsi^^Pa, lavs_t_item^^Lpa
{Grammatical attributes for attribute-list recursion 49}
.
avs_t_item ::= [partNum=Value],
{ t_SKU_value(Value) }
<:> localname('partNum')
&& namespacename('')
&& normalizedvalue(Value)
.
/* one required attribute: partNum */
attocc_t_item(LpaPres,LpaAll) :-
atts_present(LpaPres,['':partNum]),
atts_absent(LpaPres,[]),
atts_defaulted(LpaPres,[],LpaAll).
sT_atts(Lpa,Lpna,Lavs) :-
lavs_sT(LpaAll,Lavs,[]),
partition(LpaAll,LpaPres,Lpna).
lavs_sT ::= []
{Grammatical attributes for empty attribute list 48}
.
lavs_sT ::= avs_nsd^^Pa, lavs_t_Items^^Lpa
{Grammatical attributes for attribute-list recursion 49}
.
lavs_sT ::= avs_xsi^^Pa, lavs_t_Items^^Lpa
{Grammatical attributes for attribute-list recursion 49}
.
partition(LpaAll,LpaPresent,Lpna) :-
LpaAll^^attributes(L),
partition2(L,LpaPresent,Lpna).
partition2([],[],[]).
partition2([Pa|Lpa],LpaPres,[Pa|Lpna]) :-
Pa^^localname(xmlns),
partition2(Lpa,LpaPres,Lpna).
partition2([Pa|Lpa],LpaPres,[Pa|Lpna]) :-
Pa^^namespacename('http://www.w3.org/2000/xmlns/'),
partition2(Lpa,LpaPres,Lpna).
partition2([Pa|Lpa],[Pa|LpaPres],Lpna) :-
not(Pa^^localname(xmlns)),
not(Pa^^namespacename('http://www.w3.org/2000/xmlns/')),
partition2(Lpa,LpaPres,Lpna).
t_PurchaseOrderType_cont ::=
e_shipTo^^S, e_billTo^^B, opt_e_comment^^C,
e_items^^I
{Children attribute of t_PurchaseOrder 61}
.
opt_e_comment ::= []
{Empty list of children for opt_e_comment nonterminal 59}
.
opt_e_comment ::= e_comment^^Comm
{Children for opt_e_comment nonterminal 60}
.
t_USAddress_cont ::=
e_name^^N, e_street^^S, e_city^^C, e_state^^ST, e_zip^^Z
{Children attribute of t_USAddress 58}
.
t_Items_cont ::= star_e_item^^L
{Children attribute of t_Items_cont 65}
.
star_e_item ::= []
{Empty list of children for star_e_item nonterminal 66}
.
star_e_item ::= e_item^^I, star_e_item^^L
{Children for star_e_item nonterminal 67}
.
t_item_cont ::= e_productName^^PN, e_quantity^^Q, e_USPrice^^USP,
opt_e_comment^^C, opt_e_shipDate^^S
{Children attribute of t_item 62}
.
opt_e_shipDate ::= []
{Empty list of children for opt_e_shipdate nonterminal 63}
.
opt_e_shipDate ::= e_shipDate^^S
{Children for opt_e_shipdate nonterminal 64}
.
<:> children([N,S,C,ST,Z])
<:> children([])
<:> children([Comm])
<:> children(Lpe) ::- C^^children(CC), flatten([S,B,CC,I],Lpe)
<:> children(Lpe) ::- C^^children(CC), S^^children(SC), flatten([PN,Q,USP,CC,SC],Lpe)
<:> children([])
<:> children([S])
<:> children(List) ::- L^^children(List)
<:> children([])
<:> children([I|T]) ::- L^^children(T)
xsd_string_cont ::= [Atom], { xsd_string_value(Atom) }.
xsd_decimal_cont ::= [Atom], { xsd_decimal_value(Atom) }.
xsd_integer_cont ::= [Atom], { xsd_integer_value(Atom) }.
xsd_date_cont ::= [Atom], { xsd_date_value(Atom) }.
/* In our representation of XML, character data is represented * as atoms. Handling of non-ASCII characters is OK if they are * in UTF8, but the SWI parser currently has trouble with * numeric character references */ xsd_string_value(LF) :- atom(LF).Continued in < Checking decimal and integer values 70 > , < Checking date values 71 > , < Lexical form for year 72 > , < Lexical form for month 75 > , < Lexical form for day of month 76 > , < Checking date values 77 > , < Checking date values 78 >
xsd_decimal_value(LF) :-
atom_chars(LF,L),
lexform_decimal(_,L,[]).
xsd_integer_value(LF) :-
atom_chars(LF,L),
integer(_,L,[]).
lexform_decimal ::= integer, fractionalpart.
integer ::= opt_sign, digits.
fractionalpart ::= [].
fractionalpart ::= decimalpoint.
fractionalpart ::= decimalpoint, opt_digits.
opt_sign ::= [].
opt_sign ::= ['+'].
opt_sign ::= ['-'].
decimalpoint ::= ['.'].
opt_digits ::= [].
opt_digits ::= digits.
/* We supply a 'lexval' property on digits, for use in date checking */
digits ::= digit^^D
<:> lexval([Dv]) ::- D^^lexval(Dv).
digits ::= digit^^D1, digits^^Dd
<:> lexval([D1val|Ddval]) ::- D1^^lexval(D1val), Dd^^lexval(Ddval).
digit ::= [Ch], { char_type(Ch,digit) }
<:> lexval(Ch).
xsd_date_value(LF) :-
atom_chars(LF,LC),
lexform_date(_,LC,[]).
lexform_date ::= year^^Y, hyphen, month^^M, hyphen, day^^D,
{ Y^^val(Yv), M^^val(Mv), D^^val(Dv),
dateok(Yv,Mv,Dv) }.
/* Years must have at least four digits */ yearnum ::= digit^^D1, digit^^D2, digit^^D3, digits^^Dd <:> val(Num) ::- D1^^lexval(Dv1), D2^^lexval(Dv2), D3^^lexval(Dv3), Dd^^lexval(Dv4), flatten([Dv1,Dv2,Dv3,Dv4],LF), number_chars(Num,LF). year ::= yearnum^^Y <:> val(Num) ::- Y^^val(Num). year ::= ['-'], yearnum^^Y <:> val(Num) ::- Y^^val(N), Num is 0 - N. hyphen ::= ['-'].
month ::= ['0'], ['1']. month ::= ['0'], ['2']. ... month ::= ['0'], ['9']. month ::= ['1'], ['0']. month ::= ['1'], ['1']. month ::= ['1'], ['2'].
month ::= ['0'], digit^^D
{ D^^lexval(Dv), number_chars(V,Dv), V > 0 }
<:> val(V).
month ::= ['1'], digit^^D
{ D^^lexval(Dv), number_chars(V,Dv), V < 3 }
<:> val(Val) ::- Val is 10 + V.
month ::= digit^^D1, digit^^D2,
{ D1^^lexval(Dv1),
D2^^lexval(Dv2),
number_chars(Num,[Dv1,Dv2]),
Num > 0,
Num < 13 }
<:> val(Num).
day ::= digit^^D1, digit^^D2,
{ D1^^lexval(Dv1),
D2^^lexval(Dv2),
number_chars(Num,[Dv1,Dv2]),
Num > 0,
Num < 32 }
<:> val(Num).
dateok(_Y,_M,D) :- D < 29. dateok(_Y,M,29) :- M =\= 2. dateok(_Y,M,30) :- M =\= 2. dateok(_Y,M,31) :- member(M,[1,3,5,7,8,10,12]). dateok(Y,2,29) :- (Y >= 0 -> Yx = Y ; Yx is Y + 1), /* adjust for BC */ 0 is Yx mod 4, Lc is Yx mod 100, L4c is Yx mod 400, leapyearcheck(Lc,L4c).
leapyearcheck(C,_Q) :- C =\= 0. /* it's not a century year, so leapyear */ leapyearcheck(0,0). /* it's a quad-century year, so leapyear */
t_SKU_cont ::= [Atom], { t_SKU_value(Atom) }.
t_quantity_cont ::= [Atom], { t_quantity_value(Atom) }.
t_SKU_value(LF) :-
atom_chars(LF,Charseq),
sku_value(_Structure,Charseq,[]).
sku_value ::= sku_decimal_part, hyphen, sku_alpha_part.
sku_decimal_part ::= digit, digit, digit.
sku_alpha_part ::= cap_a_z, cap_a_z.
cap_a_z ::= [Char], { char_type(Char,upper) }.
Continued in < Value-checking rules for quantities 81 > t_quantity_value(LF) :- atom_chars(LF,Lchars), integer(_,Lchars,[]), number_chars(Num,Lchars), Num < 100.
/* podctg.pl: a definite-clause translation grammar representation
* of the sample purchase-order schema from the XML Schema tutorial.
*
* This DCTG was generated by a literate programming system; if
* maintenance is necessary, make changes to the source (dctgnotes.xml),
* not to this output file.
*/
{Predicates for purchase-order material 83}
{Generic utilities for DCTG-encoded schemas 84}
{Rules for elements with complex types 31}
{Rules for elements with simple types 33}
{Attribute handling for purchaseOrderType 42}
{Attribute handling for USAddress 51}
{Attribute handling for Items type 53}
{Attribute handling for t_item 54}
{Attribute handling for simple types 55}
{Rules for purchase-order content models 57}
{Simple-type content rules for purchase-order types 79}
{Value-checking rules for SKU 80}
{Grammar rules for namespace and XSI attributes 35}
{Utilities for checking attribute occurrences 36}
{Utility for checking absent attributes 37}
{Utility for providing defaulted attributes 38}
{Utility for whitespace normalization 43}
{partition predicate 56}
{xsd_Typename_cont rules 68}
{xsd_Typename_value rules 69}
nt ::= [element(n:gi,Attributes,Content)],
{
ct_atts(A,NA,Attributes),
ct_cont(C,Content,[])
}
<:> attributes(A)
&& namespaceAttributes(NA)
&& children(C)
&& localname(gi)
&& namespacename(n).
the rule pattern should read
nt ::= [element(n:gi,Attributes,Content)],
{
ct_atts(A,NA,Attributes),
ct_cont(C,Content,[]),
C^^children(Ch)
}
<:> attributes(A)
&& namespaceAttributes(NA)
&& children(Ch)
&& localname(gi)
&& namespacename(n).
or else the attribute-value assignment should read differently: not
&& children(C)but
&& children(Ch) ::- C^^children(Ch)
xsd_errorcode(cvc-simple-type,String,Typename,Desc) :- concat_atom(['The string "',String, '" is not locally valid w.r.t. the given simple type ', Typename,'.'], Desc). xsd_errorcode(cvc-datatype-valid.1,S,T,Desc) :- concat_atom(['The lexical form "',S, '" is not datatype-valid w.r.t. the given simple type ', T,': it matches no literal in the lexical space.'], Desc). xsd_errorcode(cvc-datatype-valid.2,S,T,Desc) :- concat_atom(['The lexical form "',S, '" is not datatype-valid w.r.t. the given simple type ', T,': it denotes a value not in the value space.'], Desc).Continued in < Error codes for elements with simple types 86 >
xsd_errorcode(cvc-type.3.1.1,Gi,Tn,Anbad,Desc) :-
concat_atom(['The ',Gi,' element is not locally valid: ',
'its type definition (', Tn,
') is simple, but it has attributes other than ',
'xsi:type, xsi:nil, xsi:schemaLocation, and '
'xsi:noNamespaceSchemaLocation (specifically '
Anbad, ').'],
Desc).
xsd_errorcode(cvc-type.3.1.2,Gi,Tn,GiChild,Desc) :-
concat_atom(['The ',Gi,' element is not locally valid: ',
'its type definition (',Tn,') is simple, but it has '
'element children (',GiChild,').'],
Desc).
xsd_errorcode(cvc-type.3.1.2,Gi,Tn,Desc) :-
concat_atom(['The ',Gi,' element is not locally valid: ',
'its content is not a legal lexical form for its '
'simple type ',Tn,'.'],
Desc).
xsd_string_value('xsd:string',LF,[]) :- atom(LF).
xsd_string_value('xsd:string',LF,[Err]) :-
not(atom(LF)),
xsd_errorcode(cvc-simple-type,LF,'xsd:string',DescTemp),
concat_atom(
[DescTemp,' N.B. This error was thought to be impossible.'],
Desc),
Err = error(cvc-simple-type,Desc).
xsd_string_cont(Gi,LIn,LPn,LErr) :-
member(element(GiChild,_Atts,_Content),LIn), !,
xsd_errorcode(cvc-type.3.1.2,Gi,'xsd:string',GiChild,Desc),
LErr = [error(cvc-type.3.1.2,Desc)],
lax_validate_seq(LIn,LPn).
/* This assumes that even though having any element children
* makes the element we are checking illegal, we should strictly
* speaking validate all of the element children in lax mode
* anyway (cvc-assess-elt clause 2). */
xsd_string_cont(_Gi,LIn,LPn,LErr) :-
gr_xsd_string(LErr,Pn,LIn,[]),
Pn^^children(LPn).
gr_xsd_string(LErr) ::= [Atom],
{ xsd_string_value('xsd:string',Atom,LErr) }
<:> children([Atom]).
lax_validate_seq(LIn,LPn) :-
gr_lax_sequence(Node,LIn,[]),
Node^^children(LPn).
gr_lax_sequence ::= []
<:> children([]).
gr_lax_sequence ::= gr_lax_item^^Item, gr_lax_sequence^^Seq
<:> children([CI|CS]) ::-
Item^^child(CI),
Seq^^children(CS).
gr_lax_item ::= [PCDATA], { atom(PCDATA) },
<:> child([PCDATA]).
gr_lax_item ::= [element(Gi,Atts,Cont)],
{ schema_lookup(element,Gi,Rule),
call(Rule(Node,[element(Gi,Atts,Cont)],[]))
}
<:> child(Node).
/* Define the mapping from generic identifiers to grammar rules. */
schema_lookup(element,'...':purchaseOrder,e_purchaseOrder).
e_purchaseOrder ::= [element('http://www.example.com/PO1':purchaseOrder,
e_shipTo ::= [element(shipTo,Attributes,Content)],
e_billTo ::= [element(billTo,Attributes,Content)],
e_items ::= [element(items,Attributes,Content)],
e_item ::= [element(item,Attributes,Content)],
e_comment ::= [element('http://www.example.com/PO1':comment,Attributes,Content)],
e_name ::= [element(name,Attributes,Content)],
e_street ::= [element(street,Attributes,Content)],
e_city ::= [element(city,Attributes,Content)],
e_state ::= [element(state,Attributes,Content)],
e_zip ::= [element(zip,Attributes,Content)],
e_productName ::= [element(productName,
e_quantity ::= [element(quantity,
e_USPrice ::= [element('USPrice',Attributes,Content)],
e_shipDate ::= [element(shipDate,Attributes,Content)],
gr_lax_item ::= e_purchaseOrder^^E
<:> child(E).
gr_lax_item ::= e_shipTo^^E
<:> child(E).
/* ... */
gr_lax_item ::= e_shipDate^^E
<:> child(E).
gr_lax_item ::= unknown_element^^E
<:> child(E).
unknown_element ::= [element(Ns:Ln,Attributes,Content)],
{
check_unknown_atts(A,NA,Attributes),
lax_validate_seq(Content,LPn)
}
<:> localname(Ln)
&& namespacename(Ns)
&& attributes(A)
&& namespaceattributes(NA)
&& children(LPn)
&& schemaerrorcode(error(cvc-assess-elt.1.1.1,Desc)) ::-
xsd_errorcode(cvc-assess-elt.1.1.1,Desc)
&& validationattempted(ValidationCode) ::-
find_validationcode(lax,LPn)
/* ... */
.
unknown_element ::= [Gi,Attributes,Content)],
{
check_unknown_atts(A,NA,Attributes),
lax_validate_seq(Content,LPn)
}
<:> localname(Gi)
&& namespacename(Ns)
&& attributes(A)
&& namespaceattributes(NA)
&& children(LPn)
&& schemaerrorcode(error(cvc-assess-elt.1.1.1,Desc)) ::-
xsd_errorcode(cvc-assess-elt.1.1.1,Desc)
&& validationattempted(ValidationCode) ::-
find_validationcode(lax,LPn)
/* ... */
.
/* po4.pl: a definite-clause translation grammar representation
* of the sample purchase-order schema from the XML Schema tutorial.
*
* This DCTG was generated by a literate programming system; if
* maintenance is necessary, make changes to the source (dctgnotes.xml),
* not to this output file.
*/
{Predicates for purchase-order material 83}
{Generic utilities for DCTG-encoded schemas 84}
{Rules for elements with complex types 31}
{Rules for elements with simple types 33}
{Attribute handling for purchaseOrderType 42}
{Attribute handling for USAddress 51}
{Attribute handling for Items type 53}
{Attribute handling for t_item 54}
{Attribute handling for simple types 55}
{Rules for purchase-order content models 57}
{Simple-type content rules for purchase-order types 79}
{Value-checking rules for SKU 80}
{Grammar rules for namespace and XSI attributes 35}
{Utilities for checking attribute occurrences 36}
{Utility for checking absent attributes 37}
{Utility for providing defaulted attributes 38}
{Utility for whitespace normalization 43}
{partition predicate 56}
{Content-checking rules for simple types 88}
{Value checking rules for simple types 87}
{Error codes for simple types 85}
t_PurchaseOrderType_cont ::= e_shipTo, e_billTo, opt_e_comment, e_items. opt_e_comment ::= []. opt_e_comment ::= e_comment.to
t_PurchaseOrderType_cont ::= opt_ws, t_PurchaseOrderType_cont2. t_PurchaseOrderType_cont2 ::= e_shipTo, opt_ws, e_billTo, opt_ws, opt_e_comment, e_items, opt_ws. opt_e_comment ::= []. opt_e_comment ::= e_comment, opt_ws.
b --> [element(b,Attributes,Content)],
{
b_atts(Attributes,[]),
b_cont(Content,[])
}.
a --> [element(a,Attributes,Content)],
{
a_atts(Attributes,[]),
a_cont(Content,[])
}.
and also
b --> [element(a,Attributes,Content)],
{
a_atts(Attributes,[]),
a_cont(Content,[])
}.
Abramson, Harvey. 1984. “Definite Clause Translation Grammars”. Proceedings of the 1984 International Symposium on Logic Programming, Atlantic City, New Jersey, February 6-9, 1984, pp. 233-240. (IEEE-CS 1984, ISBN 0-8186-0522-7)
Abramson, Harvey, and Veronica Dahl. 1989. Logic Grammars. Symbolic Computation AI Series. Springer-Verlag, 1989.
Abramson, Harvey, and Veronica Dahl, rev. Jocelyn Paine. 1990. DCTG: Prolog definite clause translation grammar translator. (Prolog code for translating from DCTG notation to standard Prolog. Note says syntax extended slightly by Jocelyn Paine to accept && between specifications of grammatical attributes, to minimize need for parentheses. Available from numerous AI/NLP software repositotries, including http://www-2.cs.cmu.edu/afs/cs/project/ai-repository/ai/lang/prolog/code/syntax/dctg/0.html, http://www.ims.uni-stuttgart.de/ftp/pub/languages/prolog/libraries/imperial_college/dctg.tar.gz, and http://www.ifs.org.uk/~popx/prolog/dctg/.)
Alblas, Henk. 1991. “Introduction to attribute grammars”. Attribute grammars, applications and systems: International Summer School SAGA, Prague, Czechoslovakia, June 4-13, 1991, Proceedings, pp. 1-15. Berlin: Springer, 1991. Lecture Notes in Computer Science, 545.
Bratko, Ivan. 1990. Prolog programming for artificial intelligence. Second edition. Wokingham: Addison-Wesley. xxi, 597 pp.
Brown, Allen L., Jr., and Howard A. Blair. 1990. “A logic grammar foundation for document representation and layout”. In EP90: Proceedings of the International Conference on Electronic Publishing, Document Manipulation and Typography, ed. Richard Furuta. Cambridge: Cambridge University Press, 1990, pp. 47-64.
Brown, Allen L., Jr., Toshiro Wakayama, and Howard A. Blair. 1992. “A reconstruction of context-dependent document processing in SGML”. In EP92: Proceedings of Electronic Publishing, 1992, ed. C. Vanoirbeek and G. Coray. Cambridge: Cambridge University Press, 1992. Pages 1-25.
Brüggemann-Klein, Anne. 1993. Formal models in document processing. Habilitationsschrift, Freiburg i.Br., 1993. 110 pp. Available at ftp://ftp.informatik.uni-freiburg.de/documents/papers/brueggem/habil.ps (Cover pages archival copy also at http://www.oasis-open.org/cover/bruggDissert-ps.gz).
Clocksin, W. F., and C. S. Mellish. Programming in Prolog. Second edition. Berlin: Springer, 1984.
Gal, Annie, Guy Lapalme, Patrick Saint-Dizier, and Harold Somers. 1991. Prolog for natural language processing. Chichester: Wiley, 1991. xiii, 306 pp.
Gazdar, Gerald, and Chris Mellish. 1989. Natural language processing in PROLOG: An introduction to computational linguistics. Wokingham: Addison-Wesley, 1989. xv, 504 pp.
Grune, Dick, and Ceriel J. H. Jacobs. 1990. Parsing techniques: a practical guide. New York, London: Ellis Horwood, 1990. Postscript of the book is available from the first author's Web site at http://www.cs.vu.nl/~dick/PTAPG.html
Holstege, Mary, and Asir S. Vedamuthu, ed. 2002. XML Schema: Component Designators. W3C Working Draft 19 December 2002. [Cambridge, Sophia-Antipolis, and Tokyo]: World Wide Web Consortium. http://www.w3.org/2002/12/xml-schema-component-designators.html
Knuth, D. E. 1968. “Semantics of context-free languages”. Mathematical Systems Theory 2: 127-145.
König, Esther, and Roland Seiffert. Grundkurs PROLOG für Linguisten. Tübingen: Francke, 1989. [= Uni-Taschenbücher 1525]
Pereira, Fernando C. N., and Stuart M. Shieber, Prolog and natural-language analysis. CSLI lecture notes 10. Stanford: Center for the study of language and information, 1987.
Sperberg-McQueen, C. M. 2002a. “A logic grammar representation for XML Schema”. Working paper prepared for the W3C XML Schema Working Group. [Incomplete]
Sperberg-McQueen, C. M. 2002b. “An XML Schema validator in logic-grammar form”. Working paper prepared for the W3C XML Schema Working Group. [Incomplete]
Stepney, Susan. High-integrity compilation. Prentice-Hall. Available from http://www-users.cs.york.ac.uk/~susan/bib/ss/hic/index.htm. Chapter 3 (Using Prolog) provides a terse introduction to DCTG notation and use.
W3C (World Wide Web Consortium). 2001a. “XML Schema Part 0: Primer”, ed. David Fallside. W3C Recommendation, 2 May 2001. [Cambridge, Sophia-Antipolis, Tokyo: W3C] http://www.w3.org/TR/xmlschema-0/.
W3C (World Wide Web Consortium). 2001b. XML Schema Part 1: Structures, ed. Henry S. Thompson, David Beech, Murray Maloney, and Noah Mendelsohn. W3C Recommendation 2 May 2001. [Cambridge, Sophia-Antipolis, and Tokyo]: World Wide Web Consortium. http://www.w3.org/TR/2001/REC-xmlschema-1-20010502/
W3C (World Wide Web Consortium). 2001c. XML Schema Part 2: Datatypes, ed. Biron, Paul V. and Ashok Malhotra. W3C Recommendation 2 May 2001. [Cambridge, Sophia-Antipolis, and Tokyo]: World Wide Web Consortium. http://www.w3.org/TR/2001/REC-xmlschema-2-20010502/
Wielemaker, Jan. “SWI-Prolog SGML/XML parser: Version 1.0.14, March 2001”. http://www.swi-prolog.org/packages/sgml2pl.html
['d:/usr/lib/prolog/http_open']. % load the library
http_open('http://www.w3.org/2001/XMLSchema.xsd',XSDStream),
load_xml_file(stream(XSDStream),XSD),
close(XSDStream).
/* potest: simple one-item test routine for SWI Prolog
*
* This DCG was generated by a literate programming system; if
* maintenance is necessary, make changes to the source (dctgnotes.xml),
* not to this output file.
*/
grammar_version(current,dctg,'d:/home/cmsmcq/2003/schema/dctg/po4.pl').
grammar_version(old,dctg,'d:/home/cmsmcq/2003/schema/dctg/podctg.pl').
grammar_version(dcg,dcg,'d:/home/cmsmcq/2003/schema/dctg/podcg3.pl').
potest(Grammar,dcg,XMLDocument) :-
write('Loading grammar '), write(Grammar), write('...'), nl,
consult(Grammar),
write('Loading document '), write(XMLDocument), write('...'), nl,
load_structure(XMLDocument,Infoset,[dialect(xmlns),space(remove)]),
(purchaseOrder(Infoset,[]) -> writeq('yes') ; writeq('no')),
nl.
potest(Grammar,dctg,XMLDocument) :-
write('Loading grammar '), write(Grammar), write('...'), nl,
consult('d:/usr/lib/prolog/msmdctg.pl'),
dctg_reconsult(Grammar),
write('Loading document '), write(XMLDocument), write('...'), nl,
load_structure(XMLDocument,Infoset,[dialect(xmlns),space(remove)]),
(e_purchaseOrder(_Structure,Infoset,[]) -> writeq('yes') ; writeq('no')),
nl.
potest2(XMLDocument,dcg) :-
write('Loading document '), write(XMLDocument), write('...'), nl,
load_structure(XMLDocument,Infoset,[dialect(xmlns),space(remove)]),
(purchaseOrder(Infoset,[]) -> writeq('yes') ; writeq('no')),
nl.
potest2(XMLDocument,dctg) :-
write('Loading document '), write(XMLDocument), write('...'), nl,
load_structure(XMLDocument,Infoset,[dialect(xmlns),space(remove)]),
(e_purchaseOrder(_Structure,Infoset,[]) -> writeq('yes') ; writeq('no')),
nl.
one(V) :-
grammar_version(V,Syn,File),
potest(File,Syn,'d:/usr/lib/xmlschema/po/tests/po1.xml').
two(V) :-
grammar_version(V,Syn,File),
potest(File,Syn,'d:/usr/lib/xmlschema/po/tests/po1.xml'),
potest2('d:/usr/lib/xmlschema/po/tests/po1v10a.xml',Syn).
/* Each of the following should be valid */
good(V) :-
grammar_version(V,Syn,File),
potest(File,Syn,'d:/usr/lib/xmlschema/po/tests/po1.xml'),
potest2('d:/usr/lib/xmlschema/po/tests/po1v10a.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1v25.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1v33.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1v38.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1v62d.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1v65.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1v79.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1v80.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1v100a.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1v100b.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1v121.xml',Syn).
/* Each of the following should raise an error */
bad(V) :-
grammar_version(V,Syn,File),
potest(File,Syn,'d:/usr/lib/xmlschema/po/tests/po1.xml'),
potest2('d:/usr/lib/xmlschema/po/tests/po1e04.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e13.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e14.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e15.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e15a.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e15b.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e15c.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e16.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e16b.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e18.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e19.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e20.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e27.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e28.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e28b.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e30.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e31.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e32.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e35.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e36.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e41.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e42.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e43.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e44.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e46.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e47.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e48.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e50.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e51.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e52.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e55.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e56.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e62.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e62b.xml',Syn),
/*
potest2('d:/usr/lib/xmlschema/po/tests/po1e62c.xml',Syn),
*/
potest2('d:/usr/lib/xmlschema/po/tests/po1e63.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e64.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e68.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e70.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e70b.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e78.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e81.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e86.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e87.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e88.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e89.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e91.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e92.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e101a.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e101b.xml',Syn),
/*
potest2('d:/usr/lib/xmlschema/po/tests/po1e101c.xml',Syn),
*/
potest2('d:/usr/lib/xmlschema/po/tests/po1e101d.xml',Syn),
/*
potest2('d:/usr/lib/xmlschema/po/tests/po1e105bisa.xml',Syn),
*/
potest2('d:/usr/lib/xmlschema/po/tests/po1e105bisb.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e106.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e109.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e113.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e114.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e116.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e122a.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e122b.xml',Syn),
potest2('d:/usr/lib/xmlschema/po/tests/po1e122c.xml',Syn).
/* 62c, 101c, 105bisa are commented out because they blow up
* number_chars/2. Need a more robust approach to checking
* numbers, apparently. */
ugly(V) :- good(V), bad(v).
cd ~/2003/schema/dctg $ /cygdrive/d/usr/src/pl/bin/plcon.exe -f potests.pl -g 'one(current)' -t haltor
$ /cygdrive/d/usr/src/pl/bin/plcon.exe \ > -f d:/home/cmsmcq/2002/Prolog/potest.pl \ > -g good -t haltThe command line might be simpler if Prolog has a good search path, but I haven't gotten around to that yet.
att_merge([],Padft,[Padft]). att_merge([Pa|Lpa],Padft,[Pa|Lpa]) :- Pa^^namespacename(NS), Padft^^namespacename(NS), Pa^^localname(Lnm), Padft^^localname(Lnm), !. att_merge([Pa|Lpa],Padft,Lpa2) :- att_merge(Lpa,Padft,Lpa2).
att_merge([],Padft,[Padft]).
att_merge([Pa|Lpa],Padft,Lpa2) :-
( { Pa^^namespacename(NS),
Padft^^namespacename(NS),
Pa^^localname(Lnm),
Padft^^localname(Lnm) } ->
Lpa2 = [Pa|Lpa]
;
att_merge(Lpa,Padft,Lpa2)
).