100 CALL CLEAR
$MLC F 110 10 3000
300 INPUT "A=":A
    ; last parameter 0 for COMPACT form
    ; or 1 for CLASSIC form with restrictive rules for substraction
310 CALL LINK("ROMAN",A,COM$,0)::CALL LINK("ROMAN",A,CLA$,1)
320 IF COM$=CLA$ THEN PRINT "  = ";COM$::GOTO 300
330 PRINT "  COMPACT = ";COM$::PRINT "  CLASSIC = ";CLA$::GOTO 300
$ROMAN
    STARTDATA
        WORDS 1000,-999,-995,-990,-950,900  ; create a word table with values of
        WORDS 500,-499,-495,-490,-450,400   ; usable symbols or combined symbols (by pair)
        WORDS 100,-99,-95,90
        WORDS 50,-49,-45,40
        WORDS 10,9,5,4,1,0
    ENDDATA A                           ; this table pointed by A (because A, B, C, D are word table pointers)
    STARTDATA
        STRING "M IMVMXMLMCM"           ; creeate a long string with symbols alone or by pair
        STRING "D IDVDXDLDCD"
        STRING "C ICVCXC"
        STRING "L ILVLXL"
        STRING "X IXV IVI "
    ENDDATA E                           ; pointed by E (because E, F, G, H are byte table pointers)
    DIMTABLE F 255                      ; the output string reserved here with 255 max chars
    GETPARAM 1 X                        ; get the value to be converted in X
    GETPARAM 3 T                        ; flag for classic/compact
    CLEAR K                             ; will point into output string (0 to 254)
    CLEAR I                             ; points into A() (from 0 to 25, the last A(25) is null for marker)
    CLEAR J                             ; points into E() string (from 0 to 49)
    DO
        COMPARE T 0                     ; compact form?
        IF=                             ; YES
            GETTABLE A(I) Y             ; one value from table A() into Y
            ABS Y                       ; and accept >0 or <0, no restriction
        ELSE                            ; here classic form
            DO
                GETTABLE A(I) Y         ; read a value
            WHILE<                      ; if negative, rejected
                INC I                   ; next
                ADD J 2
            LOOP
        ENDIF
    WHILE<>
        DO
            COMPARE X Y                 ; does Y fit in X?
        WHILE>=
            SUB X Y                     ; if YES, remove Y from X
            GETTABLE E(J) C             ; get one symbol
            PUTTABLE F(K) C             ; and put it into output string
            INC J                       ; see next
            INC K                       ; idem
            GETTABLE E(J) C             ; get next symbol
            COMPARE C 32                ; is it a SPACE? (32)
            IF<>
                PUTTABLE F(K) C         ; if not, it's a pair, add second symbol
                INC K                   ; one more char
            ENDIF       
            DEC J                       ; back on 1st symbol if to be repeated
         LOOP
         INC I                          ; if Y doesn't fit in X anymore, next value in A()
         ADD J 2                        ; and next symbols in E()
     LOOP
     LET U 2                            ; second paramater in CALL LINK (U, V, W, X are string pointers in CALL LINK)
     LET Z K                            ; get lenght of string in Z
     PUTTABLE U(0) F                    ; return Z chars from F table to string R$ in CALL LINK
$$
$END