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.




roman = cluster is decode
    rep = null
 
    digit_value = proc (c: char) returns (int) signals (invalid)
        if c < 'a' then c := char$i2c(char$c2i(c) + 32) end 
        if     c = 'm' then return(1000)
        elseif c = 'd' then return(500)
        elseif c = 'c' then return(100)
        elseif c = 'l' then return(50)
        elseif c = 'x' then return(10)
        elseif c = 'v' then return(5)
        elseif c = 'i' then return(1)
        else signal invalid
        end
    end digit_value
 
    decode = proc (s: string) returns (int) signals (invalid)
        acc: int := 0
        for i: int in int$from_to(1, string$size(s)) do
            d: int := digit_value(s[i])
            if i < string$size(s) cand d < digit_value(s[i+1]) then
                acc := acc - d
            else
                acc := acc + d
            end
        end resignal invalid
        return(acc)
    end decode
end roman
 
start_up = proc ()
    po: stream := stream$primary_output()
    tests: array[string] := array[string]$
        ["MCMXC", "mdclxvi", "MmViI", "mmXXi", "INVALID"]
 
    for test: string in array[string]$elements(tests) do
        stream$puts(po, test || ": ")
        stream$putl(po, int$unparse(roman$decode(test))) except when invalid:
            stream$putl(po, "not a valid Roman numeral!")
        end
    end
end start_up