Skip to content

Instantly share code, notes, and snippets.

@zed
Last active May 12, 2017 00:32
Show Gist options
  • Save zed/e7bad76d922825604d1d93bb43f6cfa6 to your computer and use it in GitHub Desktop.
Save zed/e7bad76d922825604d1d93bb43f6cfa6 to your computer and use it in GitHub Desktop.

Revisions

  1. zed revised this gist May 12, 2017. 1 changed file with 53 additions and 26 deletions.
    79 changes: 53 additions & 26 deletions roman_numerals.rl
    Original file line number Diff line number Diff line change
    @@ -1,10 +1,11 @@
    /** Convert Roman numerals given on the command line to decimals.

    $ ragel -F0 -p -o roman_numerals.c roman_numerals.rl
    $ cc -o roman_numerals roman_numerals.c
    $ ./roman_numerals IX XII
    $ 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
    */
    @@ -17,43 +18,69 @@
    write data;
    }%%


    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
    from_roman_to_int(const char* s)
    {
    int n, cs;
    char *p = argv[i], *pe = p + strlen(p), *eof = pe;
    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' %{ n += 1000; }){,3};
    hundreds = "CM" %{ n += 900; }
    | "CD" %{ n += 400; }
    | ('D' %{ n += 500; } )? ('C' %{ n += 100; }){,3};
    tens = "XC" %{ n += 90; }
    | "XL" %{ n += 40; }
    | ('L' %{ n += 50; } )? ('X' %{ n += 10; }){,3};
    units = "IX" %{ n += 9; }
    | "IV" %{ n += 4; }
    | ('V' %{ n += 5; } )? ('I' %{ n += 1; }){,3};
    numeral = thousands hundreds tens units;
    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 ;
    }


    if (!n || cs == roman_numerals_error)

    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;
    }
    }
  2. zed renamed this gist May 10, 2017. 1 changed file with 0 additions and 0 deletions.
    File renamed without changes.
  3. zed created this gist May 10, 2017.
    59 changes: 59 additions & 0 deletions roman_numerals.c
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,59 @@
    /** Convert Roman numerals given on the command line to decimals.
    $ ragel -F0 -p -o roman_numerals.c roman_numerals.rl
    $ cc -o roman_numerals roman_numerals.c
    $ ./roman_numerals IX XII
    9
    12
    $ ./roman_numerals IIX && exit 1 || echo invalid
    invalid
    */
    #include <string.h>
    #include <stdio.h>
    #include <stdlib.h>

    %%{
    machine roman_numerals;
    write data;
    }%%


    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, cs;
    char *p = argv[i], *pe = p + strlen(p), *eof = pe;

    %%{

    thousands = ('M' %{ n += 1000; }){,3};
    hundreds = "CM" %{ n += 900; }
    | "CD" %{ n += 400; }
    | ('D' %{ n += 500; } )? ('C' %{ n += 100; }){,3};
    tens = "XC" %{ n += 90; }
    | "XL" %{ n += 40; }
    | ('L' %{ n += 50; } )? ('X' %{ n += 10; }){,3};
    units = "IX" %{ n += 9; }
    | "IV" %{ n += 4; }
    | ('V' %{ n += 5; } )? ('I' %{ n += 1; }){,3};
    numeral = thousands hundreds tens units;

    main := numeral > { n = 0; } ;

    write init;
    write exec;

    }%%

    if (!n || cs == roman_numerals_error)
    exit(EXIT_FAILURE);

    printf("%d\n", n); /* print result */

    }
    return 0;
    }