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)