diff --git a/assemble.c b/assemble.c index 2a1569f..a837551 100644 --- a/assemble.c +++ b/assemble.c @@ -1154,33 +1154,60 @@ static int assemble( report(stack->top, ".RAD50 on odd " "boundary\n"); DOT++; /* Fix it */ } - - while (!EOL(*cp)) { - char endstr[6]; - int len; + { char *radstr; - char *radp; + int i, len; - endstr[0] = *cp++; - endstr[1] = '\n'; - endstr[2] = 0; + /* + * Allocate storage sufficient for the rest of + * the line. + */ + radstr = memcheck(malloc(strlen(cp))); + len = 0; - len = strcspn(cp, endstr); - radstr = memcheck(malloc(len + 1)); - memcpy(radstr, cp, len); - radstr[len] = 0; - cp += len; - if (*cp && *cp != '\n') - cp++; - for (radp = radstr; *radp;) { - unsigned rad; + do { + cp = skipwhite(cp); + if (*cp == '<') { + EX_TREE *value; + /* A byte value */ + value = parse_unary_expr(cp, 0); + cp = value->cp; + if (value->type != EX_LIT) { + report(stack->top, "expression must be constant\n"); + radstr[len++] = 0; + } else if (value->data.lit >= 050) { + report(stack->top, "invalid character value %o\n", value->data.lit); + radstr[len++] = 0; + } else { + radstr[len++] = value->data.lit; + } + free_tree(value); + } else { + char quote = *cp++; - rad = rad50(radp, &radp); - store_word(stack->top, tr, 2, rad); + while (*cp && *cp != '\n' && *cp != quote) { + int ch = ascii2rad50(*cp++); + + if (ch == -1) { + report(stack->top, "invalid character '%c'\n", cp[-1]); + radstr[len++] = 0; + } else { + radstr[len++] = ch; + } + + } + cp++; /* Skip closing quote */ + } + + cp = skipwhite(cp); + } while (!EOL(*cp)); + + for (i = 0; i < len; i += 3) { + int word = packrad50word(radstr + i, len - i); + store_word(stack->top, tr, 2, word); } - free(radstr); - cp = skipwhite(cp); + free(radstr); } return 1; diff --git a/rad50.c b/rad50.c index 03508e3..fdebdb4 100644 --- a/rad50.c +++ b/rad50.c @@ -118,3 +118,43 @@ void unrad50( } else cp[0] = cp[1] = cp[2] = ' '; } + +/* ascii2rad50 - convert a single character to a RAD50 character */ + +int ascii2rad50( + char c) +{ + char *rp; + + if (c == '\0') /* Not a RAD50 character */ + return -1; + rp = strchr(radtbl, toupper((unsigned char)c)); + if (rp == NULL) /* Not a RAD50 character */ + return -1; + return (int) (rp - radtbl); /* Convert */ +} + +/* packrad50word - packs up to 3 characters into a RAD50 word. + * + * The characters should be in the range [0, 050), + * such as having been converted by ascii2rad50(). + */ + +unsigned packrad50word( + char *cp, + int len) +{ + unsigned long acc = 0; + + if (len >= 1) { + acc += (cp[0] % 050) * 050 * 050; + } + if (len >= 2) { + acc += (cp[1] % 050) * 050; + } + if (len >= 3) { + acc += cp[2] % 050; + } + + return acc; +} diff --git a/rad50.h b/rad50.h index 4061b29..8a96c27 100644 --- a/rad50.h +++ b/rad50.h @@ -46,4 +46,11 @@ extern void unrad50( unsigned word, char *cp); +int ascii2rad50( + char c); + +unsigned packrad50word( + char *cp, + int len); + #endif /* RAD50_H */ diff --git a/tests/RunTests b/tests/RunTests index 2645b3f..2ccfd13 100755 --- a/tests/RunTests +++ b/tests/RunTests @@ -17,6 +17,7 @@ TESTS="test-asciz \ test-locals \ test-macro-comma \ test-psect \ + test-rad50 \ test-undef \ test-word-comma" diff --git a/tests/test-rad50.lst.ok b/tests/test-rad50.lst.ok new file mode 100644 index 0000000..5ba807b --- /dev/null +++ b/tests/test-rad50.lst.ok @@ -0,0 +1,47 @@ + 1 ;;;;; + 2 ; + 3 ; Test .rad50 directive + 4 ; + 5 ; + 6 ; 0 space + 7 ; 01-32 A-Z + 8 ; 33 $ + 9 ; 34 . + 10 ; 35 (undefined) + 11 ; 36-47 0-9 + 12 ; + 13 ; radix-50 value: ((C1 * 50) + C2) * 50) + C3 ; everything octal of course + 14 ; example: ABC => ((1*50)+2)*50+3 = 3223 + 15 + 16 000000 003223 .rad50 /ABC/ ; Packs ABC into one word + 17 000002 003223 .rad50 ^ABC^ ; Packs ABC into one word + 18 000004 003220 .rad50 /AB/ ; Packs AB (SPACE) into one word + 19 000006 003223 014400 .rad50 /ABCD/ ; Packs ABC into first word and + 20 ; D (SPACE) (SPACE) into second word. + 21 000012 003223 014716 .rad50 /ABCDEF/ ; Packs ABC into first word, DEF into + 22 ; second word. + 23 000016 003255 .rad50 /AB/<35> ; stores 3255 in one word +test-rad50.mac:24: ***ERROR invalid character '?' +test-rad50.mac:24: ***ERROR invalid character '!' +test-rad50.mac:24: ***ERROR invalid character '=' + 24 000020 000000 .rad50 /?!=/ ; invalid characters +test-rad50.mac:25: ***ERROR invalid character value 50 +test-rad50.mac:25: ***ERROR invalid character value 37777777777 + 25 000022 000000 .rad50 <0><50><-1> ; invalid characters + 26 000001 CHR1=1 + 27 000002 CHR2=2 + 28 000003 CHR3=3 + 29 000024 003223 .RAD50 <1><2><3> ; Equivalent to .RAD50 /ABC/ + 30 000026 003223 .RAD50 ; Equivalent to .RAD50 /ABC/ + 30 + + +Symbol table + +. ******R 001 CHR1 =000001 CHR2 =000002 CHR3 =000003 + + +Program sections: + +. ABS. 000000 000 (RW,I,GBL,ABS,OVR,NOSAV) + 000030 001 (RW,I,LCL,REL,CON,NOSAV) diff --git a/tests/test-rad50.mac b/tests/test-rad50.mac new file mode 100644 index 0000000..f16c89c --- /dev/null +++ b/tests/test-rad50.mac @@ -0,0 +1,30 @@ +;;;;; +; +; Test .rad50 directive +; +; +; 0 space +; 01-32 A-Z +; 33 $ +; 34 . +; 35 (undefined) +; 36-47 0-9 +; +; radix-50 value: ((C1 * 50) + C2) * 50) + C3 ; everything octal of course +; example: ABC => ((1*50)+2)*50+3 = 3223 + + .rad50 /ABC/ ; Packs ABC into one word + .rad50 ^ABC^ ; Packs ABC into one word + .rad50 /AB/ ; Packs AB (SPACE) into one word + .rad50 /ABCD/ ; Packs ABC into first word and + ; D (SPACE) (SPACE) into second word. + .rad50 /ABCDEF/ ; Packs ABC into first word, DEF into + ; second word. + .rad50 /AB/<35> ; stores 3255 in one word + .rad50 /?!=/ ; invalid characters + .rad50 <0><50><-1> ; invalid characters + CHR1=1 + CHR2=2 + CHR3=3 + .RAD50 <1><2><3> ; Equivalent to .RAD50 /ABC/ + .RAD50 ; Equivalent to .RAD50 /ABC/