Skip to content

Instantly share code, notes, and snippets.

@tyru
Last active September 23, 2018 12:10
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tyru/1e92412f54e69b4ec7d80c83fcc2f262 to your computer and use it in GitHub Desktop.
Save tyru/1e92412f54e69b4ec7d80c83fcc2f262 to your computer and use it in GitHub Desktop.
Parsing / Evaluating Vim script number literals in Prolog DCG
number(tInt(['1']))
number(tFloat(int_flac(['1'],['0'])))
number(tInt(['1','2','3','4','5','6','7','8','9']))
number(tFloat(int_flac(['1','2'],['3','4'])))
number(tInt(bin('0b',['1','0','1','0'])))
number(tInt(bin('0B',['0','1','0','1'])))
number(tInt(hex('0x',['D',e,'A',d,'B',e,'E',f])))
number(tInt(hex('0X',[d,'E',a,'D',b,'E',e,'F'])))
number(tInt(hex('0x',['1','2','3','4','5','6','7','8','9',a,b,c,d,e,f,'A','B','C','D','E','F'])))
number(tInt(hex('0X',['1','2','3','4','5','6','7','8','9',a,b,c,d,e,f,'A','B','C','D','E','F'])))
number(tInt(octal(['0','7','5','5'])))
number(tInt(octal(['0','1','2','3','4','5','6','7'])))
number(tFloat(int_flac_exp(['1'],['2'],-['3'])))
number(tFloat(int_flac_exp(['4'],['5'],+['6','7'])))
number(tFloat(int_flac_exp(['4'],['5'],['8'])))
"1", (is),1
"1.0", (is),1.0
"123456789", (is),123456789
"12.34", (is),12.34
"0b1010", (is),10
"0B0101", (is),5
"0xDeAdBeEf", (is),3735928559
"0XdEaDbEeF", (is),3735928559
"0x123456789abcdefABCDEF", (is),1375488932539311409843695
"0X123456789abcdefABCDEF", (is),1375488932539311409843695
"0755", (is),493
"01234567", (is),342391
"1.2e-3", (is),0.0012
"4.5E+67", (is),4.5e+67
"4.5e8", (is),450000000.0
eval_number(S, R) :- parse_number(S, number(Goal)), call(Goal, R).
parse_number(S, number(R)) :- string_chars(S, Cs), phrase(number(R), Cs).
number(tInt(I)) --> tInt(I).
number(tFloat(F)) --> tFloat(F).
tInt(Cs, R) :- is_list(Cs), !, number_chars(R, Cs).
tInt(Goal, R) :- call(Goal, R).
tFloat(Goal, R) :- call(Goal, R).
tInt(bin(Prefix, Digits)) --> bin(Prefix, Digits).
tInt(hex(Prefix, Digits)) --> hex(Prefix, Digits).
tInt(octal(Digits)) --> octal(Digits).
tInt(Digits) --> int_digits(Digits).
tFloat(int_flac(I, F)) --> int_flac(I, F).
tFloat(int_flac_exp(I, F, E)) --> int_flac_exp(I, F, E).
int_flac(I, F) --> digits(I), ['.'], digits(F).
int_flac(I, F, R) :- append([I, ['.'], F], Cs), number_chars(R, Cs).
int_flac_exp(I, F, E) --> digits(I), ['.'], digits(F), exp(E).
int_flac_exp(I, F, +E, R) :- !, append([I, ['.'], F, ['e', '+'], E], Cs), number_chars(R, Cs).
int_flac_exp(I, F, -E, R) :- !, append([I, ['.'], F, ['e', '-'], E], Cs), number_chars(R, Cs).
int_flac_exp(I, F, E, R) :- append([I, ['.'], F, ['e', '+'], E], Cs), number_chars(R, Cs).
exp(+E) --> ['e', '+'], digits(E).
exp(+E) --> ['E', '+'], digits(E).
exp(-E) --> ['e', '-'], digits(E).
exp(-E) --> ['E', '-'], digits(E).
exp(E) --> ['e'], digits(E).
exp(E) --> ['E'], digits(E).
bin('0b', Digits) --> ['0', 'b'], bin_digits(Digits).
bin('0B', Digits) --> ['0', 'B'], bin_digits(Digits).
bin(_, Digits, R) :- number_chars(R, ['0', 'b' | Digits]).
bin_digits([D]) --> bin_digit(D).
bin_digits([D|Digits]) --> bin_digit(D), bin_digits(Digits).
bin_digit('0') --> ['0'].
bin_digit('1') --> ['1'].
hex('0x', Digits) --> ['0', 'x'], hex_digits(Digits).
hex('0X', Digits) --> ['0', 'X'], hex_digits(Digits).
hex(_, Digits, R) :- number_chars(R, ['0', 'x' | Digits]).
hex_digits([D]) --> hex_digit(D).
hex_digits([D|Digits]) --> hex_digit(D), hex_digits(Digits).
octal(['0'|Digits]) --> ['0'], octal_digits(Digits).
octal(['0'|Digits], R) :- eval_octal(0, Digits, R).
eval_octal(N, [], N) :- !.
eval_octal(N, [D|Digits], R) :-
number_chars(D1, [D]),
M is N * 8 + D1,
eval_octal(M, Digits, R).
octal_digits([D]) --> octal_digit(D).
octal_digits([D|Digits]) --> octal_digit(D), octal_digits(Digits).
% digits with non-leading '0'
int_digits([]) --> [].
int_digits([D|Digits]) --> nonzero_digit(D), digits(Digits).
% digits ('0' - '9')
digits([]) --> [].
digits([D|Digits]) --> digit(D), digits(Digits).
% '0' - '9', 'A' - 'F', 'a' - 'f'
hex_digit(D) -->
[D],
{atom_codes(D, [C]), (between(48, 57, C); between(65, 70, C); between(97, 102, C))}.
% '0' - '7'
octal_digit(D) --> [D], {atom_codes(D, [C]), between(48, 55, C)}.
% '1' - '9'
nonzero_digit(D) --> [D], {atom_codes(D, [C]), between(49, 57, C)}.
% '0' - '9'
digit(D) --> [D], {atom_codes(D, [C]), between(48, 57, C)}.
:- parse_number("1", R), print(R), nl.
:- parse_number("1.0", R), print(R), nl.
:- parse_number("123456789", R), print(R), nl.
:- parse_number("12.34", R), print(R), nl.
:- parse_number("0b1010", R), print(R), nl.
:- parse_number("0B0101", R), print(R), nl.
:- parse_number("0xDeAdBeEf", R), print(R), nl.
:- parse_number("0XdEaDbEeF", R), print(R), nl.
:- parse_number("0x123456789abcdefABCDEF", R), print(R), nl.
:- parse_number("0X123456789abcdefABCDEF", R), print(R), nl.
:- parse_number("0755", R), print(R), nl.
:- parse_number("01234567", R), print(R), nl.
:- parse_number("1.2e-3", R), print(R), nl.
:- parse_number("4.5E+67", R), print(R), nl.
:- parse_number("4.5e8", R), print(R), nl.
:- eval_number("1", R), print(("1", is, R)), nl.
:- eval_number("1.0", R), print(("1.0", is, R)), nl.
:- eval_number("123456789", R), print(("123456789", is, R)), nl.
:- eval_number("12.34", R), print(("12.34", is, R)), nl.
:- eval_number("0b1010", R), print(("0b1010", is, R)), nl.
:- eval_number("0B0101", R), print(("0B0101", is, R)), nl.
:- eval_number("0xDeAdBeEf", R), print(("0xDeAdBeEf", is, R)), nl.
:- eval_number("0XdEaDbEeF", R), print(("0XdEaDbEeF", is, R)), nl.
:- eval_number("0x123456789abcdefABCDEF", R), print(("0x123456789abcdefABCDEF", is, R)), nl.
:- eval_number("0X123456789abcdefABCDEF", R), print(("0X123456789abcdefABCDEF", is, R)), nl.
:- eval_number("0755", R), print(("0755", is, R)), nl.
:- eval_number("01234567", R), print(("01234567", is, R)), nl.
:- eval_number("1.2e-3", R), print(("1.2e-3", is, R)), nl.
:- eval_number("4.5E+67", R), print(("4.5E+67", is, R)), nl.
:- eval_number("4.5e8", R), print(("4.5e8", is, R)), nl.
:- halt.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment