2 // coded by Ketmar // Vamprile Avalon
14 #include "iptclib/iptc.h"
16 #include "urasmlib/urasmlib.h"
21 ///////////////////////////////////////////////////////////////////////////////
24 static int processFile (const char *fname
);
27 ///////////////////////////////////////////////////////////////////////////////
30 static char *sysIncludeDir
= NULL
;
31 static char **knownModules
= NULL
;
34 static uint8_t memory
[65536];
35 static char memused
[65536];
36 static uint16_t pc
= 0; /* current position to write */
37 static uint16_t disp
= 0; /* current 'virtual PC' */
38 static uint16_t ent
= 0; /* eng */
39 static int wasOrg
= 0;
40 static int pass
= 0; /* 0: collect labels; 1: compiling; 2: compiling and fixing labels */
41 static int inTapeBlock
= 0;
42 static uint8_t tapeXorB
= 0;
43 static uint16_t tapeBlockSizeAddr
= 0;
44 static uint16_t tapeBlockHdrAddr
= 0;
45 static char *tapeBlockName
= NULL
;
47 static int optShowOut
= 0;
48 static int optRunSNA
= 0;
49 static int optTapExt
= 0; /* set '.tap' extension (but don't write tape; this for inline tape blocks) */
51 static char *curFileName
= NULL
;
52 static int curLineNo
= 0;
53 #define MAX_LINE_SIZE 16384
54 static char curLine
[MAX_LINE_SIZE
];
55 static FILE *curFile
= NULL
;
57 static char *lastSeenLabel
= NULL
; /* global */
58 static char *curModuleName
= NULL
;
59 static int modInCurFile
= 0; /* module started in current file */
60 static int moduleSkipFlag
= 0;
63 ///////////////////////////////////////////////////////////////////////////////
66 static void clearKnownModules (void) {
68 if (!knownModules
) return;
69 for (f
= 0; knownModules
[f
]; ++f
) free(knownModules
[f
]);
75 static int isKnownModule (const char *str
) {
77 if (!knownModules
) return 0;
78 for (f
= 0; knownModules
[f
]; ++f
) if (!strcmp(knownModules
[f
], str
)) return 1;
83 static void addKnownModule (const char *str
) {
87 for (f
= 0; knownModules
[f
]; ++f
) if (!strcmp(knownModules
[f
], str
)) return;
89 nn
= realloc(knownModules
, (f
+2)*sizeof(char *));
92 knownModules
[f
] = strdup(str
);
93 knownModules
[f
+1] = NULL
;
97 ///////////////////////////////////////////////////////////////////////////////
100 typedef struct FileStack FileStack
;
107 static FileStack
*fstack
= NULL
;
110 static void clearFileStack (void) {
113 c
= fstack
; fstack
= fstack
->prev
;
114 if (c
->fl
) fclose(c
->fl
);
115 if (c
->name
) free(c
->name
);
121 static void popFile (void) {
124 if (!fstack
) abort();
125 curFile
= fstack
->fl
;
126 curFileName
= fstack
->name
;
127 curLineNo
= fstack
->lineNo
;
128 c
= fstack
; fstack
= fstack
->prev
;
133 ///////////////////////////////////////////////////////////////////////////////
137 int count
; // dups left; <1: don't generate code
141 static DupChunk
*dupStack
= NULL
;
142 static int dupStackCnt
= 0;
145 static void newDupChunk (int dupcnt
) {
146 DupChunk
*c
, *nn
= realloc(dupStack
, (dupStackCnt
+1)*sizeof(DupChunk
));
149 c
= dupStack
+(dupStackCnt
++);
150 memset(c
, 0, sizeof(DupChunk
));
152 c
->lineNo
= curLineNo
;
153 c
->fpos
= ftell(curFile
);
157 static DupChunk
*curDupChunk (void) {
158 if (dupStackCnt
< 1) return NULL
;
159 return dupStack
+(dupStackCnt
-1);
163 static void dropDupChunk (void) {
164 if (dupStackCnt
> 0) {
170 ///////////////////////////////////////////////////////////////////////////////
174 static void trimleft (char *s) {
176 for (p = s; *p && isspace(*p); ++p) ;
177 memmove(s, p, strlen(p)+1);
182 static void trimright (char *s
) {
184 for (p
= s
+strlen(s
)-1; p
>= s
&& isspace(*p
); --p
) ;
191 * return NULL if there can't be any operator, or
192 * pointer to operator arguments
194 static char *getOpName (char *dest
, char *str
) {
198 while (*str
&& isspace(*str
)) ++str
;
199 for (e
= str
; *e
&& !isspace(*e
); ++e
) ;
200 if (e
-str
> 32 || e
== str
) return NULL
; // too big
201 memmove(dest
, str
, e
-str
);
203 for (; *e
&& isspace(*e
); ++e
) ;
208 ///////////////////////////////////////////////////////////////////////////////
209 // memory getters and setters
211 static uint8_t getByte (uint16_t addr
) {
216 static void putByte (uint16_t addr
, uint8_t b
) {
217 if (inTapeBlock
) tapeXorB
^= b
;
218 //if (pass > 0) printf("%04X: %02X\n", addr, b);
224 static void putWord (uint16_t addr
, uint16_t w
) {
225 putByte(addr
, w
&0xFFU
);
226 putByte(addr
+1, (w
>>8)&0xFFU
);
230 ///////////////////////////////////////////////////////////////////////////////
233 static void rleUnpack (uint16_t addr
, const uint8_t *buf
, int buflen
) {
234 for (; buflen
>= 2; buflen
-= 2) {
236 uint8_t byte
= *buf
++;
237 //printf("%d %u %u\n", cnt+1, byte, addr);
238 for (; cnt
>= 0; --cnt
, ++addr
) if (!memused
[addr
]) putByte(addr
, byte
);
243 static void prepareMemory (int putSNA
) {
244 memset(memory
, 0, sizeof(memory
));
245 memset(memused
, 0, sizeof(memused
));
246 //if (putSNA) rleUnpack(16384, ursna48+27, sizeof(ursna48)-27);
250 static int writeSNA (const char *fname
) {
251 char *fn
= malloc(strlen(fname
)+16);
255 sprintf(fn
, "%s.sna", fname
);
256 fo
= fopen(fn
, "wb");
258 if (!fo
) { fprintf(stderr
, "ERROR: can't write SNA file: %s.sna\n", fname
); return -1; }
259 memmove(regs
, ursna48
, 27);
261 /* push new address */
262 uint16_t sp
= (uint16_t)regs
[23]+(((uint16_t)regs
[24])<<8);
264 putByte(sp
, ent
&0xFFU
);
265 putByte(sp
+1, (ent
>>8)&0xFFU
);
267 regs
[24] = (sp
>>8)&0xFFU
;
269 fwrite(regs
, 27, 1, fo
);
270 rleUnpack(16384, ursna48
+27, sizeof(ursna48
)-27);
271 fwrite(memory
+16384, 49152, 1, fo
);
277 ///////////////////////////////////////////////////////////////////////////////
278 // error raisers, etc
280 static jmp_buf errJP
;
282 static void __attribute__((format(printf
, 1, 2))) errorMsg (const char *fmt
, ...) {
286 fprintf(stderr
, "FATAL at file %s, line %d: ", curFileName
, curLineNo
);
287 vfprintf(stderr
, fmt
, ap
);
294 static void __attribute__((noreturn
)) __attribute__((format(printf
, 1, 2))) fatal (const char *fmt
, ...) {
298 fprintf(stderr
, "FATAL at file %s, line %d: ", curFileName
, curLineNo
);
299 vfprintf(stderr
, fmt
, ap
);
307 static void __attribute__((noreturn
)) fatalPos (int errcode
, const char *errpos
) {
308 fprintf(stderr
, "ERROR at file %s, line %d, position %d: %s\n%s\n", curFileName
, curLineNo
, errpos
-curLine
+1, urErrorMessage(errcode
), curLine
);
309 for (; errpos
>= curLine
; --errpos
) fputc('^', stderr
);
316 ///////////////////////////////////////////////////////////////////////////////
319 static int32_t getArg (const char **args
, int *defined
) {
321 const char *a
= *args
;
324 while (*a
&& isspace(*a
)) ++a
;
325 if (!*a
) fatalPos(URA_GENERIC
, a
);
326 const char *ee
= urExpression(&res
, a
, disp
, defined
, &error
);
327 if (error
|| (*ee
&& ee
[0] != ';' && ee
[0] != ',')) fatalPos(URA_GENERIC
, ee
);
333 static int32_t getOneArg (const char *args
, int *defined
) {
334 const char *aa
= args
;
335 int32_t res
= getArg(&aa
, defined
);
336 if (aa
[0] && aa
[0] != ';') fatalPos(URA_BAD_OPERAND
, aa
);
342 static char *getStrArg (const char **args
, int *lenp
) {
344 char *res
= malloc(MAX_LINE_SIZE
+128), *p
= res
, qch
;
345 const char *a
= *args
;
347 while (*a
&& isspace(*a
)) ++a
;
348 if (a
[0] && (a
[0] != '"' && a
[0] != '\'')) { free(res
); fatalPos(URA_GENERIC
, a
); }
350 for (; *a
&& *a
!= qch
; ++a
) {
354 case 't': *p
++ = '\t'; break;
355 case 'r': *p
++ = '\r'; break;
356 case 'n': *p
++ = '\n'; break;
357 case 'a': *p
++ = '\a'; break;
358 case 'f': *p
++ = '\f'; break;
359 case 'v': *p
++ = '\v'; break;
360 default: *p
++ = a
[1]; break;
368 if (a
[0] != qch
) { free(res
); fatalPos(URA_GENERIC
, a
); }
370 while (*a
&& isspace(*a
)) ++a
;
372 if (*a
&& a
[0] != ';' && a
[0] != ',') { free(res
); fatalPos(URA_GENERIC
, a
); }
379 static __attribute__((unused
)) char *getOneStrArg (const char *args
, int *len
) {
380 const char *aa
= args
;
381 char *res
= getStrArg(&aa
, len
);
382 if (aa
[0] && aa
[0] != ';') { free(res
); fatalPos(URA_BAD_OPERAND
, aa
); }
388 static char *getLabelArg (const char **args
) {
389 char *res
= malloc(MAX_LINE_SIZE
+128), *p
= res
;
390 const char *a
= *args
;
392 while (*a
&& isspace(*a
)) ++a
;
393 if (!a
[0]) { free(res
); fatalPos(URA_GENERIC
, a
); }
394 for (; *a
&& a
[0] != ';' && a
[0] != ','; ++a
) *p
++ = *a
;
395 while (*a
&& isspace(*a
)) ++a
;
396 for (; p
> res
&& isspace(p
[-1]); --p
) ;
398 if (*a
&& a
[0] != ';' && a
[0] != ',') { free(res
); fatalPos(URA_GENERIC
, a
); }
399 if (!urIsValidLabelName(res
)) { free(res
); fatalPos(URA_GENERIC
, *args
); }
405 static char *getOneLabelArg (const char *args
) {
406 const char *aa
= args
;
407 char *res
= getLabelArg(&aa
);
408 if (aa
[0] && aa
[0] != ';') { free(res
); fatalPos(URA_BAD_OPERAND
, aa
); }
414 static char *getIncludeArg (const char **args
, int *system
) {
415 char *res
= malloc(MAX_LINE_SIZE
+128), *p
= res
, qch
;
416 const char *a
= *args
;
418 if (system
) *system
= 0;
419 while (*a
&& isspace(*a
)) ++a
;
420 if (a
[0] && (a
[0] != '"' && a
[0] != '\'' && a
[0] != '<')) { free(res
); fatalPos(URA_GENERIC
, a
); }
424 if (system
) *system
= 1;
426 for (; *a
&& *a
!= qch
; ++a
) {
430 case 't': *p
++ = '\t'; break;
431 case 'r': *p
++ = '\r'; break;
432 case 'n': *p
++ = '\n'; break;
433 case 'a': *p
++ = '\a'; break;
434 case 'f': *p
++ = '\f'; break;
435 case 'v': *p
++ = '\v'; break;
436 default: *p
++ = a
[1]; break;
443 if (a
[0] != qch
) { free(res
); fatalPos(URA_GENERIC
, a
); }
445 while (*a
&& isspace(*a
)) ++a
;
447 if (*a
&& a
[0] != ';' && a
[0] != ',') { free(res
); fatalPos(URA_GENERIC
, a
); }
453 static char *getOneIncludeArg (const char *args
, int *system
) {
454 const char *aa
= args
;
455 char *res
= getIncludeArg(&aa
, system
);
456 if (aa
[0] && aa
[0] != ';') { free(res
); fatalPos(URA_BAD_OPERAND
, aa
); }
461 ///////////////////////////////////////////////////////////////////////////////
464 static char *fixLocalLabel (const char *name
) {
465 // this is local label, let's rename it
466 char *newname
= malloc(MAX_LINE_SIZE
+1024);
467 if (!newname
) fatal("out of memory!");
468 sprintf(newname
, "{%s%s}", lastSeenLabel
, name
);
473 static int32_t findLabelCB (const char *name
, uint16_t addr
, int *defined
, int *found
) {
476 static char n2
[(MAX_LINE_SIZE
+1024)*2];
478 nn
= name
[0]=='.'&&lastSeenLabel
? fixLocalLabel(name
) : (char *)name
;
479 lbl
= urFindLabel(nn
);
480 if (!lbl
&& curModuleName
&& (nn
!= name
|| !strchr(name
, '.'))) {
481 sprintf(n2
, "%s.%s", curModuleName
, nn
);
482 lbl
= urFindLabel(n2
);
486 errorMsg("using undefined label %s", name
);
491 if (curModuleName
&& (nn
!= name
|| !strchr(name
, '.'))) {
492 sprintf(n2
, "%s.%s", curModuleName
, nn
);
493 lbl
= urAddLabel(n2
);
495 lbl
= urAddLabel(nn
);
499 lbl
->refLine
= curLineNo
;
500 lbl
->refFile
= strdup(curFileName
);
501 //printf("new label: [%s]\n", nn);
503 //printf("label reference: [%s]\n", nn);
505 if (nn
!= name
) free(nn
);
508 *defined
= lbl
->known
!=0;
520 * 1: go to the next line
522 static int processLabel (void) {
523 char opname
[64], *argstart
;
527 static char n2
[(MAX_LINE_SIZE
+1024)*2];
531 for (ep
= curLine
; *ep
&& !isspace(*ep
) && *ep
!= ':' && *ep
!= ';'; ++ep
) ;
532 DupChunk
*cdup
= curDupChunk();
533 if (cdup
&& cdup
->count
< 1) {
534 // skip label and following spaces
535 if (*ep
== ':') ++ep
;
536 for (; *ep
&& isspace(*ep
); ++ep
) ;
538 if (*ep
== '=') return 1; // next line
539 if (!(argstart
= getOpName(opname
, ep
))) return 1; // next line
540 if (!strcasecmp(opname
, "equ")) return 1; // next line
541 return 0; // go on, do nothing with label
543 if (*ep
== ';') *ep
= '\0';
544 ch
= *ep
; *ep
= '\0';
545 if (!urIsValidLabelName(curLine
)) fatal("invalid label: %s", curLine
);
546 if (curLine
[0] == '@' && curLine
[1]) {
547 /* @... doesn't affect locals */
548 memmove(curLine
, curLine
+1, strlen(curLine
));
552 nn
= curLine
[0]=='.'&&lastSeenLabel
? fixLocalLabel(curLine
) : curLine
;
555 if (curModuleName
&& (nn
!= curLine
|| !strchr(curLine
, '.'))) {
556 sprintf(n2
, "%s.%s", curModuleName
, nn
);
557 lbl
= urAddLabel(n2
);
559 lbl
= urAddLabel(nn
);
567 // skip label and following spaces
570 for (; *ep
&& isspace(*ep
); ++ep
) ;
574 lbl
->refLine
= curLineNo
;
575 lbl
->refFile
= strdup(curFileName
);
577 //printf("%d: new: [%s]\n", localLbl, lbl->name);
583 argstart
= getOpName(opname
, ep
);
586 if (!strcmp(opname
, "=")) {
588 if (lbl
->type
!= -1 && lbl
->type
!= 0) fatal("duplicate label %s", lbl
->name
);
590 int32_t res
= getOneArg(argstart
, &defined
);
596 if (pass
!= 0) fatal("can't calculate label %s", lbl
->name
);
598 //printf("%s = %d\n", lbl->name, res);
602 if (pass
== 0 && lbl
->type
!= -1) fatal("duplicate label %s", lbl
->name
);
603 if (!strcasecmp(opname
, "equ")) {
606 int32_t res
= getOneArg(argstart
, &defined
);
612 if (pass
!= 0) fatal("can't calculate label %s", lbl
->name
);
614 //printf("%s EQU %d\n", lbl->name, res);
618 if (!localLbl
&& !noLocAff
) {
619 if (lastSeenLabel
) free(lastSeenLabel
);
620 lastSeenLabel
= strdup(lbl
->name
);
625 memmove(curLine
, ep
, strlen(ep
)+1);
630 static int checkLabels (void) {
634 for (c
= labels
; c
; c
= c
->next
) {
636 fprintf(stderr
, "ERROR at file %s, line %d: referencing undefined label: %s\n", c
->refFile
, c
->refLine
, c
->name
);
640 //if (wasError) longjmp(errJP, 667);
645 static void checkUndefineds (void) {
648 for (c
= labels
; c
; c
= c
->next
) {
650 fprintf(stderr
, "WARNING at file %s, line %d: referencing undefined label: %s\n", c
->refFile
, c
->refLine
, c
->name
);
652 if (c
->type
== 0) c
->known
= -1;
657 ///////////////////////////////////////////////////////////////////////////////
658 // collectors/feeders
660 typedef void (*CollectorFn
) (void);
661 typedef int (*FeederFn
) (void);
664 static CollectorFn collectorCB
= NULL
;
665 static FeederFn feederCB
= NULL
;
668 static CollectorFn
*colStack
= NULL
;
669 static int colStackCnt
= 0;
670 static FeederFn
*feedStack
= NULL
;
671 static int feedStackCnt
= 0;
674 static __attribute__((unused
)) void newCollector (CollectorFn fn
) {
675 CollectorFn
*nn
= realloc(colStack
, (colStackCnt
+1)*sizeof(CollectorFn
));
678 colStack
[colStackCnt
++] = collectorCB
;
683 static __attribute__((unused
)) void newFeeder (FeederFn fn
) {
684 FeederFn
*nn
= realloc(feedStack
, (feedStackCnt
+1)*sizeof(FeederFn
));
687 feedStack
[feedStackCnt
++] = feederCB
;
692 static __attribute__((unused
)) void popCollector (void) {
693 if (colStackCnt
-- < 1) abort();
694 collectorCB
= colStack
[colStackCnt
];
698 static __attribute__((unused
)) void popFeeder (void) {
699 if (feedStackCnt
-- < 1) abort();
700 feederCB
= feedStack
[feedStackCnt
];
704 ///////////////////////////////////////////////////////////////////////////////
705 // pseudoinstructions
707 static int piORG (const char *args
) {
709 int32_t res
= getOneArg(args
, &defined
);
710 if (!defined
) fatal("sorry, ORG operand value must be known here");
711 if (res
< 0 || res
> 65535) fatal("invalid ORG operand value: %d", res
);
712 if (inTapeBlock
) fatal("sorry, no ORGs in TAPEDATA allowed");
722 static int piDISP (const char *args
) {
724 int32_t res
= getOneArg(args
, &defined
);
725 if (!defined
) fatal("sorry, DISP operand value must be known here");
726 if (res
< 0 || res
> 65535) fatal("invalid DISP operand value: %d", res
);
727 //printf("DISP=%d\n", res);
733 static int piENDDISP (const char *args
) {
734 if (inTapeBlock
) fatal("sorry, no ENDDISPs in TAPEDATA allowed");
740 static int piENT (const char *args
) {
742 int32_t res
= getOneArg(args
, &defined
);
743 if (!defined
) fatal("sorry, ENT operand value must be known here");
744 if (res
< 0 || res
> 65535) fatal("invalid ENT operand value: %d", res
);
750 static int piALIGN (const char *args
) {
752 if (inTapeBlock
) fatal("sorry, no ALIGNs in TAPEDATA allowed");
753 int32_t res
= getOneArg(args
, &defined
);
754 if (!defined
) fatal("sorry, ALIGN operand value must be known here");
755 if (res
< 0 || res
> 65535) fatal("invalid ALIGN operand value: %d", res
);
756 if (pc
!= disp
) fatal("sorry, no ALIGNs in desynced blocks allowed");
757 if (res
> 0 && pc
%res
!= 0) {
763 //printf("new DISP: 0x%04x\n", res);
768 static int piDISPALIGN (const char *args
) {
770 int32_t res
= getOneArg(args
, &defined
);
771 if (!defined
) fatal("sorry, DISPALIGN operand value must be known here");
772 if (res
< 0 || res
> 65535) fatal("invalid DISPALIGN operand value: %d", res
);
773 if (res
> 0 && disp
%res
!= 0) {
778 //printf("new DISP: 0x%04x\n", res);
783 static int piDEFBW (const char *args
, int isWord
) {
786 const char *a
= args
;
789 res
= getArg(&a
, &defined
);
790 if (pass
> 0 && !defined
) fatalPos(URA_BAD_INSTRUCTION
, a
);
792 if (res
< -32768 || res
> 65535) fatal("invalid operand value: %d", res
);
795 putByte(pc
, res
&0xFFU
);
797 putByte(pc
, (res
>>8)&0xFFU
);
800 putByte(pc
, (res
>>8)&0xFFU
);
802 putByte(pc
, res
&0xFFU
);
806 if (res
< -128 || res
> 255) fatal("invalid operand value: %d", res
);
807 putByte(pc
, res
&0xFFU
);
811 if (*a
== ';') break;
812 if (*a
!= ',') fatalPos(URA_BAD_OPERAND
, a
);
821 static int piDEFB (const char *args
) { return piDEFBW(args
, 0); }
822 static int piDEFW (const char *args
) { return piDEFBW(args
, 1); }
823 static int piDEFR (const char *args
) { return piDEFBW(args
, 2); }
826 static int piDEFSTR (const char *args
, int type
) {
829 const char *a
= args
;
832 if (*a
== '"' || *a
== '\'') {
833 res
= getStrArg(&a
, &len
);
834 for (f
= 0; f
< len
; ++f
) {
835 unsigned char b
= (unsigned char)res
[f
];
836 if (f
== len
-1 && type
== 2) b
|= 0x80;
842 putByte(pc
, (unsigned char)res
[f
]);
847 int32_t v
= getArg(&a
, &defined
);
848 if (pass
> 0 && !defined
) fatalPos(URA_BAD_OPERAND
, a
);
854 if (*a
== ';') break;
855 if (*a
!= ',') fatalPos(URA_BAD_OPERAND
, a
);
860 for (; *a
&& isspace(*a
); ++a
) ;
867 static int piDEFM (const char *args
) { return piDEFSTR(args
, 0); }
868 static int piDEFZ (const char *args
) { return piDEFSTR(args
, 1); }
869 static int piDEFX (const char *args
) { return piDEFSTR(args
, 2); }
872 static int piDEFS (const char *args
) {
875 const char *a
= args
;
877 res
= getArg(&a
, &defined
);
878 if (pass
> 0 && !defined
) fatalPos(URA_BAD_INSTRUCTION
, a
);
879 if (res
< 1 || res
> 65535) fatalPos(URA_BAD_OPERAND
, a
);
880 if (*a
&& a
[0] == ',') {
882 bt
= getArg(&a
, &defined
);
883 if (pass
> 0 && !defined
) fatalPos(URA_BAD_INSTRUCTION
, a
);
884 if (bt
< -127 || bt
> 255) fatalPos(URA_BAD_OPERAND
, a
);
885 if (bt
< 0) bt
= 256+bt
;
886 for (f
= 0; f
< res
; ++f
) {
887 putByte(pc
, bt
&0xFFU
);
891 pc
+= res
; disp
+= res
;
894 if (*a
!= ';') fatalPos(URA_BAD_OPERAND
, a
);
900 static int piDISPLAYA (const char *args
, int anyPass
) {
903 const char *a
= args
;
906 if (*a
== '"' || *a
== '\'') {
907 res
= getStrArg(&a
, &len
);
908 if (anyPass
|| pass
> 0) printf("%s", res
);
912 int32_t v
= getArg(&a
, &defined
);
913 if (pass
> 0 && !defined
) fatalPos(URA_BAD_OPERAND
, a
);
914 if (anyPass
|| pass
> 0) printf("%d", v
);
917 if (*a
== ';') break;
918 if (*a
!= ',') fatalPos(URA_BAD_OPERAND
, a
);
923 for (; *a
&& isspace(*a
); ++a
) ;
930 static int piDISPLAY (const char *args
) { return piDISPLAYA(args
, 0); }
931 static int piDISPLAY0 (const char *args
) { return piDISPLAYA(args
, 1); }
934 /* INCBIN "name"[,maxlen] */
935 static int piINCBIN (const char *args
) {
937 const char *a
= args
;
941 char *fn
= getIncludeArg(&a
, &system
);
943 if (system
&& fn
[0] != '/') {
944 sprintf(curLine
, "%s/%s", sysIncludeDir
, fn
);
946 fn
= strdup(curLine
);
952 maxlen
= getOneArg(a
, &defined
);
954 errorMsg("INCBIN: undefined maxlen (%s)", fn
);
956 fatal("compilation failed!");
958 if (maxlen
< 1) { free(fn
); return 0; }
961 fl
= fopen(fn
, "rb");
963 errorMsg("INCBIN: file not found: %s", fn
);
965 fatal("compilation failed!");
967 while (maxlen
-- > 0) {
968 int res
= fread(&bt
, 1, 1, fl
);
971 errorMsg("INCBIN: error reading file: %s", fn
);
973 fatal("compilation failed!");
984 static int piINCLUDE (const char *args
) {
985 int oi
= modInCurFile
;
987 char *fn
= getOneIncludeArg(args
, &system
);
988 FileStack
*c
= malloc(sizeof(FileStack
));
991 if (system
&& fn
[0] != '/') {
992 sprintf(curLine
, "%s/%s", sysIncludeDir
, fn
);
994 fn
= strdup(curLine
);
996 memset(c
, 0, sizeof(FileStack
));
998 c
->name
= curFileName
;
999 c
->lineNo
= curLineNo
;
1004 res
= processFile(fn
);
1009 fatal("compilation failed");
1010 //longjmp(errJP, 667);
1012 memset(curLine
, 0, sizeof(curLine
));
1017 static int piMODULE (const char *args
) {
1020 if (curModuleName
) fatal("no nested modules allowed (yet)");
1021 mn
= getOneLabelArg(args
);
1022 if (!urIsValidLabelName(mn
)) { free(mn
); fatal("invalid module name"); }
1023 free(curModuleName
);
1025 moduleSkipFlag
= isKnownModule(mn
);
1032 static int piENDMODULE (const char *args
) {
1035 if (!curModuleName
) fatal("ENDMODULE without MODULE");
1036 if (*args
&& args
[0] != ';') {
1037 mn
= getOneLabelArg(args
);
1038 if (strcmp(mn
, curModuleName
)) { free(mn
); fatal("invalid module name in ENDMODULE"); }
1041 free(curModuleName
);
1042 curModuleName
= NULL
;
1049 ///////////////////////////////////////////////////////////////////////////////
1052 // TAPEBLOCK name,start
1053 static int piTAPEBLOCK (const char *args
) {
1057 int defined
, f
, len
;
1058 const char *a
= args
;
1061 if (inTapeBlock
) fatal("sorry, no TAPEHEADERs allowed in TAPEDATA!");
1062 memset(name
, 32, sizeof(name
));
1065 sres
= getStrArg(&a
, &len
);
1067 if (len
> 10) len
= 10;
1068 memmove(name
, sres
, len
);
1070 if (*a
!= ',') fatalPos(URA_BAD_OPERAND
, a
); ++a
;
1072 ires
= getArg(&a
, &defined
);
1073 if (pass
> 0 && !defined
) fatalPos(URA_BAD_OPERAND
, a
);
1074 if (ires
< 0 || ires
> 65535) fatal("TAPEHEADER: bad start: %d", ires
);
1076 if (*a
&& *a
!= ';') fatalPos(URA_BAD_OPERAND
, a
);
1078 //if (pass > 0) printf("%04X(%04X): TAPE HEADER: [%s], len=%u, start=%u, len2=%u\n", pc, disp, name, length, start, length2);
1079 putWord(pc
, 19); pc
+= 2; // length of header
1080 tapeBlockHdrAddr
= pc
;
1081 inTapeBlock
= 1; tapeXorB
= 0; // prepare state
1082 putByte(pc
, 0); ++pc
; // header block
1083 putByte(pc
, 3); ++pc
;
1084 for (f
= 0; f
< 10; ++f
, ++pc
) putByte(pc
, name
[f
]);
1085 putWord(pc
, 0); pc
+= 2;
1086 putWord(pc
, start
); pc
+= 2;
1087 putWord(pc
, 32767); pc
+= 2;
1089 putByte(pc
, tapeXorB
); ++pc
;
1091 tapeBlockSizeAddr
= pc
;
1092 putWord(pc
, 0); pc
+= 2; // this will be patched in ENDTAPEDATA
1093 inTapeBlock
= 1; tapeXorB
= 0; // prepare state
1094 putByte(pc
, 255); ++pc
; // data block
1100 static int piENDTAPEBLOCK (const char *args
) {
1102 if (!inTapeBlock
) fatal("sorry, no ENDTAPEBLOCK allowed without TAPEBLOCK!");
1104 putByte(pc
, tapeXorB
); ++pc
;
1105 //if (pass > 0) printf("%04X(%04X): TAPE BLOCK END\n", pc, disp);
1107 sz
= pc
; if (sz
== 0) sz
= 65536;
1108 sz
-= (int)tapeBlockSizeAddr
+2;
1109 putWord(tapeBlockSizeAddr
, sz
);
1111 putWord(tapeBlockHdrAddr
+12, sz
-2); // length patched
1114 for (f
= 0; f
< 18; ++f
) tapeXorB
^= getByte(tapeBlockHdrAddr
+f
);
1115 putByte(tapeBlockHdrAddr
+18, tapeXorB
); // checksum patched
1121 // TAPEHEADER type,name,length,start[,lenwithoutvars]
1124 static int piTAPEHEADER (const char *args
) {
1128 int defined
, f
, len
;
1129 const char *a
= args
;
1131 uint16_t length
, start
, length2
;
1133 if (inTapeBlock
) fatal("sorry, no TAPEHEADERs allowed in TAPEDATA!");
1134 memset(name
, 32, sizeof(name
));
1137 ires
= getArg(&a
, &defined
);
1138 if (!defined
) fatalPos(URA_BAD_OPERAND
, a
);
1139 if (ires
< 0 || ires
> 255) fatal("TAPEHEADER: bad type: %d", ires
);
1141 if (*a
!= ',') fatalPos(URA_BAD_OPERAND
, a
); ++a
;
1143 sres
= getStrArg(&a
, &len
);
1145 if (len
> 10) len
= 10;
1146 memmove(name
, sres
, len
);
1148 if (*a
!= ',') fatalPos(URA_BAD_OPERAND
, a
); ++a
;
1150 ires
= getArg(&a
, &defined
);
1151 if (pass
> 0 && !defined
) fatalPos(URA_BAD_OPERAND
, a
);
1152 if (ires
< 0 || ires
> 65535) fatal("TAPEHEADER: bad length: %d", ires
);
1153 length2
= length
= ires
;
1154 if (*a
!= ',') fatalPos(URA_BAD_OPERAND
, a
); ++a
;
1156 ires
= getArg(&a
, &defined
);
1157 if (pass
> 0 && !defined
) fatalPos(URA_BAD_OPERAND
, a
);
1158 if (ires
< 0 || ires
> 65535) fatal("TAPEHEADER: bad start: %d", ires
);
1162 ires
= getArg(&a
, &defined
);
1163 if (pass
> 0 && !defined
) fatalPos(URA_BAD_OPERAND
, a
);
1164 if (ires
< 0 || ires
> 65535) fatal("TAPEHEADER: bad length2: %d", ires
);
1167 if (*a
&& *a
!= ';') fatalPos(URA_BAD_OPERAND
, a
);
1169 //if (pass > 0) printf("%04X(%04X): TAPE HEADER: [%s], len=%u, start=%u, len2=%u\n", pc, disp, name, length, start, length2);
1170 putWord(pc
, 19); pc
+= 2; // length of header
1171 inTapeBlock
= 1; tapeXorB
= 0; // prepare state
1172 putByte(pc
, 0); ++pc
; // header block
1173 putByte(pc
, type
); ++pc
;
1174 for (f
= 0; f
< 10; ++f
, ++pc
) putByte(pc
, name
[f
]);
1175 putWord(pc
, length
); pc
+= 2;
1176 putWord(pc
, start
); pc
+= 2;
1177 putWord(pc
, length2
); pc
+= 2;
1179 putByte(pc
, tapeXorB
); ++pc
;
1185 static int piTAPEDATA (const char *args
) {
1186 if (inTapeBlock
) fatal("sorry, no TAPEDATAs allowed in TAPEDATA!");
1187 //if (pass > 0) printf("%04X(%04X): TAPE BLOCK\n", pc, disp);
1188 tapeBlockSizeAddr
= pc
;
1189 putWord(pc
, 0); pc
+= 2; // this will be patched in ENDTAPEDATA
1190 inTapeBlock
= 1; tapeXorB
= 0; // prepare state
1191 putByte(pc
, 255); ++pc
; // data block
1196 static int piENDTAPEDATA (const char *args
) {
1198 if (!inTapeBlock
) fatal("sorry, no ENDTAPEDATA allowed without TAPEDATA!");
1200 putByte(pc
, tapeXorB
); ++pc
;
1201 //if (pass > 0) printf("%04X(%04X): TAPE BLOCK END\n", pc, disp);
1204 sz
-= (int)tapeBlockSizeAddr
+2;
1205 putByte(tapeBlockSizeAddr
, sz
&0xFF);
1206 putByte(tapeBlockSizeAddr
+1, (sz
>>8)&0xFF);
1211 ///////////////////////////////////////////////////////////////////////////////
1214 static int piDUP (const char *args
) {
1217 DupChunk
*cdup
= curDupChunk();
1219 res
= getOneArg(args
, &defined
);
1220 if (!defined
) fatal("DUP operand must be defined!");
1221 if (res
> 65535) fatal("invalid count in DUP: %d", res
);
1222 if (cdup
&& cdup
->count
< 1) res
= 0; // just skip it
1228 static int piEDUP (const char *args
) {
1229 DupChunk
*cdup
= curDupChunk();
1230 if (!cdup
) fatal("EDUP withoud DUP");
1231 if (--(cdup
->count
) < 1) {
1235 /* do it all again */
1236 fseek(curFile
, cdup
->fpos
, SEEK_SET
);
1237 curLineNo
= cdup
->lineNo
;
1243 ///////////////////////////////////////////////////////////////////////////////
1244 // instruction dispatcher
1246 static int processInstruction (void) {
1249 char *args
= getOpName(instr
, curLine
);
1250 if (!args
) return -1;
1251 op
= urFindOp(instr
);
1253 if (op
->fn(args
)) return -2;
1260 ///////////////////////////////////////////////////////////////////////////////
1263 static IptEngine eng
;
1264 static int scriptStartLine
= 0;
1268 static int iptCheckAbort (IptEngine
*eng
) {
1273 void iptParseError (IptParserState
*pst
, const char *msg
) {
1274 fprintf(stderr
, "PARSE ERROR at line %d: %s\n", scriptStartLine
+pst
->line
-1, msg
);
1278 void iptError (IptEngine
*eng
, IptCell errCell
, const char *msg
) {
1279 fprintf(stderr
, "SCRIPT ERROR at file %s, line %d\n", curFileName
, scriptStartLine
);
1280 if (errCell
) { fprintf(stderr
, " "); iptDebugPrintCell(eng
, errCell
); fprintf(stderr
, "\n"); }
1281 fatal("SCRIPT ERROR!");
1285 static __attribute__((unused
)) void dumpStack (IptEngine
*eng
) {
1288 fprintf(stderr
, "stack depth: %u\n", iptStackDepth(eng
));
1289 for (f
= eng
->sp
; f
> 0; f
--) {
1290 fprintf(stderr
, " #%u: ", eng
->sp
-f
);
1291 iptDebugPrintCell(eng
, eng
->stack
[f
-1]);
1292 fputs("\n", stderr
);
1298 static void runScript (IptCell prg
) {
1300 iptExecute(&eng
, prg
);
1306 static int doLine (void) {
1311 cdup
= curDupChunk();
1312 if (curLine
[0] == ';') return 0;
1313 if (curLine
[0] == ':') fatal("line can't start with colon!");
1314 if (curLine
[0] == '*') fatal("line can't start with star!");
1315 if (!isspace(curLine
[0])) {
1316 if (processLabel()) return 0;
1320 if (!cdup
|| cdup
->count
> 0) {
1321 len
= urAssembleOne(curLine
, pc
, disp
, &errpos
);
1323 if (processInstruction()) fatalPos(len
, errpos
);
1326 if (len
> 0 && pass
!= 0 && optShowOut
) {
1328 int ppp
= pc
, ll
= 0, f
;
1329 for (p
= curLine
; *p
&& isspace(*p
); ++p
) ;
1330 printf("** %s (len=%d)\n", p
, len
);
1332 int len1
= urDisassembleOne(dstr
, ppp
);
1333 printf("** %s\n%04X: [", dstr
, (unsigned int)ppp
);
1334 for (f
= 0; f
< len1
; ++f
) { if (f
) putchar(' '); printf("%02X", memory
[ppp
+f
]); }
1335 printf("] (len1=%d)\n", len1
);
1336 ppp
+= len1
; ll
+= len1
;
1339 pc
+= len
; disp
+= len
;
1340 if (len
>= 0 && errpos
) {
1341 memmove(curLine
, errpos
+1, strlen(errpos
));
1349 ///////////////////////////////////////////////////////////////////////////////
1350 // Iptscrae primitives
1353 static int iptPrimSAY (IptEngine
*eng
) {
1354 IptCell res
= iptGetValue(eng
, iptPop(eng
));
1355 switch (res
->type
) {
1357 printf("%i\n", res
->iv
);
1360 printf("%.15g\n", res
->fv
);
1363 printf("%s\n", res
->sv
);
1366 printf("<bad cell type> (%d)\n", res
->type
);
1374 static int iptPrimGETPASS (IptEngine
*eng
) { iptPushInt(eng
, pass
); return 0; }
1376 static int iptPrimGETPC (IptEngine
*eng
) { iptPushInt(eng
, pc
); return 0; }
1378 static int iptPrimGETDISP (IptEngine
*eng
) { iptPushInt(eng
, disp
); return 0; }
1382 static int iptPrimSETPC (IptEngine
*eng
) {
1383 int32_t a
= iptPopInt(eng
);
1390 static int iptPrimSETDISP (IptEngine
*eng
) {
1391 int32_t a
= iptPopInt(eng
);
1398 static int iptPrimGETBYTE (IptEngine
*eng
) {
1399 int32_t a
= iptPopInt(eng
);
1400 iptPushInt(eng
, getByte(a
&0xFFFF));
1405 /* val addr PUTBYTE */
1406 static int iptPrimPUTBYTE (IptEngine
*eng
) {
1407 int32_t a
= iptPopInt(eng
);
1408 int32_t v
= iptPopInt(eng
);
1409 putByte(a
&0xFFFF, v
&0xFF);
1415 static int iptPrimEMITBYTE (IptEngine
*eng
) {
1416 int32_t v
= iptPopInt(eng
);
1417 putByte(pc
, v
&0xFF);
1423 /* "str" ASSEMBLE */
1424 static int iptPrimASSEMBLE (IptEngine
*eng
) {
1425 const char *str
= iptPopString(eng
);
1426 if (strlen(str
) >= MAX_LINE_SIZE
) fatal("line too long!\n%s", str
);
1427 strcpy(curLine
, str
);
1433 /* "str" EXPRESSION */
1434 static int iptPrimEXPRESSION (IptEngine
*eng
) {
1435 const char *str
= iptPopString(eng
);
1440 ee
= urExpression(&res
, str
, disp
, &defined
, &error
);
1441 if (error
|| (*ee
&& ee
[0] != ';' && ee
[0] != ',')) fatal("invalid expression: %s", str
);
1442 iptPushInt(eng
, res
);
1443 iptPushInt(eng
, defined
);
1452 -1: label known, but undefined
1453 1: label known and defined
1455 static int iptPrimFINDLABEL (IptEngine
*eng
) {
1456 const char *str
= iptPopString(eng
);
1457 UrLabelInfo
*lbl
= urFindLabel(str
);
1458 if (!lbl
) iptPushInt(eng
, 0);
1459 else iptPushInt(eng
, lbl
->type
>=0 && lbl
->known
? 1 : -1);
1472 static int iptPrimLABELTYPE (IptEngine
*eng
) {
1473 const char *str
= iptPopString(eng
);
1474 UrLabelInfo
*lbl
= urFindLabel(str
);
1475 if (!lbl
) iptPushInt(eng
, 0);
1476 else iptPushInt(eng
, lbl
->type
>=0 ? lbl
->type
+1 : 0);
1484 * reststr value 1/-1 (value can be string or int; -1: undefined)
1487 static int iptPrimNEXTARG (IptEngine
*eng
) {
1488 IptCell cell
= iptPopValue(eng
);
1489 if (cell
->type
!= IptCellString
) iptError(eng
, cell
, "string expected");
1490 const char *str
= cell
->sv
;
1492 while (*str
&& isspace(*str
)) ++str
;
1493 if (!str
[0] || str
[0] == ';') {
1498 if (str
[0] == '"' || str
[0] == '\'') {
1501 char *ee
= getStrArg(&str
, &len
);
1502 iptNewStringCellEx(eng
, str
, strlen(str
), cell
);
1503 iptNewStringCellEx(eng
, ee
, len
, cell
);
1509 int32_t v
= getArg(&str
, &defined
);
1510 iptNewStringCellEx(eng
, str
, strlen(str
), cell
);
1512 iptPushInt(eng
, defined
?1:-1);
1518 ///////////////////////////////////////////////////////////////////////////////
1521 typedef struct ScriptMacroInfo ScriptMacroInfo
;
1522 struct ScriptMacroInfo
{
1524 IptCell code
; /* ( "strarg" -- ) */
1525 ScriptMacroInfo
*next
;
1528 static ScriptMacroInfo
*smi
= NULL
;
1531 static void smiClear (void) {
1533 ScriptMacroInfo
*c
= smi
;
1541 static void smiMark (IptEngine
*eng
) {
1543 for (c
= smi
; c
; c
= c
->next
) iptMark(eng
, c
->code
);
1547 static ScriptMacroInfo
*smiFind (const char *name
) {
1549 for (c
= smi
; c
; c
= c
->next
) if (!strcasecmp(name
, c
->name
)) return c
;
1554 static void smiAdd (const char *name
, IptCell cell
) {
1555 ScriptMacroInfo
*c
= malloc(sizeof(ScriptMacroInfo
));
1556 memset(c
, 0, sizeof(ScriptMacroInfo
));
1557 c
->name
= strdup(name
);
1565 * {code} "str" DEFMAC
1567 static int iptPrimDEFMAC (IptEngine
*eng
) {
1568 const char *name
= iptPopString(eng
);
1569 IptCell code
= iptPopValue(eng
);
1570 if (code
->type
!= IptCellList
) iptError(eng
, code
, "code expected");
1571 if (pass
!= 0) return 0; // do nothing
1572 if (!name
[0]) iptError(eng
, code
, "DEFMAC empty name");
1573 // zeroth pass, register it
1574 if (smiFind(name
)) iptError(eng
, code
, "DEFMAC double defined");
1580 ///////////////////////////////////////////////////////////////////////////////
1583 static int processFile (const char *fname
) {
1590 char *script
= NULL
;
1591 int scriptPass
= -1;
1593 if (curFileName
) free(curFileName
);
1594 curFileName
= strdup(fname
);
1596 if (!(curFile
= fopen(fname
, "r"))) {
1597 free(curFileName
); curFileName
= NULL
;
1598 fprintf(stderr
, "ERROR: can't open input file %s!\n", fname
);
1602 memmove(&oJP
, &errJP
, sizeof(jmp_buf));
1603 if (setjmp(errJP
)) {
1604 free(curFileName
); curFileName
= NULL
;
1605 fclose(curFile
); curFile
= NULL
;
1606 if (script
) free(script
);
1607 memmove(&errJP
, &oJP
, sizeof(jmp_buf));
1613 if (feederCB()) continue;
1615 if (!curFile
) break;
1616 if (!fgets(curLine
, sizeof(curLine
)-1, curFile
)) break;
1618 curLine
[sizeof(curLine
)-1] = '\0';
1620 //printf("%s: [%s]\n", curFileName, curLine);
1627 /* collecting script */
1628 if (strncasecmp(curLine
, "*ENDSCRIPT", 10)) {
1629 /* still collecting */
1630 int len
= strlen(script
), l1
= strlen(curLine
);
1631 char *nn
= realloc(script
, len
+l1
+2); // zero and '\n'
1632 if (!nn
) fatal("out of memory for script");
1634 strcat(script
, curLine
);
1635 strcat(script
, "\n");
1639 cdup
= curDupChunk();
1640 if (!cdup
|| cdup
->count
> 0) {
1642 if (scriptPass
== -1 || scriptPass
== pass
) {
1643 IptCell prg
= iptParse(&eng
, script
);
1644 if (prg
) runScript(prg
);
1645 iptClearStack(&eng
);
1648 free(script
); script
= NULL
;
1653 if (!curLine
[0]) continue;
1654 if (curLine
[0] == ';') continue;
1655 if (curLine
[0] == ':') fatal("line can't start with colon!");
1656 if (moduleSkipFlag
) {
1657 if (!isspace(curLine
[0])) continue;
1658 if ((args
= getOpName(instr
, curLine
)) == NULL
) continue;
1659 if (!strcasecmp(instr
, "ENDMODULE")) { piENDMODULE(args
); continue; }
1662 if (curLine
[0] != '*' && !isspace(curLine
[0])) {
1663 if (processLabel()) continue;
1665 cdup
= curDupChunk();
1666 if (curLine
[0] == '*') {
1667 /* this should be SCRIPT part */
1668 if ((args
= getOpName(instr
, curLine
+1)) != NULL
) {
1669 if (!strcasecmp(instr
, "SCRIPT") || !strcasecmp(instr
, "SCRIPT0") || !strcasecmp(instr
, "SCRIPT1")) {
1671 switch (instr
[strlen(instr
)-1]) {
1672 case '0': scriptPass
= 0; break;
1673 case '1': scriptPass
= 1; break;
1674 default: scriptPass
= -1; break;
1678 scriptStartLine
= curLineNo
;
1685 if (!cdup
|| cdup
->count
> 0) {
1686 len
= urAssembleOne(curLine
, pc
, disp
, &errpos
);
1688 if (processInstruction()) fatalPos(len
, errpos
);
1691 if (len
> 0 && pass
!= 0 && optShowOut
) {
1693 int ppp
= pc
, ll
= 0, f
;
1694 for (p
= curLine
; *p
&& isspace(*p
); ++p
) ;
1695 printf("** %s (len=%d)\n", p
, len
);
1697 int len1
= urDisassembleOne(dstr
, ppp
);
1698 printf("** %s\n%04X: [", dstr
, (unsigned int)ppp
);
1699 for (f
= 0; f
< len1
; ++f
) { if (f
) putchar(' '); printf("%02X", memory
[ppp
+f
]); }
1700 printf("] (len1=%d)\n", len1
);
1701 ppp
+= len1
; ll
+= len1
;
1704 pc
+= len
; disp
+= len
;
1705 if (len
>= 0 && errpos
) {
1706 memmove(curLine
, errpos
+1, strlen(errpos
));
1710 if ((args
= getOpName(instr
, curLine
)) == NULL
) continue;
1711 if (!strcasecmp(instr
, "DUP")) { piDUP(args
); continue; }
1712 if (!strcasecmp(instr
, "EDUP")) { piEDUP(args
); continue; }
1716 if (curModuleName
&& modInCurFile
) {
1717 fprintf(stderr
, "WARNING: seems that you forgot 'ENDMODULE %s' in %s!\n", curModuleName
, curFileName
);
1719 if (script
) free(script
);
1720 if (curFile
) fclose(curFile
);
1721 free(curFileName
); curFileName
= NULL
;
1722 memmove(&errJP
, &oJP
, sizeof(jmp_buf));
1727 ///////////////////////////////////////////////////////////////////////////////
1730 /* return 'found' flag */
1731 static int findChunkFrom (int addr
, int *start
, int *len
) {
1732 if (addr
< 0) addr
= 0;
1733 for (; addr
<= 65535 && !memused
[addr
]; ++addr
) ;
1734 if (addr
> 65535) return 0;
1736 for (; addr
<= 65535 && memused
[addr
]; ++addr
) ;
1737 *len
= addr
-(*start
);
1742 static void saveBinChunks (const char *basename
) {
1743 char *fname
= malloc(strlen(basename
)+16);
1747 while (findChunkFrom(start
, &start
, &len
)) {
1748 sprintf(fname
, "%s_%04X.%s", basename
, start
, optTapExt
?"tap":"bin");
1749 fo
= fopen(fname
, "wb");
1751 fprintf(stderr
, "ERROR: can't write file %s!\n", fname
);
1753 printf("out: %s\n", fname
);
1754 if (fwrite(memory
+start
, len
, 1, fo
) != 1) {
1755 fprintf(stderr
, "ERROR: error writing file %s!\n", fname
);
1768 static int fWriteByte (FILE *fo
, uint8_t b
, uint8_t *bxor
) {
1769 if (fwrite(&b
, 1, 1, fo
) != 1) return -1;
1770 if (bxor
) *bxor
= (*bxor
)^b
;
1775 static int fWriteWord (FILE *fo
, uint16_t w
, uint8_t *bxor
) {
1776 if (fWriteByte(fo
, w
&0xFFU
, bxor
)) return -1;
1777 if (fWriteByte(fo
, (w
>>8)&0xFFU
, bxor
)) return -1;
1782 static void saveTap (const char *basename
) {
1783 char *fname
= malloc(strlen(basename
)+16);
1785 int start
= 0, len
, f
;
1789 sprintf(fname
, "%s.tap", basename
);
1790 fo
= fopen(fname
, "wb");
1792 if (!fo
) { fprintf(stderr
, "ERROR: can't write file %s.tap!\n", basename
); return; }
1793 while (findChunkFrom(start
, &start
, &len
)) {
1795 sprintf(blkname
, "c%04X:%04X", start
, len
);
1796 printf(" block: %s\n", blkname
);
1797 fWriteWord(fo
, 19, NULL
); // length of header
1799 fWriteByte(fo
, 0, &bxor
); // header block
1800 fWriteByte(fo
, 3, &bxor
); // 'code' flag
1801 for (f
= 0; f
< 10; ++f
) fWriteByte(fo
, blkname
[f
], &bxor
);
1802 fWriteWord(fo
, len
, &bxor
);
1803 fWriteWord(fo
, start
, &bxor
);
1804 fWriteWord(fo
, 32768, &bxor
);
1805 fWriteByte(fo
, bxor
, NULL
);
1807 fWriteWord(fo
, len
+2, NULL
); // plus type and checkbyte
1809 fWriteByte(fo
, 0xFFU
, &bxor
); // data block
1810 for (f
= 0; f
< len
; ++f
) fWriteByte(fo
, memory
[start
+f
], &bxor
);
1811 fWriteByte(fo
, bxor
, NULL
);
1817 ///////////////////////////////////////////////////////////////////////////////
1820 static void initInclideDir (void) {
1821 const char *id
= getenv("URASM_INCLUDE_DIR");
1823 sysIncludeDir
= strdup(id
);
1825 char buf
[128], myDir
[4096];
1826 pid_t pid
= getpid();
1827 sprintf(buf
, "/proc/%u/exe", (unsigned int)pid
);
1828 memset(myDir
, 0, sizeof(myDir
));
1829 if (readlink(buf
, myDir
, sizeof(myDir
)-1) < 0) strcpy(myDir
, ".");
1831 char *p
= (char *)strrchr(myDir
, '/');
1832 if (!p
) strcpy(myDir
, "."); else *p
= '\0';
1834 strcat(myDir
, "/libs");
1835 sysIncludeDir
= strdup(myDir
);
1837 while (sysIncludeDir
[0] && sysIncludeDir
[strlen(sysIncludeDir
)-1] == '/') sysIncludeDir
[strlen(sysIncludeDir
)-1] = '\0';
1838 if (!sysIncludeDir
[0]) strcpy(sysIncludeDir
, ".");
1842 ///////////////////////////////////////////////////////////////////////////////
1853 static void usage (void) {
1855 "usage: urasm [options] infile\n"
1857 " -s -sna --sna write 48K .SNA file\n"
1858 " -S -SNA --SNA write 48K .SNA file with autostart\n"
1859 " -t -tap --tap write .tap file\n"
1860 " -T -TAP --TAP write raw file(s) -- for use with TAPE instructions\n"
1861 " -r -raw --raw write raw file(s)\n"
1862 " -b -bin --bin write raw file(s) -- same as '-r'\n"
1864 " -n -none --none write nothing\n"
1869 int main (int argc
, char *argv
[]) {
1871 const char *infile
= NULL
;
1872 static int optWriteType
= WRITE_SNA48
;
1874 printf("urasm, %s %s\n", __DATE__
, __TIME__
);
1875 while (argc
> 1 && argv
[1][0] == '-') {
1876 if (!strcmp(argv
[1], "-h") || !strcmp(argv
[1], "--help") || !strcmp(argv
[1], "-help")) {
1880 if (!strcmp(argv
[1], "-s") || !strcmp(argv
[1], "--sna") || !strcmp(argv
[1], "-sna")) {
1881 optWriteType
= WRITE_SNA48
;
1887 if (!strcmp(argv
[1], "-S") || !strcmp(argv
[1], "--SNA") || !strcmp(argv
[1], "-SNA")) {
1888 optWriteType
= WRITE_SNA48
;
1894 if (!strcmp(argv
[1], "-t") || !strcmp(argv
[1], "--tap") || !strcmp(argv
[1], "-tap")) {
1895 optWriteType
= WRITE_TAP
;
1900 if (!strcmp(argv
[1], "-r") || !strcmp(argv
[1], "--raw") || !strcmp(argv
[1], "-raw")) {
1901 optWriteType
= WRITE_RAW
;
1906 if (!strcmp(argv
[1], "-T") || !strcmp(argv
[1], "--TAP") || !strcmp(argv
[1], "-TAP")) {
1907 optWriteType
= WRITE_RAW
;
1912 if (!strcmp(argv
[1], "-b") || !strcmp(argv
[1], "--bin") || !strcmp(argv
[1], "-bin")) {
1913 optWriteType
= WRITE_RAW
;
1918 if (!strcmp(argv
[1], "-n") || !strcmp(argv
[1], "--none") || !strcmp(argv
[1], "-none")) {
1919 optWriteType
= WRITE_NONE
;
1923 fprintf(stderr
, "ERROR: invalid option: %s\n", argv
[1]);
1931 static const char *names
[] = {"main.zas", "main.a80", "main.asm", NULL
};
1933 for (f
= 0; names
[f
]; ++f
) {
1934 FILE *fl
= fopen(names
[f
], "r");
1942 fprintf(stderr
, "ERROR: no file name specified!\n");
1950 iptSetAbortCheckFn(&eng
, iptCheckAbort
);
1951 iptSetMarkFn(&eng
, smiMark
);
1953 iptAddPrim(&eng
, "SAY", iptPrimSAY
);
1954 iptAddPrim(&eng
, "GETPASS", iptPrimGETPASS
);
1955 iptAddPrim(&eng
, "GETPC", iptPrimGETPC
);
1956 iptAddPrim(&eng
, "GETDISP", iptPrimGETDISP
);
1957 iptAddPrim(&eng
, "SETPC", iptPrimSETPC
);
1958 iptAddPrim(&eng
, "SETDISP", iptPrimSETDISP
);
1959 iptAddPrim(&eng
, "GETBYTE", iptPrimGETBYTE
);
1960 iptAddPrim(&eng
, "PUTBYTE", iptPrimPUTBYTE
);
1961 iptAddPrim(&eng
, "EMITBYTE", iptPrimEMITBYTE
);
1962 iptAddPrim(&eng
, "ASSEMBLE", iptPrimASSEMBLE
);
1963 iptAddPrim(&eng
, "EXPRESSION", iptPrimEXPRESSION
);
1964 iptAddPrim(&eng
, "FINDLABEL", iptPrimFINDLABEL
);
1965 iptAddPrim(&eng
, "LABELTYPE", iptPrimLABELTYPE
);
1966 iptAddPrim(&eng
, "NEXTARG", iptPrimNEXTARG
);
1967 iptAddPrim(&eng
, "DEFMAC", iptPrimDEFMAC
);
1968 //iptAddPrim(&eng, "NEWLABEL", iptPrimNEWLABEL);
1969 //iptAddPrim(&eng, "LOCALIZELABEL", iptPrimLOCALIZELABEL);
1970 //iptAddPrim(&eng, "GETCURMODULE", iptPrimGETCURMODULE);
1972 urGetByte
= getByte
;
1973 urPutByte
= putByte
;
1974 urFindLabelByName
= findLabelCB
;
1976 urAddOp("TAPEHEADER", piTAPEHEADER
);
1977 urAddOp("TAPEDATA", piTAPEDATA
);
1978 urAddOp("ENDTAPEDATA", piENDTAPEDATA
);
1979 urAddOp("TAPEBLOCK", piTAPEBLOCK
);
1980 urAddOp("ENDTAPEBLOCK", piENDTAPEBLOCK
);
1982 urAddOp("DISPLAY", piDISPLAY
);
1983 urAddOp("DISPLAY0", piDISPLAY0
);
1984 urAddOp("MODULE", piMODULE
);
1985 urAddOp("ENDMODULE", piENDMODULE
);
1986 urAddOp("INCLUDE", piINCLUDE
);
1987 urAddOp("INCBIN", piINCBIN
);
1988 urAddOp("ENT", piENT
);
1989 urAddOp("ORG", piORG
);
1990 urAddOp("DISP", piDISP
);
1991 urAddOp("ENDDISP", piENDDISP
);
1992 urAddOp("ALIGN", piALIGN
);
1993 urAddOp("DISPALIGN", piDISPALIGN
);
1994 urAddOp("DUP", piDUP
);
1995 urAddOp("EDUP", piEDUP
);
1996 urAddOp("DEFB", piDEFB
);
1997 urAddOp("DB", piDEFB
);
1998 urAddOp("DEFW", piDEFW
);
1999 urAddOp("DW", piDEFW
);
2000 urAddOp("DEFR", piDEFR
);
2001 urAddOp("DR", piDEFR
);
2002 urAddOp("DEFS", piDEFS
);
2003 urAddOp("DS", piDEFS
);
2004 urAddOp("DEFM", piDEFM
);
2005 urAddOp("DM", piDEFM
);
2006 urAddOp("DEFZ", piDEFZ
);
2007 urAddOp("DZ", piDEFZ
);
2008 urAddOp("DEFX", piDEFX
);
2009 urAddOp("DX", piDEFX
);
2011 if (argc
> 2) optShowOut
= 1;
2012 for (pass
= 0; pass
<= 1; ++pass
) {
2013 printf("pass %d...\n", pass
);
2014 pc
= disp
= ent
= 0x100;
2019 prepareMemory(optWriteType
==WRITE_SNA48
);
2020 res
= processFile(infile
);
2022 if (checkLabels()) goto quit
;
2024 clearKnownModules();
2025 if (tapeBlockName
) free(tapeBlockName
); tapeBlockName
= NULL
;
2026 if (lastSeenLabel
) free(lastSeenLabel
); lastSeenLabel
= NULL
;
2027 if (curModuleName
) free(curModuleName
); curModuleName
= NULL
;
2031 char *oc
= strdup(infile
);
2032 char *ps
= strchr(oc
, '/');
2033 char *pd
= strchr(oc
, '.');
2034 if (pd
&& (!ps
|| pd
> ps
)) *pd
= '\0';
2035 switch (optWriteType
) {
2036 case WRITE_RAW
: saveBinChunks(oc
); break;
2037 case WRITE_TAP
: saveTap(oc
); break;
2038 case WRITE_SNA48
: writeSNA(oc
); break;
2045 if (tapeBlockName
) free(tapeBlockName
);
2046 if (sysIncludeDir
) free(sysIncludeDir
);
2047 if (lastSeenLabel
) free(lastSeenLabel
);
2048 if (curModuleName
) free(curModuleName
);
2050 clearKnownModules();