xref: /inferno-os/appl/cmd/asm/asm.y (revision 70a234d0b5dd59660347742b2c5f3098522e5a80)
1 %{
2 
3 include "sys.m";
4 	sys: Sys;
5 
6 include "draw.m";
7 
8 include "bufio.m";
9 	bufio: Bufio;
10 	Iobuf: import bufio;
11 
12 include "math.m";
13 	math: Math;
14 	export_real: import math;
15 
16 include "string.m";
17 	str: String;
18 
19 include "arg.m";
20 
21 include "../limbo/isa.m";
22 
23 YYSTYPE: adt {
24 	inst:	ref Inst;
25 	addr:	ref Addr;
26 	op:	int;
27 	ival:	big;
28 	fval:	real;
29 	str:	string;
30 	sym:	ref Sym;
31 	listv:	ref List;
32 };
33 
34 YYLEX: adt {
35 	lval:	YYSTYPE;
36 	EOF:	con -1;
37 	lex:	fn(l: self ref YYLEX): int;
38 	error:	fn(l: self ref YYLEX, msg: string);
39 
40 	numsym:	fn(l: self ref YYLEX, first: int): int;
41 	eatstring:	fn(l: self ref YYLEX);
42 };
43 
44 Eof: con -1;
45 False: con 0;
46 True: con 1;
47 Strsize: con 1024;
48 Hashsize: con 128;
49 
50 Addr: adt
51 {
52 	mode:	int;
53 	off:	int;
54 	val:	int;
55 	sym:	ref Sym;
56 
57 	text:	fn(a: self ref Addr): string;
58 };
59 
60 List: adt
61 {
62 	link:	cyclic ref List;
63 	addr:	int;
64 	typ:	int;
65 	pick{
66 	Int =>	ival: big;	# DEFB, DEFW, DEFL
67 	Bytes =>	b: array of byte;	# DEFF, DEFS
68 	Array =>	a: ref Array;	# DEFA
69 	}
70 };
71 
72 Inst: adt
73 {
74 	op:	int;
75 	typ:	int;
76 	size:	int;
77 	reg:	ref Addr;
78 	src:	ref Addr;
79 	dst:	ref Addr;
80 	pc:	int;
81 	sym:	ref Sym;
82 	link:	cyclic ref Inst;
83 
84 	text:	fn(i: self ref Inst): string;
85 };
86 
87 Sym: adt
88 {
89 	name:	string;
90 	lexval:	int;
91 	value:	int;
92 	ds:	int;
93 };
94 
95 Desc: adt
96 {
97 	id:	int;
98 	size:	int;
99 	np:	int;
100 	map:	array of byte;
101 	link:	cyclic ref Desc;
102 };
103 
104 Array: adt
105 {
106 	i:	int;
107 	size:	int;
108 };
109 
110 Link: adt
111 {
112 	desc:	int;
113 	addr:	int;
114 	typ:	int;
115 	name:	string;
116 	link:	cyclic ref Link;
117 };
118 
119 Keywd: adt
120 {
121 	name:	string;
122 	op:	int;
123 	terminal:	int;
124 };
125 
126 Ldts: adt
127 {
128 	n:	int;
129 	ldt:	list of ref Ldt;
130 };
131 
132 Ldt: adt
133 {
134 	sign:	int;
135 	name:	string;
136 };
137 
138 Exc: adt
139 {
140 	n1, n2, n3, n4, n5, n6: int;
141 	etab: list of ref Etab;
142 };
143 
144 Etab: adt
145 {
146 	n: int;
147 	name:	string;
148 };
149 
150 %}
151 
152 %module Asm {
153 	init:	fn(nil: ref Draw->Context, nil: list of string);
154 }
155 
156 %left	'|'
157 %left	'^'
158 %left	'&'
159 %left	'<' '>'
160 %left	'+' '-'
161 %left	'*' '/' '%'
162 
163 %type<inst>	label ilist inst
164 %type<ival>	con expr heapid
165 %type<addr>	addr raddr mem roff
166 %type<listv>	elist
167 %type<str>	ptrs
168 %token<op>	TOKI0 TOKI1 TOKI2 TOKI3
169 %token <ival>	TCONST
170 %token		TOKSB TOKFP TOKHEAP TOKDB TOKDW TOKDL TOKDF TOKDS TOKVAR
171 %token		TOKEXT TOKMOD TOKLINK TOKENTRY TOKARRAY TOKINDIR TOKAPOP TOKLDTS TOKEXCS TOKEXC TOKETAB TOKSRC
172 %token<sym>	TID
173 %token<fval>	TFCONST
174 %token<str>	TSTRING
175 
176 %%
177 prog	: ilist
178 	{
179 		assem($1);
180 	}
181 	;
182 
183 ilist	:
184 	{ $$ = nil; }
185 	| ilist label
186 	{
187 		if($2 != nil) {
188 			$2.link = $1;
189 			$$ = $2;
190 		}
191 		else
192 			$$ = $1;
193 	}
194 	;
195 
196 label	: TID ':' inst
197 	{
198 		$3.sym = $1;
199 		$$ = $3;
200 	}
201 	| TOKHEAP heapid ',' expr ptrs
202 	{
203 		heap(int $2, int $4, $5);
204 		$$ = nil;
205 	}
206 	| data
207 	{
208 		$$ = nil;
209 	}
210 	| inst
211 	;
212 
213 heapid	: '$' expr
214 	{
215 		$$ = $2;
216 	}
217 	| TID
218 	{
219 		$1.value = heapid++;
220 		$$ = big $1.value;
221 	}
222 	;
223 
224 ptrs	:
225 	{ $$ = nil; }
226 	| ',' TSTRING
227 	{
228 		$$ = $2;
229 	}
230 	;
231 
232 elist	: expr
233 	{
234 		$$ = newi($1, nil);
235 	}
236 	| elist ',' expr
237 	{
238 		$$ = newi($3, $1);
239 	}
240 	;
241 
242 inst	: TOKI3 addr ',' addr
243 	{
244 		$$ = ai($1);
245 		$$.src = $2;
246 		$$.dst = $4;
247 	}
248 	| TOKI3 addr ',' raddr ',' addr
249 	{
250 		$$ = ai($1);
251 		$$.src = $2;
252 		$$.reg = $4;
253 		$$.dst = $6;
254 	}
255 	| TOKI2 addr ',' addr
256 	{
257 		$$ = ai($1);
258 		$$.src = $2;
259 		$$.dst = $4;
260 	}
261 	| TOKI1 addr
262 	{
263 		$$ = ai($1);
264 		$$.dst = $2;
265 	}
266 	| TOKI0
267 	{
268 		$$ = ai($1);
269 	}
270 	;
271 
272 data	: TOKDB expr ',' elist
273 	{
274 		data(DEFB, $2, $4);
275 	}
276 	| TOKDW expr ',' elist
277 	{
278 		data(DEFW, $2, $4);
279 	}
280 	| TOKDL expr ',' elist
281 	{
282 		data(DEFL, $2, $4);
283 	}
284 	| TOKDF expr ',' TCONST
285 	{
286 		data(DEFF, $2, newb(dtocanon(real $4), nil));
287 	}
288 	| TOKDF expr ',' TFCONST
289 	{
290 		data(DEFF, $2, newb(dtocanon($4), nil));
291 	}
292 	| TOKDF expr ',' TID
293 	{
294 		case $4.name {
295 		"Inf" or "Infinity" =>
296 			b := array[] of {byte 16r7F, byte 16rF0, byte 0, byte 0, byte 0, byte 0, byte 0, byte 0};
297 			data(DEFF, $2, newb(b, nil));
298 		"NaN" =>
299 			b := array[] of {byte 16r7F, byte 16rFF, byte 16rFF, byte 16rFF, byte 16rFF, byte 16rFF, byte 16rFF, byte 16rFF};
300 			data(DEFF, $2, newb(b, nil));
301 		* =>
302 			diag(sys->sprint("bad value for real: %s", $4.name));
303 		}
304 	}
305 	| TOKDF expr ',' '-' TCONST
306 	{
307 		data(DEFF, $2, newb(dtocanon(-real $5), nil));
308 	}
309 	| TOKDF expr ',' '-' TFCONST
310 	{
311 		data(DEFF, $2, newb(dtocanon(-$5), nil));
312 	}
313 	| TOKDF expr ',' '-' TID
314 	{
315 		case $5.name {
316 		"Inf" or "Infinity" =>
317 			b := array[] of {byte 16rFF, byte 16rF0, byte 0, byte 0, byte 0, byte 0, byte 0, byte 0};
318 			data(DEFF, $2, newb(b, nil));
319 		* =>
320 			diag(sys->sprint("bad value for real: %s", $5.name));
321 		}
322 	}
323 	| TOKDS expr ',' TSTRING
324 	{
325 		data(DEFS, $2, news($4, nil));
326 	}
327 	| TOKVAR TID ',' expr
328 	{
329 		if($2.ds != 0)
330 			diag(sys->sprint("%s declared twice", $2.name));
331 		$2.ds = int $4;
332 		$2.value = dseg;
333 		dseg += int $4;
334 	}
335 	| TOKEXT expr ',' expr ',' TSTRING
336 	{
337 		ext(int $2, int $4, $6);
338 	}
339 	| TOKLINK expr ',' expr ',' expr ',' TSTRING
340 	{
341 		mklink(int $2, int $4, int $6, $8);
342 	}
343 	| TOKMOD TID
344 	{
345 		if(amodule != nil)
346 			diag(sys->sprint("this module already defined as %s", $2.name));
347 		else
348 			amodule = $2;
349 	}
350 	| TOKENTRY expr ',' expr
351 	{
352 		if(pcentry >= 0)
353 			diag(sys->sprint("this module already has entry point %d, %d" , pcentry, dentry));
354 		pcentry = int $2;
355 		dentry = int $4;
356 	}
357 	| TOKARRAY expr ',' heapid ',' expr
358 	{
359 		data(DEFA, $2, newa(int $4, int $6));
360 	}
361 	| TOKINDIR expr ',' expr
362 	{
363 		data(DIND, $2, newa(int $4, 0));
364 	}
365 	| TOKAPOP
366 	{
367 		data(DAPOP, big 0, newa(0, 0));
368 	}
369 	| TOKLDTS TID ',' expr
370 	{
371 		ldts(int $4);
372 	}
373 	| TOKEXCS expr
374 	{
375 		excs(int $2);
376 	}
377 	| TOKEXC expr ',' expr ',' expr ',' expr ',' expr ',' expr
378 	{
379 		exc(int $2, int $4, int $6, int $8, int $10, int $12);
380 	}
381 	| TOKETAB TSTRING ',' expr
382 	{
383 		etab($2, int $4);
384 	}
385 	| TOKETAB '*' ',' expr
386 	{
387 		etab(nil, int $4);
388 	}
389 	| TOKSRC TSTRING
390 	{
391 		source($2);
392 	}
393 	;
394 
395 raddr	: '$' expr
396 	{
397 		$$ = aa($2);
398 		$$.mode = AXIMM;
399 		if($$.val > 16r7FFF || $$.val < -16r8000)
400 			diag(sys->sprint("immediate %d too large for middle operand", $$.val));
401 	}
402 	| roff
403 	{
404 		if($1.mode == AMP)
405 			$1.mode = AXINM;
406 		else
407 			$1.mode = AXINF;
408 		if($1.mode == AXINM && isoff2big($1.val))
409 			diag(sys->sprint("register offset %d(mp) too large", $1.val));
410 		if($1.mode == AXINF && isoff2big($1.val))
411 			diag(sys->sprint("register offset %d(fp) too large", $1.val));
412 		$$ = $1;
413 	}
414 	;
415 
416 addr	: '$' expr
417 	{
418 		$$ = aa($2);
419 		$$.mode = AIMM;
420 	}
421 	| TID
422 	{
423 		$$ = aa(big 0);
424 		$$.sym = $1;
425 	}
426 	| mem
427 	;
428 
429 mem	: '*' roff
430 	{
431 		$2.mode |= AIND;
432 		$$ = $2;
433 	}
434 	| expr '(' roff ')'
435 	{
436 		$3.mode |= AIND;
437 		if($3.val & 3)
438 			diag("indirect offset must be word size");
439 		if($3.mode == (AMP|AIND) && (isoff2big($3.val) || isoff2big(int $1)))
440 			diag(sys->sprint("indirect offset %bd(%d(mp)) too large", $1, $3.val));
441 		if($3.mode == (AFP|AIND) && (isoff2big($3.val) || isoff2big(int $1)))
442 			diag(sys->sprint("indirect offset %bd(%d(fp)) too large", $1, $3.val));
443 		$3.off = $3.val;
444 		$3.val = int $1;
445 		$$ = $3;
446 	}
447 	| roff
448 	;
449 
450 roff	: expr '(' TOKSB ')'
451 	{
452 		$$ = aa($1);
453 		$$.mode = AMP;
454 	}
455 	| expr '(' TOKFP ')'
456 	{
457 		$$ = aa($1);
458 		$$.mode = AFP;
459 	}
460 	;
461 
462 con	: TCONST
463 	| TID
464 	{
465 		$$ = big $1.value;
466 	}
467 	| '-' con
468 	{
469 		$$ = -$2;
470 	}
471 	| '+' con
472 	{
473 		$$ = $2;
474 	}
475 	| '~' con
476 	{
477 		$$ = ~$2;
478 	}
479 	| '(' expr ')'
480 	{
481 		$$ = $2;
482 	}
483 	;
484 
485 expr:	con
486 	| expr '+' expr
487 	{
488 		$$ = $1 + $3;
489 	}
490 	| expr '-' expr
491 	{
492 		$$ = $1 - $3;
493 	}
494 	| expr '*' expr
495 	{
496 		$$ = $1 * $3;
497 	}
498 	| expr '/' expr
499 	{
500 		$$ = $1 / $3;
501 	}
502 	| expr '%' expr
503 	{
504 		$$ = $1 % $3;
505 	}
506 	| expr '<' '<' expr
507 	{
508 		$$ = $1 << int $4;
509 	}
510 	| expr '>' '>' expr
511 	{
512 		$$ = $1 >> int $4;
513 	}
514 	| expr '&' expr
515 	{
516 		$$ = $1 & $3;
517 	}
518 	| expr '^' expr
519 	{
520 		$$ = $1 ^ $3;
521 	}
522 	| expr '|' expr
523 	{
524 		$$ = $1 | $3;
525 	}
526 	;
527 %%
528 
529 kinit()
530 {
531 	for(i := 0; keywds[i].name != nil; i++) {
532 		s := enter(keywds[i].name, keywds[i].terminal);
533 		s.value = keywds[i].op;
534 	}
535 
536 	enter("desc", TOKHEAP);
537 	enter("mp", TOKSB);
538 	enter("fp", TOKFP);
539 
540 	enter("byte", TOKDB);
541 	enter("word", TOKDW);
542 	enter("long", TOKDL);
543 	enter("real", TOKDF);
544 	enter("string", TOKDS);
545 	enter("var", TOKVAR);
546 	enter("ext", TOKEXT);
547 	enter("module", TOKMOD);
548 	enter("link", TOKLINK);
549 	enter("entry", TOKENTRY);
550 	enter("array", TOKARRAY);
551 	enter("indir", TOKINDIR);
552 	enter("apop", TOKAPOP);
553 	enter("ldts", TOKLDTS);
554 	enter("exceptions", TOKEXCS);
555 	enter("exception", TOKEXC);
556 	enter("exctab", TOKETAB);
557 	enter("source", TOKSRC);
558 
559 	cmap['0'] = '\0'+1;
560 	cmap['z'] = '\0'+1;
561 	cmap['n'] = '\n'+1;
562 	cmap['r'] = '\r'+1;
563 	cmap['t'] = '\t'+1;
564 	cmap['b'] = '\b'+1;
565 	cmap['f'] = '\f'+1;
566 	cmap['a'] = '\a'+1;
567 	cmap['v'] = '\v'+1;
568 	cmap['\\'] = '\\'+1;
569 	cmap['"'] = '"'+1;
570 }
571 
572 Bgetc(b: ref Iobuf): int
573 {
574 	return b.getb();
575 }
576 
577 Bungetc(b: ref Iobuf)
578 {
579 	b.ungetb();
580 }
581 
582 Bgetrune(b: ref Iobuf): int
583 {
584 	return b.getc();
585 }
586 
587 Bputc(b: ref Iobuf, c: int)
588 {
589 	b.putb(byte c);
590 }
591 
592 strchr(s: string, c: int): string
593 {
594 	for(i := 0; i < len s; i++)
595 		if(s[i] == c)
596 			return s[i:];
597 	return nil;
598 }
599 
600 escchar(c: int): int
601 {
602 	buf := array[32] of byte;
603 	if(c >= '0' && c <= '9') {
604 		n := 1;
605 		buf[0] = byte c;
606 		for(;;) {
607 			c = Bgetc(bin);
608 			if(c == Eof)
609 				fatal(sys->sprint("%d: <eof> in escape sequence", line));
610 			if(strchr("0123456789xX", c) == nil) {
611 				Bungetc(bin);
612 				break;
613 			}
614 			buf[n++] = byte c;
615 		}
616 		return int string buf[0:n];
617 	}
618 
619 	n := cmap[c];
620 	if(n == 0)
621 		return c;
622 	return n-1;
623 }
624 
625 strbuf := array[Strsize] of byte;
626 
627 resizebuf()
628 {
629 	t := array[len strbuf+Strsize] of byte;
630 	t[0:] = strbuf;
631 	strbuf = t;
632 }
633 
634 YYLEX.eatstring(l: self ref YYLEX)
635 {
636 	esc := 0;
637 Scan:
638 	for(cnt := 0;;) {
639 		c := Bgetc(bin);
640 		case c {
641 		Eof =>
642 			fatal(sys->sprint("%d: <eof> in string constant", line));
643 
644 		'\n' =>
645 			line++;
646 			diag("newline in string constant");
647 			break Scan;
648 
649 		'\\' =>
650 			if(esc) {
651 				if(cnt >= len strbuf)
652 					resizebuf();
653 				strbuf[cnt++] = byte c;
654 				esc = 0;
655 				break;
656 			}
657 			esc = 1;
658 
659 		'"' =>
660 			if(esc == 0)
661 				break Scan;
662 			c = escchar(c);
663 			esc = 0;
664 			if(cnt >= len strbuf)
665 				resizebuf();
666 			strbuf[cnt++] = byte c;
667 
668 		* =>
669 			if(esc) {
670 				c = escchar(c);
671 				esc = 0;
672 			}
673 			if(cnt >= len strbuf)
674 				resizebuf();
675 			strbuf[cnt++] = byte c;
676 		}
677 	}
678 	l.lval.str = string strbuf[0: cnt];
679 }
680 
681 eatnl()
682 {
683 	line++;
684 	for(;;) {
685 		c := Bgetc(bin);
686 		if(c == Eof)
687 			diag("eof in comment");
688 		if(c == '\n')
689 			return;
690 	}
691 }
692 
693 YYLEX.lex(l: self ref YYLEX): int
694 {
695 	for(;;){
696 		c := Bgetc(bin);
697 		case c {
698 		Eof =>
699 			return Eof;
700 		'"' =>
701 			l.eatstring();
702 			return TSTRING;
703 		' ' or
704 		'\t' or
705 		'\r' =>
706 			continue;
707 		'\n' =>
708 			line++;
709 		'.' =>
710 			c = Bgetc(bin);
711 			Bungetc(bin);
712 			if(isdigit(c))
713 				return l.numsym('.');
714 			return '.';
715 		'#' =>
716 			eatnl();
717 		'(' or
718 		')' or
719 		';' or
720 		',' or
721 		'~' or
722 		'$' or
723 		'+' or
724 		'/' or
725 		'%' or
726 		'^' or
727 		'*' or
728 		'&' or
729 		'=' or
730 		'|' or
731 		'<' or
732 		'>' or
733 		'-' or
734 		':' =>
735 			return c;
736 		'\'' =>
737 			c = Bgetrune(bin);
738 			if(c == '\\')
739 				l.lval.ival = big escchar(Bgetc(bin));
740 			else
741 				l.lval.ival = big c;
742 			c = Bgetc(bin);
743 			if(c != '\'') {
744 				diag("missing '");
745 				Bungetc(bin);
746 			}
747 			return TCONST;
748 
749 		* =>
750 			return l.numsym(c);
751 		}
752 	}
753 }
754 
755 isdigit(c: int): int
756 {
757 	return c >= '0' && c <= '9';
758 }
759 
760 isxdigit(c: int): int
761 {
762 	return c >= '0' && c <= '9' || c >= 'a' && c <= 'f' || c >= 'A' && c <= 'F';
763 }
764 
765 isalnum(c: int): int
766 {
767 	return c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z' || isdigit(c);
768 }
769 
770 YYLEX.numsym(l: self ref YYLEX, first: int): int
771 {
772 	Int, Hex, Frac, Expsign, Exp: con iota;
773 	state: int;
774 
775 	symbol[0] = byte first;
776 	p := 0;
777 
778 	if(first == '.')
779 		state = Frac;
780 	else
781 		state = Int;
782 
783 	c: int;
784 	if(isdigit(int symbol[p++]) || state == Frac) {
785 	Collect:
786 		for(;;) {
787 			c = Bgetc(bin);
788 			if(c < 0)
789 				fatal(sys->sprint("%d: <eof> eating numeric", line));
790 
791 			case state {
792 			Int =>
793 				if(isdigit(c))
794 					break;
795 				case c {
796 				'x' or
797 				'X' =>
798 					c = 'x';
799 					state = Hex;
800 				'.' =>
801 					state = Frac;
802 				'e' or
803 				'E' =>
804 					c = 'e';
805 					state = Expsign;
806 				* =>
807 					break Collect;
808 				}
809 			Hex =>
810 				if(!isxdigit(c))
811 					break Collect;
812 			Frac =>
813 				if(isdigit(c))
814 					break;
815 				if(c != 'e' && c != 'E')
816 					break Collect;
817 				c = 'e';
818 				state = Expsign;
819 			Expsign =>
820 				state = Exp;
821 				if(c == '-' || c == '+')
822 					break;
823 				if(!isdigit(c))
824 					break Collect;
825 			Exp =>
826 				if(!isdigit(c))
827 					break Collect;
828 			}
829 			symbol[p++] = byte c;
830 		}
831 
832 		# break Collect
833 		lastsym = string symbol[0:p];
834 		Bungetc(bin);
835 		case state {
836 		Frac or
837 		Expsign or
838 		Exp =>
839 			l.lval.fval = real lastsym;
840 			return TFCONST;
841 		* =>
842 			if(len lastsym >= 3 && lastsym[0:2] == "0x")
843 				(l.lval.ival, nil) = str->tobig(lastsym[2:], 16);
844 			else
845 				(l.lval.ival, nil) = str->tobig(lastsym, 10);
846 			return TCONST;
847 		}
848 	}
849 
850 	for(;;) {
851 		c = Bgetc(bin);
852 		if(c < 0)
853 			fatal(sys->sprint("%d <eof> eating symbols", line));
854 		# '$' and '/' can occur in fully-qualified Java class names
855 		if(c != '_' && c != '.' && c != '/' && c != '$' && !isalnum(c)) {
856 			Bungetc(bin);
857 			break;
858 		}
859 		symbol[p++] = byte c;
860 	}
861 
862 	lastsym = string symbol[0:p];
863 	s := enter(lastsym,TID);
864 	case s.lexval {
865 	TOKI0 or
866 	TOKI1 or
867 	TOKI2 or
868 	TOKI3 =>
869 		l.lval.op = s.value;
870 	* =>
871 		l.lval.sym = s;
872 	}
873 	return s.lexval;
874 }
875 
876 hash := array[Hashsize] of list of ref Sym;
877 
878 enter(name: string, stype: int): ref Sym
879 {
880 	s := lookup(name);
881 	if(s != nil)
882 		return s;
883 
884 	h := 0;
885 	for(p := 0; p < len name; p++)
886 		h = h*3 + name[p];
887 	if(h < 0)
888 		h = ~h;
889 	h %= Hashsize;
890 
891 	s = ref Sym(name, stype, 0, 0);
892 	hash[h] = s :: hash[h];
893 	return s;
894 }
895 
896 lookup(name: string): ref Sym
897 {
898 	h := 0;
899 	for(p := 0; p < len name; p++)
900 		h = h*3 + name[p];
901 	if(h < 0)
902 		h = ~h;
903 	h %= Hashsize;
904 
905 	for(l := hash[h]; l != nil; l = tl l)
906 		if((s := hd l).name == name)
907 			return s;
908 	return nil;
909 }
910 
911 YYLEX.error(l: self ref YYLEX, s: string)
912 {
913 	if(s == "syntax error") {
914 		l.error(sys->sprint("syntax error, near symbol '%s'", lastsym));
915 		return;
916 	}
917 	sys->print("%s %d: %s\n", file, line, s);
918 	if(nerr++ > 10) {
919 		sys->fprint(sys->fildes(2), "%s:%d: too many errors, giving up\n", file, line);
920 		sys->remove(ofile);
921 		raise "fail: yyerror";
922 	}
923 }
924 
925 fatal(s: string)
926 {
927 	sys->fprint(sys->fildes(2), "asm: %d (fatal compiler problem) %s\n", line, s);
928 	raise "fail:"+s;
929 }
930 
931 diag(s: string)
932 {
933 	srcline := line;
934 	sys->fprint(sys->fildes(2), "%s:%d: %s\n", file, srcline, s);
935 	if(nerr++ > 10) {
936 		sys->fprint(sys->fildes(2), "%s:%d: too many errors, giving up\n", file, line);
937 		sys->remove(ofile);
938 		raise "fail: error";
939 	}
940 }
941 
942 zinst: Inst;
943 
944 ai(op: int): ref Inst
945 {
946 	i := ref zinst;
947 	i.op = op;
948 
949 	return i;
950 }
951 
952 aa(val: big): ref Addr
953 {
954 	if(val <= big -1073741824 && val > big 1073741823)
955 		diag("offset out of range");
956 	return ref Addr(0, 0, int val, nil);
957 }
958 
959 isoff2big(o: int): int
960 {
961 	return o < 0 || o > 16rFFFF;
962 }
963 
964 inldt := 0;
965 nldts := 0;
966 aldts: list of ref Ldts;
967 curl: ref Ldts;
968 nexcs := 0;
969 aexcs: list of ref Exc;
970 cure: ref Exc;
971 srcpath: string;
972 
973 bin: ref Iobuf;
974 bout: ref Iobuf;
975 
976 line := 0;
977 heapid := 0;
978 symbol := array[1024] of byte;
979 lastsym: string;
980 nerr := 0;
981 cmap := array[256] of int;
982 file: string;
983 
984 dlist: ref Desc;
985 dcout := 0;
986 dseg := 0;
987 dcount := 0;
988 
989 mdata: ref List;
990 amodule: ref Sym;
991 links: ref Link;
992 linkt: ref Link;
993 nlink := 0;
994 listing := 0;
995 mustcompile := 0;
996 dontcompile := 0;
997 ofile: string;
998 dentry := 0;
999 pcentry := 0;
1000 
1001 init(nil: ref Draw->Context, args: list of string)
1002 {
1003 	sys = load Sys Sys->PATH;
1004 	math = load Math Math->PATH;
1005 	bufio = load Bufio Bufio->PATH;
1006 	str = load String String->PATH;
1007 
1008 	arg := load Arg Arg->PATH;
1009 	arg->setusage("asm [-l] file.s");
1010 	arg->init(args);
1011 	while((c := arg->opt()) != 0){
1012 		case c {
1013 		'C' =>	dontcompile++;
1014 		'c' =>	mustcompile++;
1015 		'l' =>		listing++;
1016 		* =>		arg->usage();
1017 		}
1018 	}
1019 	args = arg->argv();
1020 	if(len args != 1)
1021 		arg->usage();
1022 	arg = nil;
1023 
1024 	kinit();
1025 	pcentry = -1;
1026 	dentry = -1;
1027 
1028 	file = hd args;
1029 	bin = bufio->open(file, Bufio->OREAD);
1030 	if(bin == nil) {
1031 		sys->fprint(sys->fildes(2), "asm: can't open %s: %r\n", file);
1032 		raise "fail: errors";
1033 	}
1034 	p := strrchr(file, '/');
1035 	if(p == nil)
1036 		p = file;
1037 	else
1038 		p = p[1:];
1039 	ofile = mkfile(p, ".s", ".dis");
1040 	bout = bufio->create(ofile, Bufio->OWRITE, 8r666);
1041 	if(bout == nil){
1042 		sys->fprint(sys->fildes(2), "asm: can't create: %s: %r\n", ofile);
1043 		raise "fail: errors";
1044 	}
1045 	line = 1;
1046 	yyparse(ref YYLEX);
1047 	bout.close();
1048 
1049 	if(nerr != 0){
1050 		sys->remove(ofile);
1051 		raise "fail: errors";
1052 	}
1053 }
1054 
1055 strrchr(s: string, c: int): string
1056 {
1057 	for(i := len s; --i >= 0;)
1058 		if(s[i] == c)
1059 			return s[i:];
1060 	return nil;
1061 }
1062 
1063 mkfile(file: string, oldext: string, ext: string): string
1064 {
1065 	n := len file;
1066 	n2 := len oldext;
1067 	if(n >= n2 && file[n-n2:] == oldext)
1068 		n -= n2;
1069 	return file[0:n] + ext;
1070 }
1071 
1072 opcode(i: ref Inst): int
1073 {
1074 	if(i.op < 0 || i.op >= len keywds)
1075 		fatal(sys->sprint("internal error: invalid op %d (%#x)", i.op, i.op));
1076 	return keywds[i.op].op;
1077 }
1078 
1079 Inst.text(i: self ref Inst): string
1080 {
1081 	if(i == nil)
1082 		return "IZ";
1083 
1084 	case keywds[i.op].terminal {
1085 	TOKI0 =>
1086 		return sys->sprint("%s", keywds[i.op].name);
1087 	TOKI1 =>
1088 		return sys->sprint("%s\t%s", keywds[i.op].name, i.dst.text());
1089 	TOKI3 =>
1090 		if(i.reg != nil) {
1091 			pre := "";
1092 			post := "";
1093 			case i.reg.mode {
1094 			AXIMM =>
1095 				pre = "$";
1096 				break;
1097 			AXINF =>
1098 				post = "(fp)";
1099 				break;
1100 			AXINM =>
1101 				post = "(mp)";
1102 			 	break;
1103 			}
1104 			return sys->sprint("%s\t%s, %s%d%s, %s", keywds[i.op].name, i.src.text(), pre, i.reg.val, post, i.dst.text());
1105 		}
1106 		return sys->sprint("%s\t%s, %s", keywds[i.op].name, i.src.text(), i.dst.text());
1107 	TOKI2 =>
1108 		return sys->sprint("%s\t%s, %s", keywds[i.op].name, i.src.text(), i.dst.text());
1109 	* =>
1110 		return "IGOK";
1111 	}
1112 }
1113 
1114 Addr.text(a: self ref Addr): string
1115 {
1116 	if(a == nil)
1117 		return "AZ";
1118 
1119 	if(a.mode & AIND) {
1120 		case a.mode & ~AIND {
1121 		AFP =>
1122 			return sys->sprint("%d(%d(fp))", a.val, a.off);
1123 		AMP =>
1124 			return sys->sprint("%d(%d(mp))", a.val, a.off);
1125 		}
1126 	}
1127 	else {
1128 		case a.mode {
1129 		AFP =>
1130 			return sys->sprint("%d(fp)", a.val);
1131 		AMP =>
1132 			return sys->sprint("%d(mp)", a.val);
1133 		AIMM =>
1134 			return sys->sprint("$%d", a.val);
1135 		}
1136 	}
1137 
1138 	return "AGOK";
1139 }
1140 
1141 append[T](l: list of T, v: T): list of T
1142 {
1143 	if(l == nil)
1144 		return v :: nil;
1145 	return hd l :: append(tl l, v);
1146 }
1147 
1148 newa(i: int, size: int): ref List
1149 {
1150 	a := ref Array(i, size);
1151 	l := ref List.Array(nil, -1, 0, a);
1152 	return l;
1153 }
1154 
1155 # does order matter?
1156 newi(v: big, l: ref List): ref List
1157 {
1158 	n := ref List.Int(nil, -1, 0, v);
1159 	if(l == nil)
1160 		return n;
1161 
1162 	for(t := l; t.link != nil; t = t.link)
1163 		;
1164 	t.link = n;
1165 
1166 	return l;
1167 }
1168 
1169 news(s: string, l: ref List): ref List
1170 {
1171 	return ref List.Bytes(l, -1, 0, array of byte s);
1172 }
1173 
1174 newb(a: array of byte, l: ref List): ref List
1175 {
1176 	return ref List.Bytes(l, -1, 0, a);
1177 }
1178 
1179 digit(x: int): int
1180 {
1181 	if(x >= 'A' && x <= 'F')
1182 		return x - 'A' + 10;
1183 	if(x >= 'a' && x <= 'f')
1184 		return x - 'a' + 10;
1185 	if(x >= '0' && x <= '9')
1186 		return x - '0';
1187 	diag("bad hex value in pointers");
1188 	return 0;
1189 }
1190 
1191 heap(id: int, size: int, ptr: string)
1192 {
1193 	d := ref Desc;
1194 	d.id = id;
1195 	d.size = size;
1196 	size /= IBY2WD;
1197 	d.map = array[size] of {* => byte 0};
1198 	d.np = 0;
1199 	if(dlist == nil)
1200 		dlist = d;
1201 	else {
1202 		f: ref Desc;
1203 		for(f = dlist; f.link != nil; f = f.link)
1204 			;
1205 		f.link = d;
1206 	}
1207 	d.link = nil;
1208 	dcount++;
1209 
1210 	if(ptr == nil)
1211 		return;
1212 	if(len ptr & 1) {
1213 		diag("pointer descriptor has odd length");
1214 		return;
1215 	}
1216 
1217 	k := 0;
1218 	l := len ptr;
1219 	for(i := 0; i < l; i += 2) {
1220 		d.map[k++] = byte ((digit(ptr[i])<<4)|digit(ptr[i+1]));
1221 		if(k > size) {
1222 			diag("pointer descriptor too long");
1223 			break;
1224 		}
1225 	}
1226 	d.np = k;
1227 }
1228 
1229 conout(val: int)
1230 {
1231 	if(val >= -64 && val <= 63) {
1232 		Bputc(bout, val & ~16r80);
1233 		return;
1234 	}
1235 	if(val >= -8192 && val <= 8191) {
1236 		Bputc(bout, ((val>>8) & ~16rC0) | 16r80);
1237 		Bputc(bout, val);
1238 		return;
1239 	}
1240 	if(val < 0 && ((val >> 29) & 7) != 7
1241 	|| val > 0 && (val >> 29) != 0)
1242 		diag(sys->sprint("overflow in constant 0x%ux\n", val));
1243 	Bputc(bout, (val>>24) | 16rC0);
1244 	Bputc(bout, val>>16);
1245 	Bputc(bout, val>>8);
1246 	Bputc(bout, val);
1247 }
1248 
1249 aout(a: ref Addr)
1250 {
1251 	if(a == nil)
1252 		return;
1253 	if(a.mode & AIND)
1254 		conout(a.off);
1255 	conout(a.val);
1256 }
1257 
1258 Bputs(b: ref Iobuf, s: string)
1259 {
1260 	for(i := 0; i < len s; i++)
1261 		Bputc(b, s[i]);
1262 	Bputc(b, '\0');
1263 }
1264 
1265 lout()
1266 {
1267 	if(amodule == nil)
1268 		amodule = enter("main", 0);
1269 
1270 	Bputs(bout, amodule.name);
1271 
1272 	for(l := links; l != nil; l = l.link) {
1273 		conout(l.addr);
1274 		conout(l.desc);
1275 		Bputc(bout, l.typ>>24);
1276 		Bputc(bout, l.typ>>16);
1277 		Bputc(bout, l.typ>>8);
1278 		Bputc(bout, l.typ);
1279 		Bputs(bout, l.name);
1280 	}
1281 }
1282 
1283 ldtout()
1284 {
1285 	conout(nldts);
1286 	for(la := aldts; la != nil; la = tl la){
1287 		ls := hd la;
1288 		conout(ls.n);
1289 		for(l := ls.ldt; l != nil; l = tl l){
1290 			t := hd l;
1291 			Bputc(bout, t.sign>>24);
1292 			Bputc(bout, t.sign>>16);
1293 			Bputc(bout, t.sign>>8);
1294 			Bputc(bout, t.sign);
1295 			Bputs(bout, t.name);
1296 		}
1297 	}
1298 	conout(0);
1299 }
1300 
1301 excout()
1302 {
1303 	if(nexcs == 0)
1304 		return;
1305 	conout(nexcs);
1306 	for(es := aexcs; es != nil; es = tl es){
1307 		e := hd es;
1308 		conout(e.n3);
1309 		conout(e.n1);
1310 		conout(e.n2);
1311 		conout(e.n4);
1312 		conout(e.n5|(e.n6<<16));
1313 		for(ets := e.etab; ets != nil; ets = tl ets){
1314 			et := hd ets;
1315 			if(et.name != nil)
1316 				Bputs(bout, et.name);
1317 			conout(et.n);
1318 		}
1319 	}
1320 	conout(0);
1321 }
1322 
1323 srcout()
1324 {
1325 	if(srcpath == nil)
1326 		return;
1327 	Bputs(bout, srcpath);
1328 }
1329 
1330 assem(i: ref Inst)
1331 {
1332 	f: ref Inst;
1333 	while(i != nil){
1334 		link := i.link;
1335 		i.link = f;
1336 		f = i;
1337 		i = link;
1338 	}
1339 	i = f;
1340 
1341 	pc := 0;
1342 	for(f = i; f != nil; f = f.link) {
1343 		f.pc = pc++;
1344 		if(f.sym != nil)
1345 			f.sym.value = f.pc;
1346 	}
1347 
1348 	if(pcentry >= pc)
1349 		diag("entry pc out of range");
1350 	if(dentry >= dcount)
1351 		diag("entry descriptor out of range");
1352 
1353 	conout(XMAGIC);
1354 	hints := 0;
1355 	if(mustcompile)
1356 		hints |= MUSTCOMPILE;
1357 	if(dontcompile)
1358 		hints |= DONTCOMPILE;
1359 	hints |= HASLDT;
1360 	if(nexcs > 0)
1361 		hints |= HASEXCEPT;
1362 	conout(hints);		# Runtime flags
1363 	conout(1024);		# default stack size
1364 	conout(pc);
1365 	conout(dseg);
1366 	conout(dcount);
1367 	conout(nlink);
1368 	conout(pcentry);
1369 	conout(dentry);
1370 
1371 	for(f = i; f != nil; f = f.link) {
1372 		if(f.dst != nil && f.dst.sym != nil) {
1373 			f.dst.mode = AIMM;
1374 			f.dst.val = f.dst.sym.value;
1375 		}
1376 		o := opcode(f);
1377 		if(o == IRAISE){
1378 			f.src = f.dst;
1379 			f.dst = nil;
1380 		}
1381 		Bputc(bout, o);
1382 		n := 0;
1383 		if(f.src != nil)
1384 			n |= src(f.src.mode);
1385 		else
1386 			n |= src(AXXX);
1387 		if(f.dst != nil)
1388 			n |= dst(f.dst.mode);
1389 		else
1390 			n |= dst(AXXX);
1391 		if(f.reg != nil)
1392 			n |= f.reg.mode;
1393 		else
1394 			n |= AXNON;
1395 		Bputc(bout, n);
1396 		aout(f.reg);
1397 		aout(f.src);
1398 		aout(f.dst);
1399 
1400 		if(listing)
1401 			sys->print("%4d %s\n", f.pc, f.text());
1402 	}
1403 
1404 	for(d := dlist; d != nil; d = d.link) {
1405 		conout(d.id);
1406 		conout(d.size);
1407 		conout(d.np);
1408 		for(n := 0; n < d.np; n++)
1409 			Bputc(bout, int d.map[n]);
1410 	}
1411 
1412 	dout();
1413 	lout();
1414 	ldtout();
1415 	excout();
1416 	srcout();
1417 }
1418 
1419 data(typ: int, addr: big, l: ref List)
1420 {
1421 	if(inldt){
1422 		ldtw(int intof(l));
1423 		return;
1424 	}
1425 
1426 	l.typ = typ;
1427 	l.addr = int addr;
1428 
1429 	if(mdata == nil)
1430 		mdata = l;
1431 	else {
1432 		for(f := mdata; f.link != nil; f = f.link)
1433 			;
1434 		f.link = l;
1435 	}
1436 }
1437 
1438 ext(addr: int, typ: int, s: string)
1439 {
1440 	if(inldt){
1441 		ldte(typ, s);
1442 		return;
1443 	}
1444 
1445 	data(DEFW, big addr, newi(big typ, nil));
1446 
1447 	n: ref List;
1448 	for(i := 0; i < len s; i++)
1449 		n = newi(big s[i], n);
1450 	data(DEFB, big(addr+IBY2WD), n);
1451 
1452 	if(addr+len s > dseg)
1453 		diag("ext beyond mp");
1454 }
1455 
1456 mklink(desc: int, addr: int, typ: int, s: string)
1457 {
1458 	for(ls := links; ls != nil; ls = ls.link)
1459 		if(ls.name == s)
1460 			diag(sys->sprint("%s already defined", s));
1461 
1462 	nlink++;
1463 	l := ref Link;
1464 	l.desc = desc;
1465 	l.addr = addr;
1466 	l.typ = typ;
1467 	l.name = s;
1468 	l.link = nil;
1469 
1470 	if(links == nil)
1471 		links = l;
1472 	else
1473 		linkt.link = l;
1474 	linkt = l;
1475 }
1476 
1477 intof(l: ref List): big
1478 {
1479 	pick rl := l {
1480 	Int =>
1481 		return rl.ival;
1482 	* =>
1483 		raise "list botch";
1484 	}
1485 }
1486 
1487 arrayof(l: ref List): ref Array
1488 {
1489 	pick rl := l {
1490 	Array =>
1491 		return rl.a;
1492 	* =>
1493 		raise "list botch";
1494 	}
1495 }
1496 
1497 bytesof(l: ref List): array of byte
1498 {
1499 	pick rl := l {
1500 	Bytes =>
1501 		return rl.b;
1502 	* =>
1503 		raise "list botch";
1504 	}
1505 }
1506 
1507 nel(l: ref List): (int, ref List)
1508 {
1509 	n := 1;
1510 	for(e := l.link; e != nil && e.addr == -1; e = e.link)
1511 		n++;
1512 	return (n, e);
1513 }
1514 
1515 dout()
1516 {
1517 	e: ref List;
1518 	n: int;
1519 	for(l := mdata; l != nil; l = e) {
1520 		case l.typ {
1521 		DEFB =>
1522 			(n, e) = nel(l);
1523 			if(n < DMAX)
1524 				Bputc(bout, dbyte(DEFB, n));
1525 			else {
1526 				Bputc(bout, dbyte(DEFB, 0));
1527 				conout(n);
1528 			}
1529 			conout(l.addr);
1530 			while(l != e) {
1531 				Bputc(bout, int intof(l));
1532 				l = l.link;
1533 			}
1534 			break;
1535 		DEFW =>
1536 			(n, e) = nel(l);
1537 			if(n < DMAX)
1538 				Bputc(bout, dbyte(DEFW, n));
1539 			else {
1540 				Bputc(bout, dbyte(DEFW, 0));
1541 				conout(n);
1542 			}
1543 			conout(l.addr);
1544 			while(l != e) {
1545 				n = int intof(l);
1546 				Bputc(bout, n>>24);
1547 				Bputc(bout, n>>16);
1548 				Bputc(bout, n>>8);
1549 				Bputc(bout, n);
1550 				l = l.link;
1551 			}
1552 			break;
1553 		DEFL =>
1554 			(n, e) = nel(l);
1555 			if(n < DMAX)
1556 				Bputc(bout, dbyte(DEFL, n));
1557 			else {
1558 				Bputc(bout, dbyte(DEFL, 0));
1559 				conout(n);
1560 			}
1561 			conout(l.addr);
1562 			while(l != e) {
1563 				b := intof(l);
1564 				Bputc(bout, int (b>>56));
1565 				Bputc(bout, int (b>>48));
1566 				Bputc(bout, int (b>>40));
1567 				Bputc(bout, int (b>>32));
1568 				Bputc(bout, int (b>>24));
1569 				Bputc(bout, int (b>>16));
1570 				Bputc(bout, int (b>>8));
1571 				Bputc(bout, int b);
1572 				l = l.link;
1573 			}
1574 			break;
1575 		DEFF =>
1576 			(n, e) = nel(l);
1577 			if(n < DMAX)
1578 				Bputc(bout, dbyte(DEFF, n));
1579 			else {
1580 				Bputc(bout, dbyte(DEFF, 0));
1581 				conout(n);
1582 			}
1583 			conout(l.addr);
1584 			while(l != e) {
1585 				b := bytesof(l);
1586 				Bputc(bout, int b[0]);
1587 				Bputc(bout, int b[1]);
1588 				Bputc(bout, int b[2]);
1589 				Bputc(bout, int b[3]);
1590 				Bputc(bout, int b[4]);
1591 				Bputc(bout, int b[5]);
1592 				Bputc(bout, int b[6]);
1593 				Bputc(bout, int b[7]);
1594 				l = l.link;
1595 			}
1596 			break;
1597 		DEFS =>
1598 			a := bytesof(l);
1599 			n = len a;
1600 			if(n < DMAX && n != 0)
1601 				Bputc(bout, dbyte(DEFS, n));
1602 			else {
1603 				Bputc(bout, dbyte(DEFS, 0));
1604 				conout(n);
1605 			}
1606 			conout(l.addr);
1607 			for(i := 0; i < n; i++)
1608 				Bputc(bout, int a[i]);
1609 
1610 			e = l.link;
1611 			break;
1612 		DEFA =>
1613 			Bputc(bout, dbyte(DEFA, 1));
1614 			conout(l.addr);
1615 			ar := arrayof(l);
1616 			Bputc(bout, ar.i>>24);
1617 			Bputc(bout, ar.i>>16);
1618 			Bputc(bout, ar.i>>8);
1619 			Bputc(bout, ar.i);
1620 			Bputc(bout, ar.size>>24);
1621 			Bputc(bout, ar.size>>16);
1622 			Bputc(bout, ar.size>>8);
1623 			Bputc(bout, ar.size);
1624 			e = l.link;
1625 			break;
1626 		DIND =>
1627 			Bputc(bout, dbyte(DIND, 1));
1628 			conout(l.addr);
1629 			Bputc(bout, 0);
1630 			Bputc(bout, 0);
1631 			Bputc(bout, 0);
1632 			Bputc(bout, 0);
1633 			e = l.link;
1634 			break;
1635 		DAPOP =>
1636 			Bputc(bout, dbyte(DAPOP, 1));
1637 			conout(0);
1638 			e = l.link;
1639 			break;
1640 		}
1641 	}
1642 
1643 	Bputc(bout, dbyte(DEFZ, 0));
1644 }
1645 
1646 ldts(n: int)
1647 {
1648 	nldts = n;
1649 	inldt = 1;
1650 }
1651 
1652 ldtw(n: int)
1653 {
1654 	ls := ref Ldts(n, nil);
1655 	aldts = append(aldts, ls);
1656 	curl = ls;
1657 }
1658 
1659 ldte(n: int, s: string)
1660 {
1661 	l := ref Ldt(n, s);
1662 	curl.ldt = append(curl.ldt, l);
1663 }
1664 
1665 excs(n: int)
1666 {
1667 	nexcs = n;
1668 }
1669 
1670 exc(n1: int, n2: int, n3: int, n4: int, n5: int, n6: int)
1671 {
1672 	e := ref Exc;
1673 	e.n1 = n1;
1674 	e.n2 = n2;
1675 	e.n3 = n3;
1676 	e.n4 = n4;
1677 	e.n5 = n5;
1678 	e.n6 = n6;
1679 	e.etab = nil;
1680 	aexcs = append(aexcs, e);
1681 	cure = e;
1682 }
1683 
1684 etab(s: string, n: int)
1685 {
1686 	et := ref Etab;
1687 	et.n = n;
1688 	et.name = s;
1689 	cure.etab = append(cure.etab, et);
1690 }
1691 
1692 source(s: string)
1693 {
1694 	srcpath = s;
1695 }
1696 
1697 dtype(x: int): int
1698 {
1699 	return (x>>4)&16rF;
1700 }
1701 
1702 dbyte(x: int, l: int): int
1703 {
1704 	return (x<<4) | l;
1705 }
1706 
1707 dlen(x: int): int
1708 {
1709 	return x & (DMAX-1);
1710 }
1711 
1712 src(x: int): int
1713 {
1714 	return x<<3;
1715 }
1716 
1717 dst(x: int): int
1718 {
1719 	return x<<0;
1720 }
1721 
1722 dtocanon(d: real): array of byte
1723 {
1724 	b := array[8] of byte;
1725 	export_real(b, array[] of {d});
1726 	return b;
1727 }
1728 
1729 keywds: array of Keywd = array[] of
1730 {
1731 	("nop",		INOP,		TOKI0),
1732 	("alt",		IALT,		TOKI3),
1733 	("nbalt",	INBALT,		TOKI3),
1734 	("goto",		IGOTO,		TOKI2),
1735 	("call",		ICALL,		TOKI2),
1736 	("frame",	IFRAME,		TOKI2),
1737 	("spawn",	ISPAWN,		TOKI2),
1738 	("runt",		IRUNT,		TOKI2),
1739 	("load",		ILOAD,		TOKI3),
1740 	("mcall",	IMCALL,		TOKI3),
1741 	("mspawn",	IMSPAWN,	TOKI3),
1742 	("mframe",	IMFRAME,	TOKI3),
1743 	("ret",		IRET,		TOKI0),
1744 	("jmp",		IJMP,		TOKI1),
1745 	("case",		ICASE,		TOKI2),
1746 	("exit",		IEXIT,		TOKI0),
1747 	("new",		INEW,		TOKI2),
1748 	("newa",		INEWA,		TOKI3),
1749 	("newcb",	INEWCB,		TOKI1),
1750 	("newcw",	INEWCW,		TOKI1),
1751 	("newcf",	INEWCF,		TOKI1),
1752 	("newcp",	INEWCP,		TOKI1),
1753 	("newcm",	INEWCM,		TOKI2),
1754 	("newcmp",	INEWCMP,	TOKI2),
1755 	("send",		ISEND,		TOKI2),
1756 	("recv",		IRECV,		TOKI2),
1757 	("consb",	ICONSB,		TOKI2),
1758 	("consw",	ICONSW,		TOKI2),
1759 	("consp",	ICONSP,		TOKI2),
1760 	("consf",	ICONSF,		TOKI2),
1761 	("consm",	ICONSM,		TOKI3),
1762 	("consmp",	ICONSMP,	TOKI3),
1763 	("headb",	IHEADB,		TOKI2),
1764 	("headw",	IHEADW,		TOKI2),
1765 	("headp",	IHEADP,		TOKI2),
1766 	("headf",	IHEADF,		TOKI2),
1767 	("headm",	IHEADM,		TOKI3),
1768 	("headmp",	IHEADMP,	TOKI3),
1769 	("tail",		ITAIL,		TOKI2),
1770 	("lea",		ILEA,		TOKI2),
1771 	("indx",		IINDX,		TOKI3),
1772 	("movp",		IMOVP,		TOKI2),
1773 	("movm",		IMOVM,		TOKI3),
1774 	("movmp",	IMOVMP,		TOKI3),
1775 	("movb",		IMOVB,		TOKI2),
1776 	("movw",		IMOVW,		TOKI2),
1777 	("movf",		IMOVF,		TOKI2),
1778 	("cvtbw",	ICVTBW,		TOKI2),
1779 	("cvtwb",	ICVTWB,		TOKI2),
1780 	("cvtfw",	ICVTFW,		TOKI2),
1781 	("cvtwf",	ICVTWF,		TOKI2),
1782 	("cvtca",	ICVTCA,		TOKI2),
1783 	("cvtac",	ICVTAC,		TOKI2),
1784 	("cvtwc",	ICVTWC,		TOKI2),
1785 	("cvtcw",	ICVTCW,		TOKI2),
1786 	("cvtfc",	ICVTFC,		TOKI2),
1787 	("cvtcf",	ICVTCF,		TOKI2),
1788 	("addb",		IADDB,		TOKI3),
1789 	("addw",		IADDW,		TOKI3),
1790 	("addf",		IADDF,		TOKI3),
1791 	("subb",		ISUBB,		TOKI3),
1792 	("subw",		ISUBW,		TOKI3),
1793 	("subf",		ISUBF,		TOKI3),
1794 	("mulb",		IMULB,		TOKI3),
1795 	("mulw",		IMULW,		TOKI3),
1796 	("mulf",		IMULF,		TOKI3),
1797 	("divb",		IDIVB,		TOKI3),
1798 	("divw",		IDIVW,		TOKI3),
1799 	("divf",		IDIVF,		TOKI3),
1800 	("modw",		IMODW,		TOKI3),
1801 	("modb",		IMODB,		TOKI3),
1802 	("andb",		IANDB,		TOKI3),
1803 	("andw",		IANDW,		TOKI3),
1804 	("orb",		IORB,		TOKI3),
1805 	("orw",		IORW,		TOKI3),
1806 	("xorb",		IXORB,		TOKI3),
1807 	("xorw",		IXORW,		TOKI3),
1808 	("shlb",		ISHLB,		TOKI3),
1809 	("shlw",		ISHLW,		TOKI3),
1810 	("shrb",		ISHRB,		TOKI3),
1811 	("shrw",		ISHRW,		TOKI3),
1812 	("insc",		IINSC,		TOKI3),
1813 	("indc",		IINDC,		TOKI3),
1814 	("addc",		IADDC,		TOKI3),
1815 	("lenc",		ILENC,		TOKI2),
1816 	("lena",		ILENA,		TOKI2),
1817 	("lenl",		ILENL,		TOKI2),
1818 	("beqb",		IBEQB,		TOKI3),
1819 	("bneb",		IBNEB,		TOKI3),
1820 	("bltb",		IBLTB,		TOKI3),
1821 	("bleb",		IBLEB,		TOKI3),
1822 	("bgtb",		IBGTB,		TOKI3),
1823 	("bgeb",		IBGEB,		TOKI3),
1824 	("beqw",		IBEQW,		TOKI3),
1825 	("bnew",		IBNEW,		TOKI3),
1826 	("bltw",		IBLTW,		TOKI3),
1827 	("blew",		IBLEW,		TOKI3),
1828 	("bgtw",		IBGTW,		TOKI3),
1829 	("bgew",		IBGEW,		TOKI3),
1830 	("beqf",		IBEQF,		TOKI3),
1831 	("bnef",		IBNEF,		TOKI3),
1832 	("bltf",		IBLTF,		TOKI3),
1833 	("blef",		IBLEF,		TOKI3),
1834 	("bgtf",		IBGTF,		TOKI3),
1835 	("bgef",		IBGEF,		TOKI3),
1836 	("beqc",		IBEQC,		TOKI3),
1837 	("bnec",		IBNEC,		TOKI3),
1838 	("bltc",		IBLTC,		TOKI3),
1839 	("blec",		IBLEC,		TOKI3),
1840 	("bgtc",		IBGTC,		TOKI3),
1841 	("bgec",		IBGEC,		TOKI3),
1842 	("slicea",	ISLICEA,	TOKI3),
1843 	("slicela",	ISLICELA,	TOKI3),
1844 	("slicec",	ISLICEC,	TOKI3),
1845 	("indw",		IINDW,		TOKI3),
1846 	("indf",		IINDF,		TOKI3),
1847 	("indb",		IINDB,		TOKI3),
1848 	("negf",		INEGF,		TOKI2),
1849 	("movl",		IMOVL,		TOKI2),
1850 	("addl",		IADDL,		TOKI3),
1851 	("subl",		ISUBL,		TOKI3),
1852 	("divl",		IDIVL,		TOKI3),
1853 	("modl",		IMODL,		TOKI3),
1854 	("mull",		IMULL,		TOKI3),
1855 	("andl",		IANDL,		TOKI3),
1856 	("orl",		IORL,		TOKI3),
1857 	("xorl",		IXORL,		TOKI3),
1858 	("shll",		ISHLL,		TOKI3),
1859 	("shrl",		ISHRL,		TOKI3),
1860 	("bnel",		IBNEL,		TOKI3),
1861 	("bltl",		IBLTL,		TOKI3),
1862 	("blel",		IBLEL,		TOKI3),
1863 	("bgtl",		IBGTL,		TOKI3),
1864 	("bgel",		IBGEL,		TOKI3),
1865 	("beql",		IBEQL,		TOKI3),
1866 	("cvtlf",	ICVTLF,		TOKI2),
1867 	("cvtfl",	ICVTFL,		TOKI2),
1868 	("cvtlw",	ICVTLW,		TOKI2),
1869 	("cvtwl",	ICVTWL,		TOKI2),
1870 	("cvtlc",	ICVTLC,		TOKI2),
1871 	("cvtcl",	ICVTCL,		TOKI2),
1872 	("headl",	IHEADL,		TOKI2),
1873 	("consl",	ICONSL,		TOKI2),
1874 	("newcl",	INEWCL,		TOKI1),
1875 	("casec",	ICASEC,		TOKI2),
1876 	("indl",		IINDL,		TOKI3),
1877 	("movpc",	IMOVPC,		TOKI2),
1878 	("tcmp",		ITCMP,		TOKI2),
1879 	("mnewz",	IMNEWZ,		TOKI3),
1880 	("cvtrf",	ICVTRF,		TOKI2),
1881 	("cvtfr",	ICVTFR,		TOKI2),
1882 	("cvtws",	ICVTWS,		TOKI2),
1883 	("cvtsw",	ICVTSW,		TOKI2),
1884 	("lsrw",		ILSRW,		TOKI3),
1885 	("lsrl",		ILSRL,		TOKI3),
1886 	("eclr",		IECLR,		TOKI0),
1887 	("newz",		INEWZ,		TOKI2),
1888 	("newaz",	INEWAZ,		TOKI3),
1889 	("raise",	IRAISE,	TOKI1),
1890 	("casel",	ICASEL,	TOKI2),
1891 	("mulx",	IMULX,	TOKI3),
1892 	("divx",	IDIVX,	TOKI3),
1893 	("cvtxx",	ICVTXX,	TOKI3),
1894 	("mulx0",	IMULX0,	TOKI3),
1895 	("divx0",	IDIVX0,	TOKI3),
1896 	("cvtxx0",	ICVTXX0,	TOKI3),
1897 	("mulx1",	IMULX1,	TOKI3),
1898 	("divx1",	IDIVX1,	TOKI3),
1899 	("cvtxx1",	ICVTXX1,	TOKI3),
1900 	("cvtfx",	ICVTFX,	TOKI3),
1901 	("cvtxf",	ICVTXF,	TOKI3),
1902 	("expw",	IEXPW,	TOKI3),
1903 	("expl",	IEXPL,	TOKI3),
1904 	("expf",	IEXPF,	TOKI3),
1905 	("self",	ISELF,	TOKI1),
1906 	(nil,	0, 0),
1907 };
1908