Skip to content

Instantly share code, notes, and snippets.

@zed
Last active May 12, 2017 00:32
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save zed/e7bad76d922825604d1d93bb43f6cfa6 to your computer and use it in GitHub Desktop.
Save zed/e7bad76d922825604d1d93bb43f6cfa6 to your computer and use it in GitHub Desktop.
/** 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 <string.h>
#include <stdio.h>
#include <stdlib.h>
%%{
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 <text>...\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;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment