```    1:- module(quantity, [ quantity/3 ]).
2
3% Parse quantity
4quantity(Number, Options, String) :-
5    string(String),
6    string_codes(String, Codes),
7    quantity(Number, Options, Codes).
8
9quantity(Number, Options, Atom) :-
10    atom(Atom),
11    atom_codes(Atom, Codes),
12    quantity(Number, Options, Codes).
13
14quantity(Number, Options, [H | Codes]) :-
15    quantity(Number, Options, [H | Codes], []).
16
17:- use_module(library(dcg/basics)).
18
19sign(+1, [sign(none)]) -->
20    "".
21
22sign(+1, [sign(plus)]) -->
23    "+".
24
25sign(-1, [sign(hyphen)]) -->
26    "-".
27
28sign(-1, [sign(dash)]) -->
29    [226, 136, 146].
30
31sign(-1, [sign(minus)]) -->
32    [8722].
33
34nat(N) -->
35    digits([H | Codes]),
36    { number_codes(N, [H | Codes]) }.
37
38int(I, Options) -->
39    sign(S, Options),
40    nat(N),
41    { I is S * N }.
42
43sep(dot) -->
44    ".".
45
46sep(comma) -->
47    ",".
48
49frac(F, [frac(given), sep(S), digits(D)]) -->
50    sep(S),
51    digits([H | Codes]),
52    { number_codes(N, [H | Codes]),
53      length(Codes, L),
54      D is L + 1,
55      F = N / 10^D
56    }.
57
58% 1.23
59real(R, [int(given) | Options]) -->
60    sign(S, Opt1),
61    nat(N),
62    frac(F, Opt2),
63    { R is S * (N + F),
64      append([Opt1, Opt2], Options)
65    }.
66
67% .77
68real(R, [int(none) | Options]) -->
69    sign(S, Opt1),
70    frac(F, Opt2),
71    { R is S * F,
72      append([Opt1, Opt2], Options)
73    }.
74
75% 12
76real(R, [int(given), frac(none) | Options]) -->
77    sign(S, Options),
78    nat(N),
79    { R is S * N }.
80
81quantity(Q, [type(integer) | Options]) -->
82    int(Q, Options).
83
84quantity(Q, [type(real) | Options]) -->
85    real(Q, Options)```