Task

Create a function that takes a Roman numeral as its argument and returns its value as a numeric decimal integer.

You don't need to validate the form of the Roman numeral.

Modern Roman numerals are written by expressing each decimal digit of the number to be encoded separately,

starting with the leftmost decimal digit and skipping any 0s   (zeroes).

1990 is rendered as   MCMXC     (1000 = M,   900 = CM,   90 = XC)     and

2008 is rendered as   MMVIII       (2000 = MM,   8 = VIII).

The Roman numeral for 1666,   MDCLXVI,   uses each letter in descending order.




MODULE RomanNumerals;
FROM InOut IMPORT WriteString, WriteCard, WriteLn;
FROM Strings IMPORT Length;
 
(* Convert given Roman numeral to binary *)
PROCEDURE DecodeRoman(s: ARRAY OF CHAR): CARDINAL;
    VAR i, d, len, acc: CARDINAL;
 
    PROCEDURE Digit(d: CHAR): CARDINAL;
    BEGIN
        CASE CHR( BITSET(ORD(d)) + BITSET{5} ) OF (* lowercase *)
            'm': RETURN 1000;
        |   'd': RETURN 500;
        |   'c': RETURN 100;
        |   'l': RETURN 50;
        |   'x': RETURN 10;
        |   'v': RETURN 5;
        |   'i': RETURN 1;
        ELSE
            RETURN 0;
        END;
    END Digit;
BEGIN
    len := Length(s);
    acc := 0;
    FOR i := 0 TO len-1 DO
        d := Digit(s[i]);
        IF d=0 THEN RETURN 0; END;
 
        IF (i # len-1) AND (d < Digit(s[i+1])) THEN
            acc := acc - d;
        ELSE
            acc := acc + d;
        END;
    END;
    RETURN acc;
END DecodeRoman;
 
PROCEDURE Show(s: ARRAY OF CHAR);
BEGIN
    WriteString(s);
    WriteString(": ");
    WriteCard(DecodeRoman(s), 0);
    WriteLn();
END Show;
 
BEGIN
    Show("MCMXC");
    Show("MDCLXVI");
    Show("mmvii");
    Show("mmxxi");
END RomanNumerals.