% num2.pl

% convertor of strings to numbers.
% based on the grammar of num1.pl

demo :- tell('num2.out'), ignore(demo1), told.

demo1 :- demo2, fail.
demo1.

demo2 :-
	member(X,["23", " 23", "23.3 ", "34.5671 "]),
	% here's the output bound to the empty list again
	num(N,X,[]),
	% ~s will print a string of ascii numbers in their
	% atom form. e.g.   X = [116, 105, 109], format('<~s>',[X])
	% prints <tim>
	format('"~s" = [~10f]\n',[X,N]).

space --> " ". 
tabb  --> [9].
dot   --> ".".
zero  --> "0".
one   --> "1".
two   --> "2".
three --> "3".
four  --> "4".
five  --> "5".
six   --> "6".
seven --> "7".
eight --> "8".
nine  --> "9".

ascii2Number(N0,N) :-
	zero([Zero],[]),
	N is N0 - Zero.

blank --> space | tabb.

whitespace --> []
            | blank, whitespace.

digit --> 
	one | two | three | four
        | five | six | seven | eight | nine | zero.

% digitNumber does not use the DCG syntax since it wants
% to grab the head of the list without popping it off the
% list.
digitNumber(N,[N0|L],Out) :-
	digit([N0|L],Out),
	ascii2Number(N0,N).

% note the added variables- DCGs can not only parse, but
% bind variables as a side effect of the parse
digits(N,0) --> digitNumber(N).
digits(N,P) -->
	    digitNumber(N1),
	    % P0 is the number of tens places used by the
	    % digits. e.g. "123" would take P0=2
	    digits(N2,P0),
	    % the DCG expansion (adding in carry variables)
	    % is disabled inside {curly brackets}
	    % (this extra syntax could be avoided via dcgfix)
	    {P is P0 + 1,
	     N is N1*10^P + N2}.

num1(N) --> digits(N,_).
num1(N) --> digits(N1,_),
	    dot,
	    digits(N2,P),
	    % so neat- the final number is the number
	    % LHS of the dot plus the right hand side
	    % number divided by a factor for the number
	    % of digits
	    {N is N1 + N2/10^(P+1)}.

num(N) --> whitespace,num1(N),whitespace.