43:- module(humutils,
44 [ nat//1
45 , float//1
46 , charsex//4
47 , pitchclass//1
48 , pitchclass//2
49 , pitch//2
50 , recip//1
51 , bar//1
52 , recip_to_rational/2
53 , rep_shared//2
54 , peek//1
55 ]). 56
57:- use_module(library(clp/bounds)). 58:- use_module(library(dcg_core)). 59:- use_module(library(dcg_pair)). 60:- use_module(library(dcg_macros)). 61:- use_module(library(snobol)). 62
63:- set_prolog_flag(double_quotes,codes). 64
73peek([C],L,L) :- L=[C|_].
74peek([C1,C2],L,L) :- L=[C1,C2|_].
84charsex(T,Z1,Z,[X|Y]) --> [X],
85 { ctype(X,T), \+member(X,Z1), \+member(X,Z) },
86 charsex(T,[],Z,Y).
87charsex(_,_,_,[]) --> [].
88
90ctype(A,text) :- !, (char_type(A,graph); char_type(A,space)).
91ctype(A,T) :- char_type(A,T).
95nat(I) -->
96 ( {integer(I)} -> {I>=0, number_codes(I,A)}, A
97 ; charsex(digit,[],[],A), {A=[_|_], number_codes(I,A)}).
101float(X) -->
102 ( {number(X)} -> {number_codes(X,A)}, A
103 ; charsex(digit,[],[],A),
104 ( ".",charsex(digit,[],[],B)
105 -> {"."=[Dot],append(A,[Dot|B],C)}
106 ; {C=A}
107 ),
108 {C=[_|_], number_codes(X,C)}
109 ).
125pitch(P,O) --> pitch_oct(N,O), wrap_mods(N,P).
126
127wrap_mods(N,Q) --> sharpen(N,P), iterate(sharpen,P,Q), \+sharpen(Q,_).
128wrap_mods(N,Q) --> flatten(N,P), iterate(flatten,P,Q), \+flatten(Q,_).
129wrap_mods(N,N) --> maybe("n"), \+sharpen(N,_), \+flatten(N,_).
130
131sharpen(A,sharp(A)) --> "#".
132flatten(A,flat(A)) --> "-".
137pitchclass(P) --> pitchclass(lower,P).
138pitchclass(Case,P) --> pitchname(Case,N), wrap_mods(N,P).
139
141pitchname(upper,N) --> [UNC],
142 {member(UNC,"ABCDEFG"), to_lower(UNC,NC), char_code(N,NC)}.
143pitchname(lower,N) --> [NC],
144 {member(NC,"abcdefg"), char_code(N,NC)}.
145
148pitch_oct(N,O) --> {var(O)}, pitchname(lower,N), !, rep_shared(K,pitchname(lower,N)), {O is K+4}.
149pitch_oct(N,O) --> {var(O)}, pitchname(upper,N), !, rep_shared(K,pitchname(upper,N)), {O is 3-K}.
150
151pitch_oct(N,O) --> {nonvar(O)},
152 ( {O >= 4}
153 -> {K is O-3}, rep(K,pitchname(lower,N))
154 ; {K is 4-O}, rep(K,pitchname(upper,N))
155 ).
160rep_shared(K,P) --> P, rep_shared(J,P), {succ(J,K)}.
161rep_shared(0,_) --> [].
162
168recip_to_rational(dots(R,N),D) :- !,
169 recip_to_rational(R,D0),
170 rep(N,mul(1 rdiv 2),1,C),
171 D1 is D0*(2 - C),
172 D=D1.
173
174recip_to_rational(0,2) :- !.
175recip_to_rational(1,1) :- !.
176recip_to_rational(R,1 rdiv R) :- R>0.
180recip(D) --> nat(R), \+any("0123456789"), iterate(dottify,R,D).
181
182dottify(dots(A,N),dots(A,M)) --> !, ".", {succ(N,M)}.
183dottify(A,dots(A,1)) --> ".".
184
185mul(X,Y,Z) :- Z is Y*X.
186
187
188
190
191
192nth_lower(N,C) :- nth1(N,"abcdefghijklmnopqrstuvwxyz",C).
197bar(Attrs) --> "=", run_left(bar_attrs,Attrs,[]).
198
199bar_attrs -->
200 maybe(bar_double),
201 maybe(bar_number),
202 maybe(bar_pause),
203 (bar_ortho; nop).
204
205bar_double --> \> span("="), \< [double].
206bar_number --> \> (nat(N), [C]), {nth_lower(M,C)}, \< [number(N,M)].
207bar_number --> \> nat(N), \< [number(N)].
208bar_pause --> \> ";",\< [pause].
209bar_ortho --> \> seqmap(bar_ortho,O), {O\=[]}, \< [ortho(O)].
210
211bar_ortho(normal) --> "|".
212bar_ortho(heavy) --> "!".
213bar_ortho(repeat) --> ":".
214bar_ortho(partial1) --> "'".
215bar_ortho(partial2) --> "`".
216bar_ortho(invisible) --> "-"
Humdrum parsing utilities
This module provides some utility predicates for parsing. They all operate as part of a DCG where the threaded state is a list of character codes.
Parsers in this module use the following data types:
*/