/** Convert Roman numerals given on the command line to decimals. $ ragel -F0 -o roman_numerals.c roman_numerals.rl $ gcc -finput-charset=utf-8 -fexec-charset=utf-8 -o roman_numerals roman_numerals.c $ ./roman_numerals IX Ⅻ CCCC 9 12 400 $ ./roman_numerals IIX && exit 1 || echo invalid invalid */ #include #include #include %%{ machine roman_numerals; write data; }%% int from_roman_to_int(const char* s) { int n, cs; const char *p = s, *pe = s + strlen(s), *eof = pe; %%{ # units I = ('I' | 'i' | "Ⅰ" | "ⅰ") %{ n += 1; }; II = I I | ("Ⅱ" | "ⅱ") %{ n += 2; }; III = I I I | ("Ⅲ" | "ⅲ") %{ n += 3; }; V = ('V' | 'v' | "Ⅴ" | "ⅴ") %{ n += 5; }; VI = V I | ("Ⅵ" | "ⅵ") %{ n += 6; }; VII = V I I | ("Ⅶ" | "ⅶ") %{ n += 7; }; VIII = V I I I | ("Ⅷ" | "ⅷ") %{ n += 8; }; # tens X = ('X' | 'x' | "Ⅹ" | "ⅹ") %{ n += 10; }; XI = ("Ⅺ" | "ⅺ") %{ n += 11; }; XII = ("Ⅻ" | "ⅻ") %{ n += 12; }; L = ('L' | 'l' | "Ⅼ" | "ⅼ") %{ n += 50; }; # hundreds C = ('C' | 'c' | "Ⅽ" | "ⅽ") %{ n += 100; }; D = ('D' | 'd' | "Ⅾ" | "ⅾ") %{ n += 500; }; # thousands M = ('M' | 'm' | "Ⅿ" | "ⅿ") %{ n += 1000;}; # subtractive principle IV = I V %{ n -= 2; } | I{4} | ("Ⅳ" | "ⅳ") %{ n += 4; }; IX = I X %{ n -= 2; } | V I{4} | ("Ⅸ" | "ⅸ") %{ n += 9; }; XL = X L %{ n -= 20; }; XC = X C %{ n -= 20; }; CD = C D %{ n -= 200; }; CM = C M %{ n -= 200; }; thousands = M{,4}; hundreds = CM | CD | D? C{,4}; tens = XC | XL | L? X{,4}; units = IX | VIII | VII | VI | V | IV | III | II | I; numeral = thousands? hundreds? (XII? | XI? | tens? units?); main := numeral > { n = 0; } ; write init; write exec; }%% return (cs == roman_numerals_error || cs == roman_numerals_start) ? -1 : n ; } int main(int argc, char* argv[]) { if (argc < 2) { fputs("Usage: roman_numerals ...\n", stderr); exit(EXIT_FAILURE); } for (int i = 1; i < argc; ++i) { int n = from_roman_to_int(argv[i]); if (n < 0) exit(EXIT_FAILURE); printf("%d\n", n); /* print result */ } return 0; }