12 ////////////////////////////////////////////////////////////////////////////////
22 ////////////////////////////////////////////////////////////////////////////////
23 #define MAX_TOKEN_LENGTH (256)
43 ////////////////////////////////////////////////////////////////////////////////
44 static uint8_t vmcode
[65536];
48 ////////////////////////////////////////////////////////////////////////////////
49 typedef struct InputContext
{
50 struct InputContext
*prev
;
59 static InputContext
*ictx
= NULL
;
61 static char tstr
[MAX_TOKEN_LENGTH
+1];
63 static int incLevel
= 0;
66 ////////////////////////////////////////////////////////////////////////////////
67 static __attribute__((__noreturn__
)) __attribute__((format(printf
, 1, 2))) void fatal (const char *fmt
, ...) {
71 fprintf(stderr
, "FATAL (line %d, file '%s'): ", ictx
->lineno
, ictx
->fname
);
73 fprintf(stderr
, "FATAL: ");
76 vfprintf(stderr
, fmt
, ap
);
78 fprintf(stderr
, "\n");
83 ////////////////////////////////////////////////////////////////////////////////
84 static void openFile (const char *fname
) {
85 InputContext
*ic
= malloc(sizeof(InputContext
));
87 if (ic
== NULL
) abort();
88 ic
->fl
= fopen(fname
, "r");
89 if (ic
->fl
== NULL
) fatal("can't open file: '%s'", fname
);
91 ic
->fname
= strdup(fname
);
95 for (int f
= 0; f
< incLevel
; ++f
) fputc(' ', stderr
);
97 fprintf(stderr
, "compiling: %s\n", fname
);
101 static void closeFile (void) {
103 InputContext
*ic
= ictx
;
107 if (ic
->fname
) free(ic
->fname
);
111 for (int f
= 0; f
< incLevel
-1; ++f
) fputc(' ', stderr
);
112 //fprintf(stderr, "compiling: %s\n", ictx->fname);
118 ////////////////////////////////////////////////////////////////////////////////
119 static void ungetChar (int c
) {
120 if (c
!= EOF
&& ictx
!= NULL
) {
121 if (ictx
->ucnt
>= 4) fatal("too many unread chars");
122 ictx
->uca
[ictx
->ucnt
++] = c
;
127 static int tokenWantFileName
= 0;
129 static int nextChar (void) {
132 if (ictx
== NULL
) return EOF
;
133 if (ictx
->ucnt
> 0) {
134 c
= ictx
->uca
[--ictx
->ucnt
];
139 c
= (ictx
==NULL
? EOF
: '\n');
141 if (c
== '\n') ++(ictx
->lineno
);
144 if (!tokenWantFileName
) {
145 if (c
>= 'A' && c
<= 'Z') c
+= 32; // tolower
151 static void skipSpaces (void) {
155 if (c
== EOF
) return;
157 do { c
= nextChar(); } while (c
!= EOF
&& c
!= '\n');
164 do { c
= nextChar(); } while (c
!= EOF
&& c
!= '\n');
182 if (c
> 32) { ungetChar(c
); break; }
187 static int digit (int c
, int base
) {
188 if (c
== EOF
) return -1;
189 if (c
>= 'a' && c
<= 'z') c
-= 32;
190 if (c
> '9' && c
< 'A') return -1;
193 if (c
< 0 || c
>= base
) return -1;
198 static void getNumber (int c
) {
205 if (c
== EOF
) return;
208 case 'b': case 'B': base
= 2; break;
209 case 'o': case 'O': base
= 8; break;
210 case 'd': case 'D': base
= 10; break;
211 case 'x': case 'X': base
= 16; break;
213 if (isalpha(c
)) fatal("invalid number");
214 if (c
!= EOF
) ungetChar(c
);
218 if (digit(c
, base
) < 0) fatal("invalid number");
223 int d
= digit(c
, base
);
226 tint
= (tint
*base
)+d
;
227 if (tint
> 32767) fatal("number constant too big");
230 if (c
!= EOF
&& isalpha(c
)) fatal("invalid number");
231 if (c
!= EOF
) ungetChar(c
);
235 static int nextToken (void) {
238 memset(tstr
, 0, sizeof(tstr
));
242 if (ictx
== NULL
) return TK_EOF
;
244 if (c
== EOF
) return TK_EOF
;
245 if (c
>= 127) fatal("invalid char (%d)", c
);
249 if (isalpha(c
) || c
== '_' || c
== '$' || c
== '.' || c
== '@' || (tokenWantFileName
&& c
== '/')) {
255 if (isalnum(c
) || c
== '_' || c
== '$' || c
== '.' || c
== '@' || (tokenWantFileName
&& c
== '/')) {
256 if (f
>= MAX_TOKEN_LENGTH
-1) fatal("identifier too long");
257 //if (c >= 'A' && c <= 'Z') c += 32; // tolower
260 //if (c != ';' && c > 32) fatal("invalid identifier");
265 if (!isalnum(tstr
[0]) && !tstr
[1]) {
266 if (c
!= EOF
&& c
> 32) ungetChar(c
);
272 if (!tokenWantFileName
) {
275 } else if (c
<= 32 && c
!= '\n') {
278 if (c
== ':') { token
= TK_LABELDEF
; break; }
279 if (c
> 32) ungetChar(c
);
280 if (c
== EOF
|| c
> 32) break;
283 if (c
!= EOF
&& c
> 32) ungetChar(c
);
287 for (f
= 0; vmOpNames
[f
]; ++f
) {
288 if (strcmp(tstr
, vmOpNames
[f
]) == 0) {
289 if (token
== TK_LABELDEF
) fatal("invalid label: '%s'", tstr
);
290 token
= TK_VM_OPERATOR
+f
;
294 if (token
< TK_VM_OPERATOR
) {
295 if (strcmp(tstr
, "drp") == 0) token
= VMX_DRP
;
296 else if (strcmp(tstr
, "dup") == 0) token
= VMX_DUP
;
297 else if (strcmp(tstr
, "rtn") == 0) token
= VMX_RTN
;
299 } else if (strcmp(tstr
, "return") == 0) {
303 } else if (c
== '-' || c
== '+') {
307 if ((c
= nextChar()) != EOF
) {
310 if (neg
) tint
= -tint
;
315 } else if (isdigit(c
)) {
326 ////////////////////////////////////////////////////////////////////////////////
327 typedef struct LabelInfo
{
328 struct LabelInfo
*next
;
331 int value
; // code && <0: not defined yet (forward ref)
338 static LabelInfo
*labels
= NULL
;
340 static int vglast
= 0;
341 static int vtlast
= 0;
342 static int vtloc
= VM_VARS_SIZE
-1; // local thread (var 126 is used for internal thing)
345 static void addLabelRef (LabelInfo
*l
, int pc
) {
346 if (l
!= NULL
&& l
->type
== LB_CODE
&& l
->value
< 0) {
347 if (l
->fixes
== NULL
) {
348 l
->fixes
= malloc(sizeof(int)*32768);
349 if (l
->fixes
== NULL
) fatal("out of memory");
352 if (l
->fixCount
> 32760) {
353 fatal("too many label references");
355 l
->fixes
[l
->fixCount
++] = pc
;
357 //fprintf(stderr, "*[%s] fixup #%d at 0x%04x\n", l->name, l->fixCount-1, pc);
362 static void fixupLabelRefs (LabelInfo
*l
, int pc
) {
366 for (int f
= 0; f
< l
->fixCount
; ++f
) {
367 //fprintf(stderr, "[%s] FIXUP #%d: 0x%04x=0x%04x\n", l->name, f, l->fixes[f], pc);
368 vmcode
[l
->fixes
[f
]] = pc
&0xff;
369 vmcode
[l
->fixes
[f
]+1] = (pc
>>8)&0xff;
376 static void checkLabels (void) {
377 for (LabelInfo
*l
= labels
; l
!= NULL
; l
= l
->next
) {
378 if (l
->type
== LB_CODE
&& l
->value
< 0) fatal("undefined label: '%s'", l
->name
);
383 static void freeLabels (void) {
385 LabelInfo
*l
= labels
;
387 if (l
->type
== LB_CODE
&& l
->value
< 0) fatal("undefined label: '%s'", l
->name
);
389 if (l
->fixes
) free(l
->fixes
);
396 static void freeLocalLabels (int onlyVars
) {
397 LabelInfo
*p
= NULL
, *c
= labels
;
400 LabelInfo
*n
= c
->next
;
402 if ((!onlyVars
|| c
->type
!= LB_CODE
) && c
->name
[0] == '.') {
403 if (c
->type
== LB_CODE
&& c
->value
< 0) fatal("undefined label: '%s'", c
->name
);
404 if (c
->fixes
) free(c
->fixes
);
407 if (p
!= NULL
) p
->next
= n
; else labels
= n
;
416 static LabelInfo
*findLabel (const char *name
) {
417 if (name
&& name
[0] == '@') ++name
;
418 if (!name
|| !name
[0]) return NULL
;
419 for (LabelInfo
*l
= labels
; l
!= NULL
; l
= l
->next
) if (strcmp(l
->name
, name
) == 0) return l
;
424 static LabelInfo
*addLabel (const char *name
) {
427 if (!name
|| !name
[0]) abort();
428 //if (strcmp(name, "item_glovesg") == 0) fatal("!!!");
429 if (findLabel(name
)) fatal("duplicate label: '%s'", name
);
430 l
= malloc(sizeof(LabelInfo
));
431 if (l
== NULL
) fatal("out of memory");
432 l
->name
= strdup(name
);
433 if (l
->name
== NULL
) fatal("out of memory");
445 ////////////////////////////////////////////////////////////////////////////////
447 LabelInfo
*l
; // !=NULL: label
449 int value
; // if l==NULL
450 int vartype
; // 0: global; 1: tlocal; 2: stack
454 static void setIntOperand (OperandInfo
*op
, int value
) {
462 static void setLabelOperand (OperandInfo
*op
, LabelInfo
*l
) {
470 static void getOperand (OperandInfo
*op
, int wantCode
) {
471 if (token
== TK_ID
) {
472 LabelInfo
*l
= findLabel(tstr
);
480 if (wantCode
&& l
->type
!= LB_CODE
) fatal("code offset expected");
482 setLabelOperand(op
, l
);
487 if (token
== TK_NUM
) {
488 if (wantCode
) fatal("code offset expected");
489 setIntOperand(op
, tint
);
495 //if (wantCode) fatal("code offset expected");
497 if (token
== TK_ID
) {
498 LabelInfo
*l
= findLabel(tstr
);
500 if (l
== NULL
|| l
->type
== LB_CODE
) fatal("unknown variable: '%s'", tstr
);
501 setLabelOperand(op
, l
);
502 } else if (token
== '@' || token
== '.') {
505 if (nextToken() != TK_NUM
) fatal("index expected");
506 setIntOperand(op
, tint
);
509 if (tint
< 0 || tint
> 126) fatal("invalid variable index");
510 op
->vartype
= loc
=='@' ? 0 : 1;
515 } else if (token
== TK_NUM
) {
517 if (tint
< 0 || tint
> 126) fatal("invalid variable index");
518 setIntOperand(op
, tint
);
521 fatal("invalid operand");
524 if (nextToken() != ']') fatal("']' expected");
529 fprintf(stderr
, "*%d [%s] %d\n", token
, tstr
, tint
);
530 fatal("invalid operand");
534 static inline int hasOperand (void) {
535 return (token
!= TK_EOF
&& token
!= TK_LABELDEF
&& token
< TK_VM_OPERATOR
);
539 ////////////////////////////////////////////////////////////////////////////////
540 static void emitByte (int b
) {
541 if (b
< 0 || b
> 255) fatal("internal error");
542 if (pc
>= 32768) fatal("code too big");
547 static void emitOpCode (int opc
, int opcount
) {
548 if (opc
< 0 || opc
> 63 || opcount
< 0 || opcount
> 3) fatal("internal error");
549 emitByte(opc
|(opcount
<<6));
554 static void emitInteger (int val) {
555 emitByte(255); // special
557 emitByte((val>>8)&0xff);
562 static void emitOperand (OperandInfo
*op
) {
563 if (!op
|| op
->var
< 0) return;
569 switch (op
->l
->type
) {
570 case LB_GVAR
: emitByte(op
->l
->value
|0x80); break;
571 case LB_TVAR
: emitByte(op
->l
->value
); break;
573 emitByte(127); // special
574 emitByte(op
->l
->value
&0xff);
575 emitByte((op
->l
->value
>>8)&0xff);
577 default: fatal("internal error");
581 switch (op
->vartype
) {
582 case 0: emitByte(op
->value
|0x80); break;
583 case 1: emitByte(op
->value
); break;
585 emitByte(127); // special
586 emitByte(op
->value
&0xff);
587 emitByte((op
->value
>>8)&0xff);
589 default: fatal("internal error");
597 emitByte(255); // special
600 if (op
->l
->type
== LB_CODE
&& op
->l
->value
< 0) {
602 addLabelRef(op
->l
, pc
);
607 emitByte(op
->l
->value
&0xff);
608 emitByte((op
->l
->value
>>8)&0xff);
612 if (op
->value
< -32767 || op
->value
> 32767) fatal("invalid value");
613 emitByte(op
->value
&0xff);
614 emitByte((op
->value
>>8)&0xff);
620 static void emitInstruction (int opc
, OperandInfo
*op0
, OperandInfo
*op1
, OperandInfo
*op2
) {
623 if (op0
&& op0
->var
>= 0) ++ocnt
;
624 if (ocnt
== 1 && op1
&& op1
->var
>= 0) ++ocnt
;
625 if (ocnt
== 2 && op2
&& op2
->var
>= 0) ++ocnt
;
626 emitOpCode(opc
, ocnt
);
627 if (ocnt
> 0) emitOperand(op0
);
628 if (ocnt
> 1) emitOperand(op1
);
629 if (ocnt
> 2) emitOperand(op2
);
633 ////////////////////////////////////////////////////////////////////////////////
634 static void doNoOperands (int opcode
) {
635 emitInstruction(opcode
, NULL
, NULL
, NULL
);
639 static void doMath (int opcode
) {
640 OperandInfo op0
, op1
, op2
;
642 op0
.var
= op1
.var
= op2
.var
= -1;
651 if (op2
.var
!= 1) fatal("variable expected as third operand");
653 if (op0
.var
!= 1) fatal("variable expected as first operand");
657 emitInstruction(opcode
, &op0
, &op1
, &op2
);
661 static void doJXX (int opcode
) {
662 OperandInfo op0
, op1
, op2
;
664 op0
.var
= op1
.var
= op2
.var
= -1;
676 emitInstruction(opcode
, &op0
, &op1
, &op2
);
680 static void doBranch (int opcode
) {
687 emitInstruction(opcode
, &op0
, NULL
, NULL
);
691 static void doBSR (int opcode
) {
692 OperandInfo op0
, op1
, op2
;
694 op0
.var
= op1
.var
= op2
.var
= -1;
706 emitInstruction(opcode
, &op0
, &op1
, &op2
);
710 static void doMap (int opcode
, int lastMBV
) {
711 OperandInfo op0
, op1
, op2
;
713 op0
.var
= op1
.var
= op2
.var
= -1;
725 emitInstruction(opcode
, &op0
, &op1
, &op2
);
729 static void doRST (int opcode
) {
730 OperandInfo op0
, op1
, op2
;
732 op0
.var
= op1
.var
= op2
.var
= -1;
744 emitInstruction(opcode
, &op0
, &op1
, &op2
);
748 static void doSet (int opcode
) {
749 OperandInfo op0
, op1
, op2
;
751 op0
.var
= op1
.var
= op2
.var
= -1;
761 if (op2
.var
< 0 && op0
.var
!= 1) fatal("first operand should be var");
762 emitInstruction(opcode
, &op0
, &op1
, &op2
);
766 static void doDrop (int opcode
) {
770 if (hasOperand()) getOperand(&op0
, 0);
771 if (op0
.var
> 0) fatal("number expected");
772 if (op0
.value
< 0) fatal("positive number expected");
773 emitInstruction(opcode
, &op0
, NULL
, NULL
);
777 static void doPush (int opcode
) {
778 OperandInfo op0
, op1
, op2
;
780 op0
.var
= op1
.var
= op2
.var
= -1;
790 emitInstruction(opcode
, &op0
, &op1
, &op2
);
794 static void doPop (int opcode
) {
795 OperandInfo op0
, op1
, op2
;
797 op0
.var
= op1
.var
= op2
.var
= -1;
809 emitInstruction(opcode
, &op0
, &op1
, &op2
);
813 static void doSwap (int opcode
) {
814 OperandInfo op0
, op1
;
816 op0
.var
= op1
.var
= -1;
824 emitInstruction(opcode
, &op0
, &op1
, NULL
);
828 static void doDepth (int opcode
) {
832 if (hasOperand()) getOperand(&op0
, 0);
833 emitInstruction(opcode
, &op0
, NULL
, NULL
);
837 static void doPickRoll (int opcode
) {
838 OperandInfo op0
, op1
;
840 op0
.var
= op1
.var
= -1;
846 if (op1
.var
!= 1) fatal("second argument must be variable");
849 emitInstruction(opcode
, &op0
, &op1
, NULL
);
853 static void doNew (int opcode
) {
854 OperandInfo op0
, op1
;
856 op0
.var
= op1
.var
= -1;
864 emitInstruction(opcode
, &op0
, &op1
, NULL
);
868 static void doTId (int opcode
) {
872 if (hasOperand()) getOperand(&op0
, 0);
873 emitInstruction(opcode
, &op0
, NULL
, NULL
);
877 static void doKillSusRes (int opcode
) {
881 if (hasOperand()) getOperand(&op0
, 0);
882 emitInstruction(opcode
, &op0
, NULL
, NULL
);
886 static void doSta (int opcode
) {
887 OperandInfo op0
, op1
;
889 op0
.var
= op1
.var
= -1;
895 if (op1
.var
!= 1) fatal("variable expected");
898 emitInstruction(opcode
, &op0
, &op1
, NULL
);
902 static void doGet (int opcode
) {
903 OperandInfo op0
, op1
, op2
;
905 op0
.var
= op1
.var
= op2
.var
= -1;
907 if (token
!= ',') fatal("at least two operands expected");
913 if (op2
.var
!= 1) fatal("variable expected as third operand");
915 emitInstruction(opcode
, &op0
, &op1
, &op2
);
919 static void doRXC (int opcode
) {
920 OperandInfo op0
, op1
;
922 op0
.var
= op1
.var
= -1;
928 if (op1
.var
!= 1) fatal("variable expected as second operand");
931 emitInstruction(opcode
, &op0
, &op1
, NULL
);
935 static void doWXC (int opcode
) {
936 OperandInfo op0
, op1
;
938 op0
.var
= op1
.var
= -1;
946 emitInstruction(opcode
, &op0
, &op1
, NULL
);
950 static void doRet (int opcode
) {
951 OperandInfo op0
, op1
, op2
;
953 op0
.var
= op1
.var
= op2
.var
= -1;
956 if (token
!= ',') fatal("at least two operands expected");
964 emitInstruction(opcode
, &op0
, &op1
, &op2
);
968 ////////////////////////////////////////////////////////////////////////////////
969 static void parseInlcude (void) {
970 static char fname
[8192], *t
;
972 tokenWantFileName
= 1;
973 if (nextToken() != TK_ID
) fatal("identifier expected");
974 tokenWantFileName
= 0;
975 strcpy(fname
, ictx
->fname
);
976 t
= strrchr(fname
, '/');
977 if (t
!= NULL
) t
[1] = 0; else fname
[0] = 0;
979 if (incLevel
> 64) fatal("too many includes");
985 static void parseVarList (int type
, int local
) {
989 if (nextToken() != TK_ID
) fatal("identifier expected");
990 if (tstr
[0] == '.' && local
<= 0) fatal("invalid variable name: '%s'", tstr
);
991 if (tstr
[0] != '.' && local
> 0) fatal("invalid variable name: '%s'", tstr
);
993 if (l
!= NULL
) fatal("duplicate variable or label: '%s'", tstr
);
996 if (local
> 0 && vtloc
<= vtlast
) fatal("too many local vars");
997 l
->value
= local
>0?(--vtloc
):(type
==LB_GVAR
?vglast
++:vtlast
++);
998 if (local
< 0) l
->ext
= 1;
999 if (l
->value
> 126) fatal("too many vars");
1000 if (nextToken() != ',') break;
1005 static void parseExterns (void) {
1009 if (nextToken() != TK_ID
) fatal("identifier expected");
1010 if (tstr
[0] == '.') fatal("invalid label name: '%s'", tstr
);
1011 l
= findLabel(tstr
);
1020 if (nextToken() != ',') break;
1025 static void parseLocList (void) {
1029 if (nextToken() != TK_ID
) fatal("identifier expected");
1030 if (tstr
[0] != '.') fatal("local identifier expected instead of '%s'", tstr
);
1031 l
= findLabel(tstr
);
1032 if (l
!= NULL
) fatal("can't redefine label as local: '%s'", tstr
);
1037 if (nextToken() != '=') fatal("'=' expected");
1038 if (nextToken() != TK_NUM
) fatal("number expected");
1040 if (nextToken() != ',') break;
1045 static void parseConst (int ext
) {
1048 if (nextToken() != TK_ID
) fatal("identifier expected");
1049 if (tstr
[0] == '.') fatal("invalid constant name: '%s'", tstr
);
1050 l
= findLabel(tstr
);
1051 if (l
!= NULL
) fatal("constant must be unique: '%s'", tstr
);
1053 if (nextToken() == '=') nextToken();
1054 if (token
!= TK_NUM
) fatal("constant must be numeric");
1062 static char procname
[8192];
1063 static int proclocals
= 0;
1064 static int procargs
= 0;
1065 static int lastWasReturn
= 0;
1068 static void parseProc (int ext
) {
1069 LabelInfo
*l
, *a
= NULL
;
1073 if (nextToken() != TK_ID
) fatal("identifier expected");
1074 if (tstr
[0] == '.') fatal("invalid proc name: '%s'", tstr
);
1075 if (procname
[0]) fatal("unclosed proc: '%s'", procname
);
1076 strcpy(procname
, tstr
);
1079 freeLocalLabels(0); // vars and code
1081 l
= findLabel(tstr
);
1083 if (l
->type
!= LB_CODE
|| l
->value
>= 0) fatal("duplicate proc label: '%s'", tstr
);
1084 fixupLabelRefs(l
, pc
);
1090 if (ext
) l
->ext
= 1;
1094 while (token
== TK_LABELDEF
&& (strcmp(tstr
, "arg") == 0 || strcmp(tstr
, "args") == 0)) {
1096 if (nextToken() != TK_ID
) fatal("identifier expected");
1097 if (tstr
[0] != '.') fatal("argument name must starts with '.'");
1098 l
= findLabel(tstr
);
1099 if (l
!= NULL
) fatal("duplicate argument: '%s'", l
->name
);
1104 if (nextToken() != ',') break;
1108 // -1: return address, -2: last arg
1109 for (spt
= -2, l
= a
; l
->type
== LB_SVAR
; l
= l
->next
) {
1115 spt
= -1; // first local
1116 while (token
== TK_LABELDEF
&& (strcmp(tstr
, "local") == 0 || strcmp(tstr
, "locals") == 0)) {
1118 if (nextToken() != TK_ID
) fatal("identifier expected");
1119 if (tstr
[0] != '.') fatal("local variable name must starts with '.'");
1120 l
= findLabel(tstr
);
1121 if (l
!= NULL
) fatal("duplicate local: '%s'", l
->name
);
1127 for (l
= a
; l
!= NULL
&& l
->type
== LB_SVAR
; l
= l
->next
) --(l
->value
);
1128 if (nextToken() != ',') break;
1132 if (proclocals
> 0) {
1136 setIntOperand(&op0
, -proclocals
);
1137 emitInstruction(VM_POP
, &op0
, NULL
, NULL
);
1142 static void parseEndP (void) {
1143 if (!procname
[0]) fatal("'endp' without 'proc'");
1144 if (nextToken() != TK_ID
) fatal("identifier expected");
1145 if (strcmp(procname
, tstr
) != 0) fatal("endp for '%s' in proc '%s'", tstr
, procname
);
1146 //if (!lastWasReturn) fatal("no 'return' in proc");
1153 static void doReturn (void) {
1154 OperandInfo op0
, op1
, op2
;
1156 if (!procname
[0]) fatal("'return' without 'proc'");
1158 op0
.var
= op1
.var
= op2
.var
= -1;
1159 if (hasOperand()) getOperand(&op2
, 0); // result
1160 setIntOperand(&op0
, proclocals
);
1161 setIntOperand(&op1
, procargs
);
1162 emitInstruction(VM_RET
, &op0
, &op1
, &op2
);
1166 static void parseLabel (void) {
1169 if (tstr
[0] != '.' && tstr
[0] != '@') {
1170 if (procname
[0]) fatal("you can not define non-special global labels inside proc ('%s')", procname
);
1171 freeLocalLabels(0); // vars and code
1173 if (tstr
[0] == '@') {
1176 while (*d
++) d
[-1] = d
[0];
1179 l
= findLabel(tstr
);
1181 if (l
->type
!= LB_CODE
|| l
->value
>= 0) fatal("duplicate label: '%s'", tstr
);
1182 fixupLabelRefs(l
, pc
);
1192 static void parseDB (void) {
1195 if (token
== TK_ID
) {
1196 LabelInfo
*l
= findLabel(tstr
);
1198 if (l
== NULL
) fatal("unknown label: '%s'", tstr
);
1199 if (l
->type
== LB_CODE
) fatal("bad label type: '%s'", l
->name
);
1201 } else if (token
!= TK_NUM
) {
1202 fatal("number expected");
1204 if (tint
< -128 || tint
> 255) fatal("bad value: %d", tint
);
1205 emitByte(tint
&0xff);
1206 if (nextToken() != ',') break;
1211 static void parseDW (void) {
1214 if (token
== TK_ID
) {
1215 LabelInfo
*l
= findLabel(tstr
);
1221 //fatal("unknown label: '%s'", tstr);
1225 } else if (token
!= TK_NUM
) {
1226 fatal("number expected");
1228 //if (tint < -128 || tint > 255) fatal("bad value: %d", tint);
1229 emitByte(tint
&0xff);
1230 emitByte((tint
>>8)&0xff);
1231 if (nextToken() != ',') break;
1237 static void parseAndPutString (int qch
) {
1239 int ch
= nextChar();
1241 if (ch
== EOF
) fatal("unterminated string");
1243 if (ch
== qch
) break;
1248 if (ch
== EOF
) fatal("invalid escape");
1250 case 'a': emitByte('\a'); break;
1251 case 'b': emitByte('\b'); break;
1252 case 'e': emitByte('\x1b'); break;
1253 case 'f': emitByte('\f'); break;
1254 case 'n': emitByte('\n'); break;
1255 case 'r': emitByte('\r'); break;
1256 case 't': emitByte('\t'); break;
1257 case 'v': emitByte('\v'); break;
1258 case '"': case '\'': case '\\': case ' ': emitByte(ch
); break;
1260 n
= digit(nextChar(), 16);
1261 if (n
< 0) fatal("invalid hex escape");
1263 if (ch
== EOF
) fatal("invalid hex escape");
1264 if (digit(ch
, 16)) {
1265 n
= n
*16+digit(ch
, 16);
1271 default: fatal("invalid escape: '%c'", ch
);
1279 if (ch
== EOF
) return;
1294 static void parseDAscii (int zeroend
) {
1300 if (ch
== EOF
) break;
1302 case '"': tokenWantFileName
= 1; parseAndPutString(ch
); tokenWantFileName
= 0; break;
1303 case '\'': tokenWantFileName
= 1; parseAndPutString(ch
); tokenWantFileName
= 0; break;
1307 if (token
== TK_ID
) {
1308 LabelInfo
*l
= findLabel(tstr
);
1310 if (l
== NULL
) fatal("unknown label: '%s'", tstr
);
1311 if (l
->type
== LB_CODE
) fatal("bad label type: '%s'", l
->name
);
1313 } else if (token
!= TK_NUM
) {
1314 fatal("number expected");
1316 if (tint
< -128 || tint
> 255) fatal("bad value: %d", tint
);
1317 emitByte(tint
&0xff);
1319 if (nextToken() != ',') break;
1321 if (zeroend
) emitByte(0);
1325 static void process (void) {
1326 LabelInfo
*l
= addLabel("retval");
1328 l
->value
= VM_VARS_SIZE
-1;
1333 while (token
!= TK_EOF
) {
1336 if (token
== TK_LABELDEF
) {
1337 // new label or operator
1338 if (strcmp(tstr
, "include") == 0) {
1340 } else if (strcmp(tstr
, "defloc") == 0) {
1342 } else if (strcmp(tstr
, "defgvar") == 0) {
1343 parseVarList(LB_GVAR
, 0);
1344 } else if (strcmp(tstr
, "defevar") == 0) { // extern global
1345 parseVarList(LB_GVAR
, -1);
1346 } else if (strcmp(tstr
, "deftvar") == 0) {
1347 freeLocalLabels(1); // only vars
1348 vtloc
= VM_VARS_SIZE
;
1349 parseVarList(LB_TVAR
, 0);
1350 } else if (strcmp(tstr
, "defetvar") == 0) {
1351 freeLocalLabels(1); // only vars
1352 vtloc
= VM_VARS_SIZE
;
1353 parseVarList(LB_TVAR
, -1);
1354 } else if (strcmp(tstr
, "deflvar") == 0) {
1355 parseVarList(LB_TVAR
, 1);
1356 } else if (strcmp(tstr
, "extern") == 0) {
1358 } else if (strcmp(tstr
, "proc") == 0 || strcmp(tstr
, "eproc") == 0) {
1359 parseProc(tstr
[0] == 'e');
1360 } else if (strcmp(tstr
, "endp") == 0) {
1362 } else if (strcmp(tstr
, "const") == 0 || strcmp(tstr
, "econst") == 0) {
1363 parseConst(tstr
[0] == 'e');
1364 } else if (strcmp(tstr
, "db") == 0) {
1366 } else if (strcmp(tstr
, "dw") == 0) {
1368 } else if (strcmp(tstr
, "da") == 0) {
1370 } else if (strcmp(tstr
, "dz") == 0) {
1378 if (token
< TK_VM_OPERATOR
) fatal("mnemonics expected");
1380 if (opc
< 600) opc
-= TK_VM_OPERATOR
;
1468 if (procname
[0]) doReturn(); else doRet(opc
);
1474 doNoOperands(VM_PSH
);
1486 if (procname
[0]) fatal("'proc' without 'endp': '%s'", procname
);
1491 static void dumpGlobalVars (const char *fname) {
1494 if (fname == NULL || !fname[0]) return;
1495 fl = fopen(fname, "w");
1497 fprintf(fl, "#ifndef _VM_GVARS_HEADER_\n");
1498 fprintf(fl, "#define _VM_GVARS_HEADER_\n\n");
1499 for (LabelInfo *l = labels; l != NULL; l = l->next) {
1501 static char name[4096];
1503 strcpy(name, l->name);
1504 for (int f = 0; name[f]; ++f) {
1505 name[f] = toupper(name[f]);
1506 if (!isalnum(name[f]) && name[f] != '_') name[f] = '_';
1508 fprintf(fl, "#define ");
1510 case LB_GVAR: fprintf(fl, "GVAR"); break;
1511 case LB_TVAR: fprintf(fl, "TVAR"); break;
1512 case LB_CODE: fprintf(fl, "CODE"); break;
1513 case LB_CONST: fprintf(fl, "CONST"); break;
1515 fprintf(fl, "_%s (%d)\n", name, l->value);
1518 fprintf(fl, "\n#endif\n");
1524 ////////////////////////////////////////////////////////////////////////////////
1525 int main (int argc
, char *argv
[]) {
1527 fprintf(stderr
, "usage: awasm infile outfile\n");
1531 //while (nextToken() != TK_EOF) printf("%d [%s] %d\n", token, tstr, tint); return 0;
1533 while (ictx
!= NULL
) closeFile();
1535 //if (argc > 3) dumpGlobalVars(argv[3]);
1537 FILE *fo
= fopen(argv
[2], "wb");
1538 const char *sign
= "AVM0";
1542 for (LabelInfo
*l
= labels
; l
!= NULL
; l
= l
->next
) if (l
->ext
) ++lcnt
;
1544 if (fo
== NULL
) { fprintf(stderr
, "FATAL: can't create output file: '%s'\n", argv
[2]); return 1; }
1546 printf("%d bytes of code, %d public labels\n", pc
, lcnt
);
1548 fwrite(sign
, 4, 1, fo
);
1551 fwrite(&b
, 1, 1, fo
);
1553 fwrite(&b
, 1, 1, fo
);
1555 for (int f
= 0; f
< pc
; ++f
) vmcode
[f
] ^= 42;
1556 fwrite(vmcode
, pc
, 1, fo
);
1559 fwrite(&b
, 1, 1, fo
);
1561 fwrite(&b
, 1, 1, fo
);
1563 for (LabelInfo
*l
= labels
; l
!= NULL
; l
= l
->next
) {
1566 fwrite(&b
, 1, 1, fo
);
1572 fwrite(&b
, 1, 1, fo
);
1578 fwrite(&b
, 1, 1, fo
);
1579 b
= (l
->value
>>8)&0xff;
1580 fwrite(&b
, 1, 1, fo
);
1586 b
= strlen(l
->name
);
1587 fwrite(&b
, 1, 1, fo
);
1588 for (int f
= 0; l
->name
[f
]; ++f
) {
1589 b
= (unsigned char)(l
->name
[f
]);
1591 fwrite(&b
, 1, 1, fo
);