xref: /csrg-svn/old/as.vax/asexpr.c (revision 12944)
15823Srrh /*
25823Srrh  *	Copyright (c) 1982 Regents of the University of California
35823Srrh  */
45823Srrh #ifndef lint
5*12944Srrh static char sccsid[] = "@(#)asexpr.c 4.4 06/09/83";
65823Srrh 
75823Srrh #endif not lint
8593Sbill #include <stdio.h>
9593Sbill #include "as.h"
105823Srrh #include "asscan.h"
11593Sbill #include "asexpr.h"
12593Sbill 
13593Sbill /*
14593Sbill  * Tables for combination of operands.
15593Sbill  */
16593Sbill #define	XTXRN	5<<1		/* indexes last row/column when right shifted */
17593Sbill 
18593Sbill /*
19593Sbill  *	table for +
20593Sbill  */
21593Sbill readonly char pltab[6][6] = {
22593Sbill /*		UND	ABS	TXT	DAT	BSS	EXT */
23593Sbill 
24593Sbill /*UND*/		XUNDEF,	XUNDEF,	XUNDEF,	XUNDEF,	XUNDEF,	XUNDEF,
25593Sbill /*ABS*/		XUNDEF,	XABS,	XTEXT,	XDATA,	XBSS,	XXTRN,
26593Sbill /*TXT*/		XUNDEF,	XTEXT,	ERR,	ERR,	ERR,	ERR,
27593Sbill /*DAT*/		XUNDEF,	XDATA,	ERR,	ERR,	ERR,	ERR,
28593Sbill /*BSS*/		XUNDEF,	XBSS,	ERR,	ERR,	ERR,	ERR,
29593Sbill /*EXT*/		XUNDEF,	XXTRN,	ERR,	ERR,	ERR,	ERR,
30593Sbill };
31593Sbill 
32593Sbill /*
33593Sbill  *	table for -
34593Sbill  */
35593Sbill readonly char mintab[6][6] = {
36593Sbill /*		UND	ABS	TXT	DAT	BSS	EXT */
37593Sbill 
38593Sbill /*UND*/		XUNDEF,	XUNDEF,	XUNDEF,	XUNDEF,	XUNDEF,	XUNDEF,
39593Sbill /*ABS*/		XUNDEF,	XABS,	ERR,	ERR,	ERR,	ERR,
40593Sbill /*TXT*/		XUNDEF,	XTEXT,	XABS,	ERR,	ERR,	ERR,
41593Sbill /*DAT*/		XUNDEF,	XDATA,	ERR,	XABS,	ERR,	ERR,
42593Sbill /*BSS*/		XUNDEF,	XBSS,	ERR,	ERR,	XABS,	ERR,
43593Sbill /*EXT*/		XUNDEF,	XXTRN,	ERR,	ERR,	ERR,	ERR,
44593Sbill };
45593Sbill 
46593Sbill /*
47593Sbill  *	table for other operators
48593Sbill  */
49593Sbill readonly char othtab[6][6] = {
50593Sbill /*		UND	ABS	TXT	DAT	BSS	EXT */
51593Sbill 
52593Sbill /*UND*/		XUNDEF,	XUNDEF,	XUNDEF,	XUNDEF,	XUNDEF,	XUNDEF,
53593Sbill /*ABS*/		XUNDEF,	XABS,	ERR,	ERR,	ERR,	ERR,
54593Sbill /*TXT*/		XUNDEF,	ERR,	ERR,	ERR,	ERR,	ERR,
55593Sbill /*DAT*/		XUNDEF,	ERR,	ERR,	ERR,	ERR,	ERR,
56593Sbill /*BSS*/		XUNDEF,	ERR,	ERR,	ERR,	ERR,	ERR,
57593Sbill /*EXT*/		XUNDEF,	ERR,	ERR,	ERR,	ERR,	ERR,
58593Sbill };
59593Sbill 
605823Srrh struct exp *combine(op, exp1, exp2)
615823Srrh 	reg struct exp *exp1, *exp2;
62593Sbill {
635823Srrh 	reg 	e1_type, e2_type;
645823Srrh 	reg	back_type;
655823Srrh 	char	*btype = "The assembler can only do arithmetic on 1,2, or 4 byte integers";
66593Sbill 
67593Sbill 	lastnam=0; 			/* kludge for jxxx instructions */
68593Sbill 
69630Shenry 	e1_type = exp1->e_xtype&XTYPE;
70630Shenry 	e2_type = exp2->e_xtype&XTYPE;
71593Sbill 
72630Shenry 	if (exp1->e_xtype==XXTRN+XUNDEF)
73593Sbill 		e1_type = XTXRN;
74630Shenry 	if (exp2->e_xtype==XXTRN+XUNDEF)
75593Sbill 		e2_type = XTXRN;
76593Sbill 	if (passno==1)
77630Shenry 		if (exp1->e_xloc!=exp2->e_xloc && e1_type==e2_type)
78593Sbill 			e1_type = e2_type = XTXRN;	/* error on != loc ctrs */
79593Sbill 	e1_type >>= 1;		/*dispose of the external (XXTRN) bit*/
80593Sbill 	e2_type >>= 1;
81593Sbill 
825823Srrh 	switch(exp1->e_number.num_tag){
835823Srrh 	case TYPB:
845823Srrh 	case TYPW:
855823Srrh 	case TYPL:
865823Srrh 		break;
875823Srrh 	default:
885823Srrh 		yyerror(btype);
895823Srrh 		return(exp1);
905823Srrh 	}
915823Srrh 	switch(exp2->e_number.num_tag){
925823Srrh 	case TYPB:
935823Srrh 	case TYPW:
945823Srrh 	case TYPL:
955823Srrh 		break;
965823Srrh 	default:
975823Srrh 		yyerror(btype);
985823Srrh 		return(exp1);
995823Srrh 	}
1005823Srrh 	switch (op){
101593Sbill 	case PLUS:
102630Shenry 		exp1->e_xvalue += exp2->e_xvalue;
103630Shenry 		back_type = pltab[e1_type][e2_type];
104593Sbill 		break;
105593Sbill 	case MINUS:
106630Shenry 		exp1->e_xvalue -= exp2->e_xvalue;
107630Shenry 		back_type = mintab[e1_type][e2_type];
108593Sbill 		break;
109593Sbill 	case IOR:
110630Shenry 		exp1->e_xvalue |= exp2->e_xvalue;
111593Sbill 		goto comm;
112593Sbill 	case XOR:
113630Shenry 		exp1->e_xvalue ^= exp2->e_xvalue;
114593Sbill 		goto comm;
115593Sbill 	case AND:
116630Shenry 		exp1->e_xvalue &= exp2->e_xvalue;
117593Sbill 		goto comm;
118593Sbill 	case ORNOT:
119630Shenry 		exp1->e_xvalue |= ~exp2->e_xvalue;
120593Sbill 		goto comm;
121593Sbill 	case LSH:
122630Shenry 		exp1->e_xvalue <<= exp2->e_xvalue;
123593Sbill 		goto comm;
124593Sbill 	case RSH:
125630Shenry 		exp1->e_xvalue >>= exp2->e_xvalue;
126593Sbill 		goto comm;
127593Sbill 	case TILDE:
128630Shenry 		exp1->e_xvalue |= ~ exp2->e_xvalue;
129593Sbill 		goto comm;
130593Sbill 	case MUL:
131630Shenry 		exp1->e_xvalue *= exp2->e_xvalue;
132593Sbill 		goto comm;
133593Sbill 	case DIV:
134630Shenry 		if (exp2->e_xvalue == 0)
135593Sbill 			yyerror("Divide check");
136593Sbill 		else
137630Shenry 			exp1->e_xvalue /= exp2->e_xvalue;
138593Sbill 		goto comm;
139593Sbill 	case REGOP:
140630Shenry 		if (exp2->e_xvalue == 0)
141593Sbill 			yyerror("Divide check (modulo)");
142593Sbill 		else
143630Shenry 			exp1->e_xvalue %= exp2->e_xvalue;
144593Sbill 		goto comm;
145593Sbill 
146593Sbill 	comm:
147630Shenry 		back_type = othtab[e1_type][e2_type];
148593Sbill 		break;
149593Sbill 	default:
150593Sbill 		yyerror("Internal error: unknown operator");
151593Sbill 	}
152593Sbill 
153593Sbill 	if (e2_type==(XTXRN>>1))
154630Shenry 		exp1->e_xname = exp2->e_xname;
155630Shenry 	exp1->e_xtype = back_type | (
156630Shenry 			(exp1->e_xtype|exp2->e_xtype) & (XFORW|XXTRN) );
157630Shenry 	if (back_type==ERR)
158593Sbill 		yyerror("Relocation error");
159593Sbill 	return(exp1);
160593Sbill }
161593Sbill 
162593Sbill buildtokensets()
163593Sbill {
164593Sbill #define clobber(val, set) tokensets[(val)] |= (set)
165593Sbill 
166593Sbill 	clobber(SEMI,	LINSTBEGIN);
167593Sbill 	clobber(NL,	LINSTBEGIN);
168593Sbill 	clobber(INT,	LINSTBEGIN);
169593Sbill 
170593Sbill 	clobber(NAME,	YUKKYEXPRBEG + LINSTBEGIN);
171593Sbill 	clobber(INSTn,	YUKKYEXPRBEG);
172593Sbill 	clobber(INST0,	YUKKYEXPRBEG);
173593Sbill 	clobber(REG,	YUKKYEXPRBEG);
174593Sbill 	clobber(BFINT,	YUKKYEXPRBEG);
175593Sbill 
176593Sbill 	clobber(INT,	SAFEEXPRBEG);
1775823Srrh 	clobber(BIGNUM,	SAFEEXPRBEG);
178593Sbill 
179593Sbill 	clobber(PLUS,	ADDOPS);
180593Sbill 	clobber(MINUS,	ADDOPS + EBEGOPS);
181593Sbill 
182593Sbill 	clobber(LP,	EBEGOPS);
183593Sbill 
184593Sbill 	clobber(IOR,	BOOLOPS);
185593Sbill 	clobber(XOR,	BOOLOPS);
186593Sbill 	clobber(AND,	BOOLOPS);
187593Sbill 	clobber(ORNOT,	BOOLOPS);
188593Sbill 
189593Sbill 	clobber(TILDE,	MULOPS + EBEGOPS);
190593Sbill 	clobber(LSH,	MULOPS);
191593Sbill 	clobber(RSH,	MULOPS);
192593Sbill 	clobber(MUL,	MULOPS);
193593Sbill 	clobber(DIV,	MULOPS);
194593Sbill 	clobber(REGOP,	MULOPS);	/* % */
195593Sbill 
196593Sbill }
197593Sbill 
198593Sbill /*
199593Sbill  *	We keep the current token class in this global variable, so
200593Sbill  *	the recursive descent expression analyzers can talk amongst
201593Sbill  *	themselves, and so that we may use the macros shift and shift over
202593Sbill  */
203593Sbill 
204593Sbill extern	int	yylval;		/*the value of the lexical value*/
205593Sbill extern	struct	exp	*xp;	/*the next free expression slot*/
206593Sbill 
2075823Srrh static	inttoktype	val;
2085823Srrh 
2095823Srrh /*
2105823Srrh  *	return the value the read head is sitting on
2115823Srrh  */
2125823Srrh inttoktype exprparse(inval, backexpr)
2135823Srrh 	inttoktype	inval;
214593Sbill 	struct	exp **backexpr;
215593Sbill {
2165823Srrh 	reg	struct exp *lexpr;
2175823Srrh 	inttoktype	op;
218593Sbill 
219593Sbill 	val = inval;
220593Sbill 	lexpr = boolterm();
221593Sbill 	while (INTOKSET(val, ADDOPS)){
222593Sbill 		op = val;
223593Sbill 		shift;
224593Sbill 		lexpr = combine(op, lexpr, boolterm());
225593Sbill 	}
226593Sbill 	*backexpr = lexpr;
227593Sbill 	return(val);
228593Sbill }
229593Sbill 
230593Sbill struct exp *boolterm()
231593Sbill {
2325823Srrh 	reg	struct exp *lexpr;
2335823Srrh 	inttoktype	op;
234593Sbill 
235593Sbill 	lexpr = term();
236593Sbill 	while(INTOKSET(val, BOOLOPS)){
237593Sbill 		op = val;
238593Sbill 		shift;
239593Sbill 		lexpr = combine(op, lexpr, term());
240593Sbill 	}
241593Sbill 	return(lexpr);
242593Sbill }
243593Sbill 
244593Sbill struct exp *term()
245593Sbill {
2465823Srrh 	reg	struct	exp	*lexpr;
2475823Srrh 	inttoktype	op;
248593Sbill 
249593Sbill 	lexpr = factor();
250593Sbill 	while(INTOKSET(val, MULOPS)){
251593Sbill 		op = val;
252593Sbill 		shift;
253593Sbill 		lexpr = combine(op, lexpr, factor());
254593Sbill 	}
255593Sbill 	return(lexpr);
256593Sbill }
257593Sbill 
258593Sbill struct exp *factor()
259593Sbill {
260593Sbill 	struct	exp *lexpr;
2615823Srrh 	inttoktype	op;
262593Sbill 	extern		int	droppedLP;	/*called exprparse after consuming an LP*/
263593Sbill 
264593Sbill 	if (val == LP || droppedLP){
265593Sbill 		if (droppedLP)
266593Sbill 			droppedLP = 0;
267593Sbill 		else
268593Sbill 			shift;		/*the LP*/
269593Sbill 		val = exprparse(val, &lexpr);
270593Sbill 		if (val != RP)
271593Sbill 			yyerror("right parenthesis expected");
272593Sbill 		else
273593Sbill 			shift;
274593Sbill 	} else
275593Sbill 	if (INTOKSET(val, YUKKYEXPRBEG)){
276593Sbill 		lexpr = yukkyexpr(val, yylval);
277593Sbill 		shift;
278593Sbill 	}
279593Sbill 	else if (INTOKSET(val, SAFEEXPRBEG)){
280593Sbill 		lexpr = (struct exp *)yylval;
281593Sbill 		shift;
282593Sbill 	}
283593Sbill 	else if ( (val == TILDE) || (val == MINUS) ){
284593Sbill 		op = val;
285593Sbill 		shift;
286593Sbill 		lexpr = xp++;
287630Shenry 		lexpr->e_xtype = XABS;
2885823Srrh 		lexpr->e_number = Znumber;
2895823Srrh 		lexpr->e_number.num_tag = TYPL;
290593Sbill 		lexpr = combine(op, lexpr, factor());
2915823Srrh 	} else {
292593Sbill 		yyerror("Bad expression syntax");
293593Sbill 		lexpr = xp++;
294630Shenry 		lexpr->e_xtype = XABS;
2955823Srrh 		lexpr->e_number = Znumber;
2965823Srrh 		lexpr->e_number.num_tag = TYPL;
297593Sbill 	}
298593Sbill 	return(lexpr);
299593Sbill }
300593Sbill 
301593Sbill struct exp *yukkyexpr(val, np)
302593Sbill 	int	val;
3035823Srrh 	reg	np;
304593Sbill {
3055823Srrh 	reg	struct exp *locxp;
3065823Srrh 	extern	int	exprisname;	/*last factor is a name*/
3075823Srrh 		int	off = 0;
308593Sbill 
309593Sbill 	exprisname = 0;
310593Sbill 	locxp = xp++;
3115823Srrh 	locxp->e_number = Znumber;
3125823Srrh 	locxp->e_number.num_tag = TYPL;
3135823Srrh 
3145823Srrh 	switch(val){
3155823Srrh 	case BFINT:
3165823Srrh 		yylval = ((struct exp *)np)->e_xvalue;
3175823Srrh 		if (yylval < 0) {
3185823Srrh 			yylval = -yylval;
3195823Srrh 			yylval--;
3205823Srrh 			off = -1;
3215823Srrh 			if (lgensym[yylval] == 1)
3225823Srrh 				yyerror("Reference to undefined local label %db", yylval);
3235823Srrh 		} else {
3245823Srrh 			yylval--;
3255823Srrh 			genref[yylval] = 1;
326593Sbill 		}
3275823Srrh 		(void)sprintf(yytext, "L%d\001%d", yylval, lgensym[yylval] + off);
3285823Srrh 		yylval = np = (int)*lookup(passno == 1);
3295823Srrh 		lastnam = (struct symtab *)np;
3305823Srrh 		/* FALLTHROUGH */
3315823Srrh 	case NAME:
332593Sbill 		exprisname++;
333630Shenry 		locxp->e_xtype = ((struct symtab *)np)->s_type;
334630Shenry 		if (( ((struct symtab *)np)->s_type&XTYPE)==XUNDEF) { /*forward*/
335630Shenry 			locxp->e_xname = (struct symtab *)np;
336630Shenry 			locxp->e_xvalue = 0;
337593Sbill 			if (passno==1)
338630Shenry 				((struct symtab *)np)->s_type |= XFORW;
339593Sbill 		} else {	/*otherwise, just get the value*/
340630Shenry 			locxp->e_xvalue = ((struct symtab *)np)->s_value;
341630Shenry 			locxp->e_xname = NULL;
342593Sbill 		}
3435823Srrh 		break;
3445823Srrh 	default:
3455823Srrh 		yyerror("Internal Error in yukkyexpr");
3465823Srrh 		/* FALLTHROUGH */
3475823Srrh 
3485823Srrh 	case INSTn:
3495823Srrh 	case INST0:
3505823Srrh 	case REG:
351630Shenry 		locxp->e_xtype = XABS;
352630Shenry 		locxp->e_xvalue = ( (int)np) & 0xFF;
353630Shenry 		locxp->e_xloc = 0;
354630Shenry 		locxp->e_xname = NULL;
3555823Srrh 		break;
356593Sbill 	}
357593Sbill 
358593Sbill 	return(locxp);
359593Sbill }
360593Sbill 
361*12944Srrh /*
362*12944Srrh  *	Print definitions for token kinds
363*12944Srrh  */
364*12944Srrh static char pdirect[]	= "directive";
365*12944Srrh static char pinstr[]	= "instruction";
366*12944Srrh static char phunk[]	= "lexeme";
367*12944Srrh static char psmall[]	= "small symbol";
368*12944Srrh static char pcntrl[]	= "control token";
369593Sbill 
370*12944Srrh #define	DIRECT	pdirect
371*12944Srrh #define	INSTR	pinstr
372*12944Srrh #define	HUNK	phunk
373*12944Srrh #define	SMALL	psmall
374*12944Srrh #define	CNTRL	pcntrl
375*12944Srrh 
376593Sbill struct Tok_Desc{
377593Sbill 	int		tok_which;
378*12944Srrh 	char		*tok_kind;
379593Sbill 	char		*tok_name;
380593Sbill };
381*12944Srrh struct Tok_Desc *tok_name[LASTTOKEN - FIRSTTOKEN + 1];
382*12944Srrh 
383*12944Srrh struct Tok_Desc tok_desc[] = {
384*12944Srrh 	FIRSTTOKEN,	DIRECT,	"first token",
385*12944Srrh 
386*12944Srrh 	IBYTE,		DIRECT,	".byte",
387*12944Srrh 	IWORD,		DIRECT,	".word",
388*12944Srrh 	IINT,		DIRECT,	".int",
389*12944Srrh 	ILONG,		DIRECT,	".long",
390*12944Srrh 	IQUAD,		DIRECT,	".quad",
391*12944Srrh 	IOCTA,		DIRECT,	".octa",
392*12944Srrh 	IFFLOAT,	DIRECT,	".ffloat",
393*12944Srrh 	IDFLOAT,	DIRECT,	".dfloat",
394*12944Srrh 	IGFLOAT,	DIRECT,	".gfloat",
395*12944Srrh 	IHFLOAT,	DIRECT,	".hfloat",
396*12944Srrh 	IASCII,		DIRECT,	".ascii",
397*12944Srrh 	IASCIZ,		DIRECT,	".asciz",
398*12944Srrh 	IFILL,		DIRECT,	".fill",
399*12944Srrh 	ISPACE,		DIRECT,	".space",
400*12944Srrh 
401*12944Srrh 	IDATA,		DIRECT,	".data",
402*12944Srrh 	ITEXT,		DIRECT,	".text",
403*12944Srrh 	IGLOBAL,	DIRECT,	".global",
404*12944Srrh 	IALIGN,		DIRECT,	".align",
405*12944Srrh 
406*12944Srrh 	ISET,		DIRECT,	".set",
407*12944Srrh 	ICOMM,		DIRECT,	".comm",
408*12944Srrh 	ILCOMM,		DIRECT,	".lcomm",
409*12944Srrh 	IORG,		DIRECT,	".org",
410*12944Srrh 	ILSYM,		DIRECT,	".lsym",
411*12944Srrh 
412*12944Srrh 	ISTAB,		DIRECT,	".stab",
413*12944Srrh 	ISTABSTR,	DIRECT,	".stabstr",
414*12944Srrh 	ISTABNONE,	DIRECT,	".stabnone",
415*12944Srrh 	ISTABDOT,	DIRECT,	".stabdot",
416*12944Srrh 
417*12944Srrh 	IFILE,		DIRECT,	".file",
418*12944Srrh 	ILINENO,	DIRECT,	".lineno",
419*12944Srrh 	IABORT,		DIRECT,	".abort",
420*12944Srrh 
421*12944Srrh 	IJXXX,		INSTR,	"jump pseudo",
422*12944Srrh 	INST0,		INSTR,	"0 argument inst",
423*12944Srrh 	INSTn,		INSTR,	"n argument inst",
424*12944Srrh 
425*12944Srrh 	PARSEEOF,	CNTRL,	"parse end of file",
426*12944Srrh 	ILINESKIP,	CNTRL,	"skip lines",
427*12944Srrh 	VOID,		CNTRL,	"void",
428*12944Srrh 	SKIP,		CNTRL,	"skip",
429*12944Srrh 	NEEDSBUF,	CNTRL,	"need scanner buffer",
430*12944Srrh 	NL,		CNTRL,	"new line",
431*12944Srrh 	SCANEOF,	CNTRL,	"scanner end of file",
432*12944Srrh 	BADCHAR,	CNTRL,	"bad character",
433*12944Srrh 	SH,		CNTRL,	"comment, #",
434*12944Srrh 
435*12944Srrh 	INT,		HUNK,	"int",
436*12944Srrh 	BFINT,		HUNK,	"local label",
437*12944Srrh 	BIGNUM,		HUNK,	"big number",
438*12944Srrh 	NAME,		HUNK,	"name",
439*12944Srrh 	STRING,		HUNK,	"string",
440*12944Srrh 	REG,		HUNK,	"register specifier",
441*12944Srrh 
442*12944Srrh 	SIZESPEC,	SMALL,	"size specifier, [BWLbwl]",
443*12944Srrh 	SIZEQUOTE,	SMALL,	"sizequote, [^']",
444*12944Srrh 	LITOP,		SMALL,	"litop",
445*12944Srrh 
446*12944Srrh 	MP,		SMALL,	"minus parenthesis, -(",
447*12944Srrh 	REGOP,		SMALL,	"register operator, %",
448*12944Srrh 
449*12944Srrh 	SP,		SMALL,	"space",
450*12944Srrh 	ALPH,		SMALL,	"alphabetic character, [A-Za-z_]",
451*12944Srrh 	DIG,		SMALL,	"digit character, [A-Fa-f0-9]",
452*12944Srrh 
453*12944Srrh 	SQ,		SMALL,	"single quote, '",
454*12944Srrh 	DQ,		SMALL,	"double quote, \"",
455*12944Srrh 
456*12944Srrh 	LSH,		SMALL,	"arithmetic left shift, <",
457*12944Srrh 	RSH,		SMALL,	"arithmetic right shift, >",
458*12944Srrh 	XOR,		SMALL,	"exclusive or, ^",
459*12944Srrh 
460*12944Srrh 	PLUS,		SMALL,	"plus, +",
461*12944Srrh 	MINUS,		SMALL,	"minus, -",
462*12944Srrh 	MUL,		SMALL,	"multiply, *",
463*12944Srrh 	DIV,		SMALL,	"divide, /",
464*12944Srrh 	SEMI,		SMALL,	"semi colon, ;",
465*12944Srrh 	COLON,		SMALL,	"colon, :",
466*12944Srrh 	IOR,		SMALL,	"inclusive or, |",
467*12944Srrh 	AND,		SMALL,	"and, &",
468*12944Srrh 
469*12944Srrh 	TILDE,		SMALL,	"one's complement, ~",
470*12944Srrh 	ORNOT,		SMALL,	"ornot, !",
471*12944Srrh 	CM,		SMALL,	"comma",
472*12944Srrh 
473*12944Srrh 	LB,		SMALL,	"left bracket, [",
474*12944Srrh 	RB,		SMALL,	"right bracket, ]",
475*12944Srrh 	LP,		SMALL,	"left parenthesis, (",
476*12944Srrh 	RP,		SMALL,	"right parentheis, )",
477*12944Srrh 
478*12944Srrh 	LASTTOKEN,	SMALL,	"last token",
479*12944Srrh };
480593Sbill /*
481593Sbill  *	turn a token type into a string
482593Sbill  */
483593Sbill char *tok_to_name(token)
484593Sbill {
4855823Srrh 	static	int	fixed = 0;
486*12944Srrh 	static	char	buf[64];
487*12944Srrh 	static	struct	Tok_Desc 	NA = {0, (char *)0, "NOT ASSIGNED"};
488*12944Srrh 		int	i;
489*12944Srrh 		char	*cp;
4905823Srrh 
491593Sbill 	if (!fixed){
492593Sbill 		for (i = FIRSTTOKEN; i <= LASTTOKEN; i++)
493*12944Srrh 			tok_name[i] = &NA;
494*12944Srrh 		for (i = 0; i <= sizeof(tok_desc)/sizeof(struct Tok_Desc); i++){
495*12944Srrh 			tok_name[tok_desc[i].tok_which] = &tok_desc[i];
496593Sbill 		}
497593Sbill 		fixed = 1;
498593Sbill 	}
499*12944Srrh 	if (FIRSTTOKEN <= token && token <= LASTTOKEN){
500*12944Srrh 		sprintf(buf, "%s %s", tok_name[token]->tok_kind,
501*12944Srrh 			tok_name[token]->tok_name);
502*12944Srrh 		return(buf);
503*12944Srrh 	} else {
504593Sbill 		panic("Unknown token number, %d\n", token);
505*12944Srrh 		/*NOTREACHED*/
506*12944Srrh 	}
507593Sbill }
508