xref: /csrg-svn/old/as.vax/asexpr.c (revision 32430)
15823Srrh /*
219822Sdist  * Copyright (c) 1982 Regents of the University of California.
319822Sdist  * All rights reserved.  The Berkeley software License Agreement
419822Sdist  * specifies the terms and conditions for redistribution.
55823Srrh  */
619822Sdist 
75823Srrh #ifndef lint
8*32430Sbostic static char sccsid[] = "@(#)asexpr.c	5.4 (Berkeley) 10/22/87";
919822Sdist #endif not lint
105823Srrh 
11593Sbill #include <stdio.h>
12593Sbill #include "as.h"
135823Srrh #include "asscan.h"
14593Sbill #include "asexpr.h"
15593Sbill 
16593Sbill /*
17593Sbill  * Tables for combination of operands.
18593Sbill  */
19593Sbill #define	XTXRN	5<<1		/* indexes last row/column when right shifted */
20593Sbill 
21593Sbill /*
22593Sbill  *	table for +
23593Sbill  */
24593Sbill readonly char pltab[6][6] = {
25593Sbill /*		UND	ABS	TXT	DAT	BSS	EXT */
26593Sbill 
27593Sbill /*UND*/		XUNDEF,	XUNDEF,	XUNDEF,	XUNDEF,	XUNDEF,	XUNDEF,
28593Sbill /*ABS*/		XUNDEF,	XABS,	XTEXT,	XDATA,	XBSS,	XXTRN,
29593Sbill /*TXT*/		XUNDEF,	XTEXT,	ERR,	ERR,	ERR,	ERR,
30593Sbill /*DAT*/		XUNDEF,	XDATA,	ERR,	ERR,	ERR,	ERR,
31593Sbill /*BSS*/		XUNDEF,	XBSS,	ERR,	ERR,	ERR,	ERR,
32593Sbill /*EXT*/		XUNDEF,	XXTRN,	ERR,	ERR,	ERR,	ERR,
33593Sbill };
34593Sbill 
35593Sbill /*
36593Sbill  *	table for -
37593Sbill  */
38593Sbill readonly char mintab[6][6] = {
39593Sbill /*		UND	ABS	TXT	DAT	BSS	EXT */
40593Sbill 
41593Sbill /*UND*/		XUNDEF,	XUNDEF,	XUNDEF,	XUNDEF,	XUNDEF,	XUNDEF,
42593Sbill /*ABS*/		XUNDEF,	XABS,	ERR,	ERR,	ERR,	ERR,
43593Sbill /*TXT*/		XUNDEF,	XTEXT,	XABS,	ERR,	ERR,	ERR,
44593Sbill /*DAT*/		XUNDEF,	XDATA,	ERR,	XABS,	ERR,	ERR,
45593Sbill /*BSS*/		XUNDEF,	XBSS,	ERR,	ERR,	XABS,	ERR,
46593Sbill /*EXT*/		XUNDEF,	XXTRN,	ERR,	ERR,	ERR,	ERR,
47593Sbill };
48593Sbill 
49593Sbill /*
50593Sbill  *	table for other operators
51593Sbill  */
52593Sbill readonly char othtab[6][6] = {
53593Sbill /*		UND	ABS	TXT	DAT	BSS	EXT */
54593Sbill 
55593Sbill /*UND*/		XUNDEF,	XUNDEF,	XUNDEF,	XUNDEF,	XUNDEF,	XUNDEF,
56593Sbill /*ABS*/		XUNDEF,	XABS,	ERR,	ERR,	ERR,	ERR,
57593Sbill /*TXT*/		XUNDEF,	ERR,	ERR,	ERR,	ERR,	ERR,
58593Sbill /*DAT*/		XUNDEF,	ERR,	ERR,	ERR,	ERR,	ERR,
59593Sbill /*BSS*/		XUNDEF,	ERR,	ERR,	ERR,	ERR,	ERR,
60593Sbill /*EXT*/		XUNDEF,	ERR,	ERR,	ERR,	ERR,	ERR,
61593Sbill };
62593Sbill 
combine(op,exp1,exp2)635823Srrh struct exp *combine(op, exp1, exp2)
645823Srrh 	reg struct exp *exp1, *exp2;
65593Sbill {
665823Srrh 	reg 	e1_type, e2_type;
675823Srrh 	reg	back_type;
685823Srrh 	char	*btype = "The assembler can only do arithmetic on 1,2, or 4 byte integers";
69593Sbill 
70593Sbill 	lastnam=0; 			/* kludge for jxxx instructions */
71593Sbill 
72630Shenry 	e1_type = exp1->e_xtype&XTYPE;
73630Shenry 	e2_type = exp2->e_xtype&XTYPE;
74593Sbill 
75630Shenry 	if (exp1->e_xtype==XXTRN+XUNDEF)
76593Sbill 		e1_type = XTXRN;
77630Shenry 	if (exp2->e_xtype==XXTRN+XUNDEF)
78593Sbill 		e2_type = XTXRN;
79593Sbill 	if (passno==1)
80630Shenry 		if (exp1->e_xloc!=exp2->e_xloc && e1_type==e2_type)
81593Sbill 			e1_type = e2_type = XTXRN;	/* error on != loc ctrs */
82593Sbill 	e1_type >>= 1;		/*dispose of the external (XXTRN) bit*/
83593Sbill 	e2_type >>= 1;
84593Sbill 
855823Srrh 	switch(exp1->e_number.num_tag){
865823Srrh 	case TYPB:
875823Srrh 	case TYPW:
885823Srrh 	case TYPL:
895823Srrh 		break;
905823Srrh 	default:
915823Srrh 		yyerror(btype);
925823Srrh 		return(exp1);
935823Srrh 	}
945823Srrh 	switch(exp2->e_number.num_tag){
955823Srrh 	case TYPB:
965823Srrh 	case TYPW:
975823Srrh 	case TYPL:
985823Srrh 		break;
995823Srrh 	default:
1005823Srrh 		yyerror(btype);
1015823Srrh 		return(exp1);
1025823Srrh 	}
1035823Srrh 	switch (op){
104593Sbill 	case PLUS:
105630Shenry 		exp1->e_xvalue += exp2->e_xvalue;
106630Shenry 		back_type = pltab[e1_type][e2_type];
107593Sbill 		break;
108593Sbill 	case MINUS:
109630Shenry 		exp1->e_xvalue -= exp2->e_xvalue;
110630Shenry 		back_type = mintab[e1_type][e2_type];
111593Sbill 		break;
112593Sbill 	case IOR:
113630Shenry 		exp1->e_xvalue |= exp2->e_xvalue;
114593Sbill 		goto comm;
115593Sbill 	case XOR:
116630Shenry 		exp1->e_xvalue ^= exp2->e_xvalue;
117593Sbill 		goto comm;
118593Sbill 	case AND:
119630Shenry 		exp1->e_xvalue &= exp2->e_xvalue;
120593Sbill 		goto comm;
121593Sbill 	case ORNOT:
122630Shenry 		exp1->e_xvalue |= ~exp2->e_xvalue;
123593Sbill 		goto comm;
124593Sbill 	case LSH:
125630Shenry 		exp1->e_xvalue <<= exp2->e_xvalue;
126593Sbill 		goto comm;
127593Sbill 	case RSH:
128630Shenry 		exp1->e_xvalue >>= exp2->e_xvalue;
129593Sbill 		goto comm;
130593Sbill 	case TILDE:
131630Shenry 		exp1->e_xvalue |= ~ exp2->e_xvalue;
132593Sbill 		goto comm;
133593Sbill 	case MUL:
134630Shenry 		exp1->e_xvalue *= exp2->e_xvalue;
135593Sbill 		goto comm;
136593Sbill 	case DIV:
137630Shenry 		if (exp2->e_xvalue == 0)
138593Sbill 			yyerror("Divide check");
139593Sbill 		else
140630Shenry 			exp1->e_xvalue /= exp2->e_xvalue;
141593Sbill 		goto comm;
142593Sbill 	case REGOP:
143630Shenry 		if (exp2->e_xvalue == 0)
144593Sbill 			yyerror("Divide check (modulo)");
145593Sbill 		else
146630Shenry 			exp1->e_xvalue %= exp2->e_xvalue;
147593Sbill 		goto comm;
148593Sbill 
149593Sbill 	comm:
150630Shenry 		back_type = othtab[e1_type][e2_type];
151593Sbill 		break;
152593Sbill 	default:
153593Sbill 		yyerror("Internal error: unknown operator");
154593Sbill 	}
155593Sbill 
156593Sbill 	if (e2_type==(XTXRN>>1))
157630Shenry 		exp1->e_xname = exp2->e_xname;
158630Shenry 	exp1->e_xtype = back_type | (
159630Shenry 			(exp1->e_xtype|exp2->e_xtype) & (XFORW|XXTRN) );
160630Shenry 	if (back_type==ERR)
161593Sbill 		yyerror("Relocation error");
162593Sbill 	return(exp1);
163593Sbill }
164593Sbill 
buildtokensets()165593Sbill buildtokensets()
166593Sbill {
167593Sbill #define clobber(val, set) tokensets[(val)] |= (set)
168593Sbill 
169593Sbill 	clobber(SEMI,	LINSTBEGIN);
170593Sbill 	clobber(NL,	LINSTBEGIN);
171593Sbill 	clobber(INT,	LINSTBEGIN);
172593Sbill 
173593Sbill 	clobber(NAME,	YUKKYEXPRBEG + LINSTBEGIN);
174593Sbill 	clobber(INSTn,	YUKKYEXPRBEG);
175593Sbill 	clobber(INST0,	YUKKYEXPRBEG);
176593Sbill 	clobber(REG,	YUKKYEXPRBEG);
177593Sbill 	clobber(BFINT,	YUKKYEXPRBEG);
178593Sbill 
179593Sbill 	clobber(INT,	SAFEEXPRBEG);
1805823Srrh 	clobber(BIGNUM,	SAFEEXPRBEG);
181593Sbill 
182593Sbill 	clobber(PLUS,	ADDOPS);
183593Sbill 	clobber(MINUS,	ADDOPS + EBEGOPS);
184593Sbill 
185593Sbill 	clobber(LP,	EBEGOPS);
186593Sbill 
187593Sbill 	clobber(IOR,	BOOLOPS);
188593Sbill 	clobber(XOR,	BOOLOPS);
189593Sbill 	clobber(AND,	BOOLOPS);
190593Sbill 	clobber(ORNOT,	BOOLOPS);
191593Sbill 
192593Sbill 	clobber(TILDE,	MULOPS + EBEGOPS);
193593Sbill 	clobber(LSH,	MULOPS);
194593Sbill 	clobber(RSH,	MULOPS);
195593Sbill 	clobber(MUL,	MULOPS);
196593Sbill 	clobber(DIV,	MULOPS);
197593Sbill 	clobber(REGOP,	MULOPS);	/* % */
198593Sbill 
199593Sbill }
200593Sbill 
201593Sbill /*
202593Sbill  *	We keep the current token class in this global variable, so
203593Sbill  *	the recursive descent expression analyzers can talk amongst
204593Sbill  *	themselves, and so that we may use the macros shift and shift over
205593Sbill  */
206593Sbill 
207593Sbill extern	int	yylval;		/*the value of the lexical value*/
208593Sbill extern	struct	exp	*xp;	/*the next free expression slot*/
209593Sbill 
2105823Srrh static	inttoktype	val;
2115823Srrh 
2125823Srrh /*
2135823Srrh  *	return the value the read head is sitting on
2145823Srrh  */
exprparse(inval,backexpr)2155823Srrh inttoktype exprparse(inval, backexpr)
2165823Srrh 	inttoktype	inval;
217593Sbill 	struct	exp **backexpr;
218593Sbill {
2195823Srrh 	reg	struct exp *lexpr;
2205823Srrh 	inttoktype	op;
221593Sbill 
222593Sbill 	val = inval;
223593Sbill 	lexpr = boolterm();
224593Sbill 	while (INTOKSET(val, ADDOPS)){
225593Sbill 		op = val;
226593Sbill 		shift;
227593Sbill 		lexpr = combine(op, lexpr, boolterm());
228593Sbill 	}
229593Sbill 	*backexpr = lexpr;
230593Sbill 	return(val);
231593Sbill }
232593Sbill 
boolterm()233593Sbill struct exp *boolterm()
234593Sbill {
2355823Srrh 	reg	struct exp *lexpr;
2365823Srrh 	inttoktype	op;
237593Sbill 
238593Sbill 	lexpr = term();
239593Sbill 	while(INTOKSET(val, BOOLOPS)){
240593Sbill 		op = val;
241593Sbill 		shift;
242593Sbill 		lexpr = combine(op, lexpr, term());
243593Sbill 	}
244593Sbill 	return(lexpr);
245593Sbill }
246593Sbill 
term()247593Sbill struct exp *term()
248593Sbill {
2495823Srrh 	reg	struct	exp	*lexpr;
2505823Srrh 	inttoktype	op;
251593Sbill 
252593Sbill 	lexpr = factor();
253593Sbill 	while(INTOKSET(val, MULOPS)){
254593Sbill 		op = val;
255593Sbill 		shift;
256593Sbill 		lexpr = combine(op, lexpr, factor());
257593Sbill 	}
258593Sbill 	return(lexpr);
259593Sbill }
260593Sbill 
factor()261593Sbill struct exp *factor()
262593Sbill {
263593Sbill 	struct	exp *lexpr;
2645823Srrh 	inttoktype	op;
265593Sbill 	extern		int	droppedLP;	/*called exprparse after consuming an LP*/
266593Sbill 
267593Sbill 	if (val == LP || droppedLP){
268593Sbill 		if (droppedLP)
269593Sbill 			droppedLP = 0;
270593Sbill 		else
271593Sbill 			shift;		/*the LP*/
272593Sbill 		val = exprparse(val, &lexpr);
273593Sbill 		if (val != RP)
274593Sbill 			yyerror("right parenthesis expected");
275593Sbill 		else
276593Sbill 			shift;
277593Sbill 	} else
278593Sbill 	if (INTOKSET(val, YUKKYEXPRBEG)){
279593Sbill 		lexpr = yukkyexpr(val, yylval);
280593Sbill 		shift;
281593Sbill 	}
282593Sbill 	else if (INTOKSET(val, SAFEEXPRBEG)){
283593Sbill 		lexpr = (struct exp *)yylval;
284593Sbill 		shift;
285593Sbill 	}
286593Sbill 	else if ( (val == TILDE) || (val == MINUS) ){
287593Sbill 		op = val;
288593Sbill 		shift;
289593Sbill 		lexpr = xp++;
290630Shenry 		lexpr->e_xtype = XABS;
2915823Srrh 		lexpr->e_number = Znumber;
2925823Srrh 		lexpr->e_number.num_tag = TYPL;
293593Sbill 		lexpr = combine(op, lexpr, factor());
2945823Srrh 	} else {
295593Sbill 		yyerror("Bad expression syntax");
296593Sbill 		lexpr = xp++;
297630Shenry 		lexpr->e_xtype = XABS;
2985823Srrh 		lexpr->e_number = Znumber;
2995823Srrh 		lexpr->e_number.num_tag = TYPL;
300593Sbill 	}
301593Sbill 	return(lexpr);
302593Sbill }
303593Sbill 
yukkyexpr(val,np)304593Sbill struct exp *yukkyexpr(val, np)
305593Sbill 	int	val;
3065823Srrh 	reg	np;
307593Sbill {
3085823Srrh 	reg	struct exp *locxp;
3095823Srrh 	extern	int	exprisname;	/*last factor is a name*/
3105823Srrh 		int	off = 0;
311593Sbill 
312593Sbill 	exprisname = 0;
313593Sbill 	locxp = xp++;
3145823Srrh 	locxp->e_number = Znumber;
3155823Srrh 	locxp->e_number.num_tag = TYPL;
3165823Srrh 
3175823Srrh 	switch(val){
3185823Srrh 	case BFINT:
3195823Srrh 		yylval = ((struct exp *)np)->e_xvalue;
3205823Srrh 		if (yylval < 0) {
3215823Srrh 			yylval = -yylval;
3225823Srrh 			yylval--;
3235823Srrh 			off = -1;
3245823Srrh 			if (lgensym[yylval] == 1)
3255823Srrh 				yyerror("Reference to undefined local label %db", yylval);
3265823Srrh 		} else {
3275823Srrh 			yylval--;
3285823Srrh 			genref[yylval] = 1;
329593Sbill 		}
3305823Srrh 		(void)sprintf(yytext, "L%d\001%d", yylval, lgensym[yylval] + off);
3315823Srrh 		yylval = np = (int)*lookup(passno == 1);
3325823Srrh 		lastnam = (struct symtab *)np;
3335823Srrh 		/* FALLTHROUGH */
3345823Srrh 	case NAME:
33530098Sdonn 		exprisname = (int) np;
336630Shenry 		locxp->e_xtype = ((struct symtab *)np)->s_type;
337630Shenry 		if (( ((struct symtab *)np)->s_type&XTYPE)==XUNDEF) { /*forward*/
338630Shenry 			locxp->e_xname = (struct symtab *)np;
339630Shenry 			locxp->e_xvalue = 0;
340593Sbill 			if (passno==1)
341630Shenry 				((struct symtab *)np)->s_type |= XFORW;
342593Sbill 		} else {	/*otherwise, just get the value*/
343630Shenry 			locxp->e_xvalue = ((struct symtab *)np)->s_value;
344630Shenry 			locxp->e_xname = NULL;
345593Sbill 		}
3465823Srrh 		break;
3475823Srrh 	default:
3485823Srrh 		yyerror("Internal Error in yukkyexpr");
3495823Srrh 		/* FALLTHROUGH */
3505823Srrh 
3515823Srrh 	case INSTn:
3525823Srrh 	case INST0:
3535823Srrh 	case REG:
354630Shenry 		locxp->e_xtype = XABS;
355630Shenry 		locxp->e_xvalue = ( (int)np) & 0xFF;
356630Shenry 		locxp->e_xloc = 0;
357630Shenry 		locxp->e_xname = NULL;
3585823Srrh 		break;
359593Sbill 	}
360593Sbill 
361593Sbill 	return(locxp);
362593Sbill }
363593Sbill 
36412944Srrh /*
36512944Srrh  *	Print definitions for token kinds
36612944Srrh  */
36712944Srrh static char pdirect[]	= "directive";
36812944Srrh static char pinstr[]	= "instruction";
36912944Srrh static char phunk[]	= "lexeme";
37012944Srrh static char psmall[]	= "small symbol";
37112944Srrh static char pcntrl[]	= "control token";
372593Sbill 
37312944Srrh #define	DIRECT	pdirect
37412944Srrh #define	INSTR	pinstr
37512944Srrh #define	HUNK	phunk
37612944Srrh #define	SMALL	psmall
37712944Srrh #define	CNTRL	pcntrl
37812944Srrh 
379593Sbill struct Tok_Desc{
380593Sbill 	int		tok_which;
38112944Srrh 	char		*tok_kind;
382593Sbill 	char		*tok_name;
383593Sbill };
38412944Srrh struct Tok_Desc *tok_name[LASTTOKEN - FIRSTTOKEN + 1];
38512944Srrh 
38612944Srrh struct Tok_Desc tok_desc[] = {
38712944Srrh 	FIRSTTOKEN,	DIRECT,	"first token",
38812944Srrh 
38912944Srrh 	IBYTE,		DIRECT,	".byte",
39012944Srrh 	IWORD,		DIRECT,	".word",
39112944Srrh 	IINT,		DIRECT,	".int",
39212944Srrh 	ILONG,		DIRECT,	".long",
39312944Srrh 	IQUAD,		DIRECT,	".quad",
39412944Srrh 	IOCTA,		DIRECT,	".octa",
39512944Srrh 	IFFLOAT,	DIRECT,	".ffloat",
39612944Srrh 	IDFLOAT,	DIRECT,	".dfloat",
39712944Srrh 	IGFLOAT,	DIRECT,	".gfloat",
39812944Srrh 	IHFLOAT,	DIRECT,	".hfloat",
39912944Srrh 	IASCII,		DIRECT,	".ascii",
40012944Srrh 	IASCIZ,		DIRECT,	".asciz",
40112944Srrh 	IFILL,		DIRECT,	".fill",
40212944Srrh 	ISPACE,		DIRECT,	".space",
40312944Srrh 
40412944Srrh 	IDATA,		DIRECT,	".data",
40512944Srrh 	ITEXT,		DIRECT,	".text",
40612944Srrh 	IGLOBAL,	DIRECT,	".global",
40712944Srrh 	IALIGN,		DIRECT,	".align",
40812944Srrh 
40912944Srrh 	ISET,		DIRECT,	".set",
41012944Srrh 	ICOMM,		DIRECT,	".comm",
41112944Srrh 	ILCOMM,		DIRECT,	".lcomm",
41212944Srrh 	IORG,		DIRECT,	".org",
41312944Srrh 	ILSYM,		DIRECT,	".lsym",
41412944Srrh 
41512944Srrh 	ISTAB,		DIRECT,	".stab",
41612944Srrh 	ISTABSTR,	DIRECT,	".stabstr",
41712944Srrh 	ISTABNONE,	DIRECT,	".stabnone",
41812944Srrh 	ISTABDOT,	DIRECT,	".stabdot",
41912944Srrh 
42012944Srrh 	IFILE,		DIRECT,	".file",
42112944Srrh 	ILINENO,	DIRECT,	".lineno",
42212944Srrh 	IABORT,		DIRECT,	".abort",
42312944Srrh 
42412944Srrh 	IJXXX,		INSTR,	"jump pseudo",
42512944Srrh 	INST0,		INSTR,	"0 argument inst",
42612944Srrh 	INSTn,		INSTR,	"n argument inst",
42712944Srrh 
42812944Srrh 	PARSEEOF,	CNTRL,	"parse end of file",
42912944Srrh 	ILINESKIP,	CNTRL,	"skip lines",
43012944Srrh 	VOID,		CNTRL,	"void",
43112944Srrh 	SKIP,		CNTRL,	"skip",
43212944Srrh 	NL,		CNTRL,	"new line",
43312944Srrh 	SCANEOF,	CNTRL,	"scanner end of file",
43412944Srrh 	BADCHAR,	CNTRL,	"bad character",
43512944Srrh 	SH,		CNTRL,	"comment, #",
43612944Srrh 
43712944Srrh 	INT,		HUNK,	"int",
43812944Srrh 	BFINT,		HUNK,	"local label",
43912944Srrh 	BIGNUM,		HUNK,	"big number",
44012944Srrh 	NAME,		HUNK,	"name",
44112944Srrh 	STRING,		HUNK,	"string",
44212944Srrh 	REG,		HUNK,	"register specifier",
44312944Srrh 
44412944Srrh 	SIZESPEC,	SMALL,	"size specifier, [BWLbwl]",
44512944Srrh 	SIZEQUOTE,	SMALL,	"sizequote, [^']",
44612944Srrh 	LITOP,		SMALL,	"litop",
44712944Srrh 
44812944Srrh 	MP,		SMALL,	"minus parenthesis, -(",
44912944Srrh 	REGOP,		SMALL,	"register operator, %",
45012944Srrh 
45112944Srrh 	SP,		SMALL,	"space",
45212944Srrh 	ALPH,		SMALL,	"alphabetic character, [A-Za-z_]",
45312944Srrh 	DIG,		SMALL,	"digit character, [A-Fa-f0-9]",
45412944Srrh 
45512944Srrh 	SQ,		SMALL,	"single quote, '",
45612944Srrh 	DQ,		SMALL,	"double quote, \"",
45712944Srrh 
45812944Srrh 	LSH,		SMALL,	"arithmetic left shift, <",
45912944Srrh 	RSH,		SMALL,	"arithmetic right shift, >",
46012944Srrh 	XOR,		SMALL,	"exclusive or, ^",
46112944Srrh 
46212944Srrh 	PLUS,		SMALL,	"plus, +",
46312944Srrh 	MINUS,		SMALL,	"minus, -",
46412944Srrh 	MUL,		SMALL,	"multiply, *",
46512944Srrh 	DIV,		SMALL,	"divide, /",
46612944Srrh 	SEMI,		SMALL,	"semi colon, ;",
46712944Srrh 	COLON,		SMALL,	"colon, :",
46812944Srrh 	IOR,		SMALL,	"inclusive or, |",
46912944Srrh 	AND,		SMALL,	"and, &",
47012944Srrh 
47112944Srrh 	TILDE,		SMALL,	"one's complement, ~",
47212944Srrh 	ORNOT,		SMALL,	"ornot, !",
47312944Srrh 	CM,		SMALL,	"comma",
47412944Srrh 
47512944Srrh 	LB,		SMALL,	"left bracket, [",
47612944Srrh 	RB,		SMALL,	"right bracket, ]",
47712944Srrh 	LP,		SMALL,	"left parenthesis, (",
47812944Srrh 	RP,		SMALL,	"right parentheis, )",
47912944Srrh 
48012944Srrh 	LASTTOKEN,	SMALL,	"last token",
48112944Srrh };
482593Sbill /*
483593Sbill  *	turn a token type into a string
484593Sbill  */
tok_to_name(token)485593Sbill char *tok_to_name(token)
486593Sbill {
4875823Srrh 	static	int	fixed = 0;
48812944Srrh 	static	char	buf[64];
48912944Srrh 	static	struct	Tok_Desc 	NA = {0, (char *)0, "NOT ASSIGNED"};
49012944Srrh 		int	i;
49112944Srrh 		char	*cp;
4925823Srrh 
493593Sbill 	if (!fixed){
494593Sbill 		for (i = FIRSTTOKEN; i <= LASTTOKEN; i++)
49512944Srrh 			tok_name[i] = &NA;
49612944Srrh 		for (i = 0; i <= sizeof(tok_desc)/sizeof(struct Tok_Desc); i++){
49712944Srrh 			tok_name[tok_desc[i].tok_which] = &tok_desc[i];
498593Sbill 		}
499593Sbill 		fixed = 1;
500593Sbill 	}
50112944Srrh 	if (FIRSTTOKEN <= token && token <= LASTTOKEN){
502*32430Sbostic 		(void)sprintf(buf, "%s %s", tok_name[token]->tok_kind,
50312944Srrh 			tok_name[token]->tok_name);
50412944Srrh 		return(buf);
50512944Srrh 	} else {
506593Sbill 		panic("Unknown token number, %d\n", token);
50712944Srrh 		/*NOTREACHED*/
50812944Srrh 	}
509593Sbill }
510