Skip to content

Instantly share code, notes, and snippets.

@yamasushi
Last active December 22, 2023 23:18
Show Gist options
  • Save yamasushi/d80157733f7c286f8e760bca193e027d to your computer and use it in GitHub Desktop.
Save yamasushi/d80157733f7c286f8e760bca193e027d to your computer and use it in GitHub Desktop.
integer <----> roman numeral
% integer --> roman numeral
% Compilers 1st ed. ex. P2.1 (p. 81)
% Compilers 2nd ed. ex. 2.3.3 (p. 60)
% https://gist.github.com/yamasushi/d80157733f7c286f8e760bca193e027d
-module(i2r).
-export([integer2roman/1]).
%-----------------------------------------------
% integer --> roman numeral
%-----------------------------------------------
%
% N -> N D | D
%
% N -> D R1 { N.s = n2roman(R1.k , D.d ) + R1.s }
% R -> D R1 { R.k = R1.k + 1 , R.s = n2roman(R1.k , D.d ) + R1.s }
% R -> ε { R.k = 0 , R.s= "" }
integer2roman(Num)->
[Rn,_]=n(integer_to_list(Num)),
Rn.
n2roman(_,0)-> "";
n2roman(T,N) when N > 0 ->
Num_Table=[
["I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"], % 1 ~ 9
["X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"], % 10 ~ 90
["C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"], % 100 ~ 900
["M", "MM", "MMM" ] ], % 1000 ~ 3000
lists:nth(N,lists:nth(T+1,Num_Table)).
n(Xs=[])->error([ n , {"Xs=",Xs} ]);
n([Head|Rest]) when (Head >= $0) and (Head =< $9) ->
D=Head-$0,
[ K , S ,Xs2 ]=r(Rest),
[ n2roman(K,D)++S , Xs2];
n(Xs)->error([n , {"Xs=",Xs} ]).
r(Xs=[])-> [0,"",Xs]; % ε
r([Head|Rest]) when (Head >= $0) and (Head =< $9) ->
D=Head-$0,
[ K , S , Xs2 ] = r(Rest),
[ K+1 , n2roman(K,D)++S , Xs2 ];
r(Xs)-> [0,"",Xs]. % ε
-module(r2i).
% roman numeral --> integer
% Compilers 2nd ed. ex. 2.3.4 (p. 60)
% https://gist.github.com/yamasushi/d80157733f7c286f8e760bca193e027d
-export([roman2integer/1]).
roman2integer(Str) ->
{N,_}=n(Str),
N.
n(Xs)->
{N3,Xs0}=m3(Xs ),
{N2,Xs1}=m2(Xs0),
{N1,Xs2}=m1(Xs1),
{N0,Xs3}=m0(Xs2),
{N3*1000 + N2*100 + N1*10 + N0 , Xs3}.
m0(Xs)->m($I, $V ,$X, Xs).
m1(Xs)->m($X, $L ,$C, Xs).
m2(Xs)->m($C, $D ,$M, Xs).
m3(Xs)->m($M, nil, nil, Xs).
m(I,V,X,RomanNum)->
% R -> I { R.n = 1 }
% | ε { R.n = 0 }
R=fun(Xs)->
case Xs of
[I|Xs0] -> { 1 , Xs0 };
_ -> { 0 , Xs } % ε
end
end,
% P -> I R { P.n = 1 + R.n }
% | V { P.n = 3 }
% | X { P.n = 8 }
% | ε { P.n = 0 }
P=fun(Xs)->
case Xs of
[I|Xs0] -> {N,Xs1}=R(Xs0),{ N+1 , Xs1 };
[V|Xs0] -> { 3 , Xs0 };
[X|Xs0] -> { 8 , Xs0 };
_ -> { 0 , Xs } % ε
end
end,
% S -> I R {S.n = 1 + R.n}
% | ε {S.n = 0}
S=fun(Xs)->
case Xs of
[I|Xs0] -> {N,Xs1}=R(Xs0),{ N+1 , Xs1 };
_ -> {0,Xs} % ε
end
end,
% Q -> I S {Q.n = 1 + S.n}
% | ε {Q.n = 0}
Q=fun(Xs)->
case Xs of
[I|Xs0] -> {N,Xs1}=S(Xs0),{ N+1 , Xs1 };
_ -> {0,Xs} % ε
end
end,
% M -> I P {M.n = 1 + P.n }
% | V Q {M.n = 5 + Q.n }
% | ε M.n = 0
case RomanNum of
[I|Xs0] -> {N,Xs1}=P(Xs0),{ N+1 , Xs1 };
[V|Xs0] -> {N,Xs1}=Q(Xs0),{ N+5 , Xs1 };
Xs -> {0,Xs} % ε
end.
% https://gist.github.com/yamasushi/d80157733f7c286f8e760bca193e027d
-module(roman).
-export([test/1]).
test(I,Max) when I<Max ->
Roman=i2r:integer2roman(I),
Num =r2i:roman2integer(Roman),
io:format("~w --i2r-> ~s --r2i--> ~w~n",[I,Roman,Num]),
if
I =/= Num -> error(something_wrong);
true -> ok
end,
test(I+1,Max);
test(_,_) -> ok.
test(Max) -> test(0,Max).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment