xref: /csrg-svn/old/as.tahoe/asexpr.c (revision 32433)
129831Ssam /*
229831Ssam  *	Copyright (c) 1982 Regents of the University of California
329831Ssam  */
429831Ssam #ifndef lint
529831Ssam static char sccsid[] = "@(#)asexpr.c 4.5 6/30/83";
629831Ssam 
729831Ssam #endif not lint
829831Ssam #include <stdio.h>
929831Ssam #include "as.h"
1029831Ssam #include "asscan.h"
1129831Ssam #include "asexpr.h"
1229831Ssam 
1329831Ssam /*
1429831Ssam  * Tables for combination of operands.
1529831Ssam  */
1629831Ssam #define	XTXRN	5<<1		/* indexes last row/column when right shifted */
1729831Ssam 
1829831Ssam /*
1929831Ssam  *	table for +
2029831Ssam  */
2129831Ssam readonly char pltab[6][6] = {
2229831Ssam /*		UND	ABS	TXT	DAT	BSS	EXT */
2329831Ssam 
2429831Ssam /*UND*/		XUNDEF,	XUNDEF,	XUNDEF,	XUNDEF,	XUNDEF,	XUNDEF,
2529831Ssam /*ABS*/		XUNDEF,	XABS,	XTEXT,	XDATA,	XBSS,	XXTRN,
2629831Ssam /*TXT*/		XUNDEF,	XTEXT,	ERR,	ERR,	ERR,	ERR,
2729831Ssam /*DAT*/		XUNDEF,	XDATA,	ERR,	ERR,	ERR,	ERR,
2829831Ssam /*BSS*/		XUNDEF,	XBSS,	ERR,	ERR,	ERR,	ERR,
2929831Ssam /*EXT*/		XUNDEF,	XXTRN,	ERR,	ERR,	ERR,	ERR,
3029831Ssam };
3129831Ssam 
3229831Ssam /*
3329831Ssam  *	table for -
3429831Ssam  */
3529831Ssam readonly char mintab[6][6] = {
3629831Ssam /*		UND	ABS	TXT	DAT	BSS	EXT */
3729831Ssam 
3829831Ssam /*UND*/		XUNDEF,	XUNDEF,	XUNDEF,	XUNDEF,	XUNDEF,	XUNDEF,
3929831Ssam /*ABS*/		XUNDEF,	XABS,	ERR,	ERR,	ERR,	ERR,
4029831Ssam /*TXT*/		XUNDEF,	XTEXT,	XABS,	ERR,	ERR,	ERR,
4129831Ssam /*DAT*/		XUNDEF,	XDATA,	ERR,	XABS,	ERR,	ERR,
4229831Ssam /*BSS*/		XUNDEF,	XBSS,	ERR,	ERR,	XABS,	ERR,
4329831Ssam /*EXT*/		XUNDEF,	XXTRN,	ERR,	ERR,	ERR,	ERR,
4429831Ssam };
4529831Ssam 
4629831Ssam /*
4729831Ssam  *	table for other operators
4829831Ssam  */
4929831Ssam readonly char othtab[6][6] = {
5029831Ssam /*		UND	ABS	TXT	DAT	BSS	EXT */
5129831Ssam 
5229831Ssam /*UND*/		XUNDEF,	XUNDEF,	XUNDEF,	XUNDEF,	XUNDEF,	XUNDEF,
5329831Ssam /*ABS*/		XUNDEF,	XABS,	ERR,	ERR,	ERR,	ERR,
5429831Ssam /*TXT*/		XUNDEF,	ERR,	ERR,	ERR,	ERR,	ERR,
5529831Ssam /*DAT*/		XUNDEF,	ERR,	ERR,	ERR,	ERR,	ERR,
5629831Ssam /*BSS*/		XUNDEF,	ERR,	ERR,	ERR,	ERR,	ERR,
5729831Ssam /*EXT*/		XUNDEF,	ERR,	ERR,	ERR,	ERR,	ERR,
5829831Ssam };
5929831Ssam 
combine(op,exp1,exp2)6029831Ssam struct exp *combine(op, exp1, exp2)
6129831Ssam 	reg struct exp *exp1, *exp2;
6229831Ssam {
6329831Ssam 	reg 	int e1_type, e2_type;
6429831Ssam 	reg	int back_type;
6529831Ssam 	char	*btype = "The assembler can only do arithmetic on 1,2, or 4 byte integers";
6629831Ssam 
6729831Ssam 	lastnam=0; 			/* kludge for jxxx instructions */
6829831Ssam 
6929831Ssam 	e1_type = exp1->e_xtype&XTYPE;
7029831Ssam 	e2_type = exp2->e_xtype&XTYPE;
7129831Ssam 
7229831Ssam 	if (exp1->e_xtype==XXTRN+XUNDEF)
7329831Ssam 		e1_type = XTXRN;
7429831Ssam 	if (exp2->e_xtype==XXTRN+XUNDEF)
7529831Ssam 		e2_type = XTXRN;
7629831Ssam 	if (passno==1)
7729831Ssam 		if (exp1->e_xloc!=exp2->e_xloc && e1_type==e2_type)
7829831Ssam 			e1_type = e2_type = XTXRN;	/* error on != loc ctrs */
7929831Ssam 	e1_type >>= 1;		/*dispose of the external (XXTRN) bit*/
8029831Ssam 	e2_type >>= 1;
8129831Ssam 
8229831Ssam 	switch (op){
8329831Ssam 	case PLUS:
8429831Ssam 		exp1->e_xvalue += exp2->e_xvalue;
8529831Ssam 		back_type = pltab[e1_type][e2_type];
8629831Ssam 		break;
8729831Ssam 	case MINUS:
8829831Ssam 		exp1->e_xvalue -= exp2->e_xvalue;
8929831Ssam 		back_type = mintab[e1_type][e2_type];
9029831Ssam 		break;
9129831Ssam 	case IOR:
9229831Ssam 		exp1->e_xvalue |= exp2->e_xvalue;
9329831Ssam 		goto comm;
9429831Ssam 	case XOR:
9529831Ssam 		exp1->e_xvalue ^= exp2->e_xvalue;
9629831Ssam 		goto comm;
9729831Ssam 	case AND:
9829831Ssam 		exp1->e_xvalue &= exp2->e_xvalue;
9929831Ssam 		goto comm;
10029831Ssam 	case ORNOT:
10129831Ssam 		exp1->e_xvalue |= ~exp2->e_xvalue;
10229831Ssam 		goto comm;
10329831Ssam 	case LSH:
10429831Ssam 		exp1->e_xvalue <<= exp2->e_xvalue;
10529831Ssam 		goto comm;
10629831Ssam 	case RSH:
10729831Ssam 		exp1->e_xvalue >>= exp2->e_xvalue;
10829831Ssam 		goto comm;
10929831Ssam 	case TILDE:
11029831Ssam 		exp1->e_xvalue |= ~ exp2->e_xvalue;
11129831Ssam 		goto comm;
11229831Ssam 	case MUL:
11329831Ssam 		exp1->e_xvalue *= exp2->e_xvalue;
11429831Ssam 		goto comm;
11529831Ssam 	case DIV:
11629831Ssam 		if (exp2->e_xvalue == 0)
11729831Ssam 			yyerror("Divide check");
11829831Ssam 		else
11929831Ssam 			exp1->e_xvalue /= exp2->e_xvalue;
12029831Ssam 		goto comm;
12129831Ssam 	case REGOP:
12229831Ssam 		if (exp2->e_xvalue == 0)
12329831Ssam 			yyerror("Divide check (modulo)");
12429831Ssam 		else
12529831Ssam 			exp1->e_xvalue %= exp2->e_xvalue;
12629831Ssam 		goto comm;
12729831Ssam 
12829831Ssam 	comm:
12929831Ssam 		back_type = othtab[e1_type][e2_type];
13029831Ssam 		break;
13129831Ssam 	default:
13229831Ssam 		yyerror("Internal error: unknown operator");
13329831Ssam 	}
13429831Ssam 
13529831Ssam 	if (e2_type==(XTXRN>>1))
13629831Ssam 		exp1->e_xname = exp2->e_xname;
13729831Ssam 	exp1->e_xtype = back_type | (
13829831Ssam 			(exp1->e_xtype|exp2->e_xtype) & (XFORW|XXTRN) );
13929831Ssam 	if (back_type==ERR)
14029831Ssam 		yyerror("Relocation error");
14129831Ssam 	return(exp1);
14229831Ssam }
14329831Ssam 
buildtokensets()14429831Ssam buildtokensets()
14529831Ssam {
14629831Ssam #define clobber(val, set) tokensets[(val)] |= (set)
14729831Ssam 
14829831Ssam 	clobber(SEMI,	LINSTBEGIN);
14929831Ssam 	clobber(NL,	LINSTBEGIN);
15029831Ssam 	clobber(INT,	LINSTBEGIN);
15129831Ssam 
15229831Ssam 	clobber(NAME,	YUKKYEXPRBEG + LINSTBEGIN);
15329831Ssam 	clobber(INSTn,	YUKKYEXPRBEG);
15429831Ssam 	clobber(INST0,	YUKKYEXPRBEG);
15529831Ssam 	clobber(REG,	YUKKYEXPRBEG);
15629831Ssam 	clobber(BFINT,	YUKKYEXPRBEG);
15729831Ssam 
15829831Ssam 	clobber(INT,	SAFEEXPRBEG);
15929831Ssam 	clobber(BIGNUM,	SAFEEXPRBEG);
16029831Ssam 
16129831Ssam 	clobber(PLUS,	ADDOPS);
16229831Ssam 	clobber(MINUS,	ADDOPS + EBEGOPS);
16329831Ssam 
16429831Ssam 	clobber(LP,	EBEGOPS);
16529831Ssam 
16629831Ssam 	clobber(IOR,	BOOLOPS);
16729831Ssam 	clobber(XOR,	BOOLOPS);
16829831Ssam 	clobber(AND,	BOOLOPS);
16929831Ssam 	clobber(ORNOT,	BOOLOPS);
17029831Ssam 
17129831Ssam 	clobber(TILDE,	MULOPS + EBEGOPS);
17229831Ssam 	clobber(LSH,	MULOPS);
17329831Ssam 	clobber(RSH,	MULOPS);
17429831Ssam 	clobber(MUL,	MULOPS);
17529831Ssam 	clobber(DIV,	MULOPS);
17629831Ssam 	clobber(REGOP,	MULOPS);	/* % */
17729831Ssam 
17829831Ssam }
17929831Ssam 
18029831Ssam /*
18129831Ssam  *	We keep the current token class in this global variable, so
18229831Ssam  *	the recursive descent expression analyzers can talk amongst
18329831Ssam  *	themselves, and so that we may use the macros shift and shift over
18429831Ssam  */
18529831Ssam 
18629831Ssam extern	int	yylval;		/*the value of the lexical value*/
18729831Ssam extern	struct	exp	*xp;	/*the next free expression slot*/
18829831Ssam 
18929831Ssam static	inttoktype	val;
19029831Ssam 
19129831Ssam /*
19229831Ssam  *	return the value the read head is sitting on
19329831Ssam  */
exprparse(inval,backexpr)19429831Ssam inttoktype exprparse(inval, backexpr)
19529831Ssam 	inttoktype	inval;
19629831Ssam 	struct	exp **backexpr;
19729831Ssam {
19829831Ssam 	reg	struct exp *lexpr;
19929831Ssam 	inttoktype	op;
20029831Ssam 
20129831Ssam 	val = inval;
20229831Ssam 	lexpr = boolterm();
20329831Ssam 	while (INTOKSET(val, ADDOPS)){
20429831Ssam 		op = val;
20529831Ssam 		shift;
20629831Ssam 		lexpr = combine(op, lexpr, boolterm());
20729831Ssam 	}
20829831Ssam 	*backexpr = lexpr;
20929831Ssam 	return(val);
21029831Ssam }
21129831Ssam 
boolterm()21229831Ssam struct exp *boolterm()
21329831Ssam {
21429831Ssam 	reg	struct exp *lexpr;
21529831Ssam 	inttoktype	op;
21629831Ssam 
21729831Ssam 	lexpr = term();
21829831Ssam 	while(INTOKSET(val, BOOLOPS)){
21929831Ssam 		op = val;
22029831Ssam 		shift;
22129831Ssam 		lexpr = combine(op, lexpr, term());
22229831Ssam 	}
22329831Ssam 	return(lexpr);
22429831Ssam }
22529831Ssam 
term()22629831Ssam struct exp *term()
22729831Ssam {
22829831Ssam 	reg	struct	exp	*lexpr;
22929831Ssam 	inttoktype	op;
23029831Ssam 
23129831Ssam 	lexpr = factor();
23229831Ssam 	while(INTOKSET(val, MULOPS)){
23329831Ssam 		op = val;
23429831Ssam 		shift;
23529831Ssam 		lexpr = combine(op, lexpr, factor());
23629831Ssam 	}
23729831Ssam 	return(lexpr);
23829831Ssam }
23929831Ssam 
factor()24029831Ssam struct exp *factor()
24129831Ssam {
24229831Ssam 	struct	exp *lexpr;
24329831Ssam 	inttoktype	op;
24429831Ssam 	extern		int	droppedLP;	/*called exprparse after consuming an LP*/
24529831Ssam 
24629831Ssam 	if (val == LP || droppedLP){
24729831Ssam 		if (droppedLP)
24829831Ssam 			droppedLP = 0;
24929831Ssam 		else
25029831Ssam 			shift;		/*the LP*/
25129831Ssam 		val = exprparse(val, &lexpr);
25229831Ssam 		if (val != RP)
25329831Ssam 			yyerror("right parenthesis expected");
25429831Ssam 		else
25529831Ssam 			shift;
25629831Ssam 	} else
25729831Ssam 	if (INTOKSET(val, YUKKYEXPRBEG)){
25829831Ssam 		lexpr = yukkyexpr(val, yylval);
25929831Ssam 		shift;
26029831Ssam 	}
26129831Ssam 	else if (INTOKSET(val, SAFEEXPRBEG)){
26229831Ssam 		lexpr = (struct exp *)yylval;
26329831Ssam 		shift;
26429831Ssam 	}
26529831Ssam 	else if ( (val == TILDE) || (val == MINUS) ){
26629831Ssam 		op = val;
26729831Ssam 		shift;
26829831Ssam 		lexpr = xp++;
26929831Ssam 		lexpr->e_xtype = XABS;
27029831Ssam 		lexpr->e_number = Znumber;
27129831Ssam 		lexpr->e_number.num_tag = TYPL;
27229831Ssam 		lexpr = combine(op, lexpr, factor());
27329831Ssam 	} else {
27429831Ssam 		yyerror("Bad expression syntax");
27529831Ssam 		lexpr = xp++;
27629831Ssam 		lexpr->e_xtype = XABS;
27729831Ssam 		lexpr->e_number = Znumber;
27829831Ssam 		lexpr->e_number.num_tag = TYPL;
27929831Ssam 	}
28029831Ssam 	return(lexpr);
28129831Ssam }
28229831Ssam 
yukkyexpr(val,np)28329831Ssam struct exp *yukkyexpr(val, np)
28429831Ssam 	int	val;
28529831Ssam 	reg	int np;
28629831Ssam {
28729831Ssam 	reg	struct exp *locxp;
28829831Ssam 	extern	int	exprisname;	/*last factor is a name*/
28929831Ssam 		int	off = 0;
29029831Ssam 
29129831Ssam 	exprisname = 0;
29229831Ssam 	locxp = xp++;
29329831Ssam 	locxp->e_number = Znumber;
29429831Ssam 	locxp->e_number.num_tag = TYPL;
29529831Ssam 
29629831Ssam 	switch(val){
29729831Ssam 	case BFINT:
29829831Ssam 		yylval = ((struct exp *)np)->e_xvalue;
29929831Ssam 		if (yylval < 0) {
30029831Ssam 			yylval = -yylval;
30129831Ssam 			yylval--;
30229831Ssam 			off = -1;
30329831Ssam 			if (lgensym[yylval] == 1)
30429831Ssam 				yyerror("Reference to undefined local label %db", yylval);
30529831Ssam 		} else {
30629831Ssam 			yylval--;
30729831Ssam 			genref[yylval] = 1;
30829831Ssam 		}
30929831Ssam 		(void)sprintf(yytext, "L%d\001%d", yylval, lgensym[yylval] + off);
31029831Ssam 		yylval = np = (int)*lookup(passno == 1);
31129831Ssam 		lastnam = (struct symtab *)np;
31229831Ssam 		/* FALLTHROUGH */
31329831Ssam 	case NAME:
31431350Ssam 		exprisname = (int)np;
31529831Ssam 		locxp->e_xtype = ((struct symtab *)np)->s_type;
31629831Ssam 		if (( ((struct symtab *)np)->s_type&XTYPE)==XUNDEF) { /*forward*/
31729831Ssam 			locxp->e_xname = (struct symtab *)np;
31829831Ssam 			locxp->e_xvalue = 0;
31929831Ssam 			if (passno==1)
32029831Ssam 				((struct symtab *)np)->s_type |= XFORW;
32129831Ssam 		} else {	/*otherwise, just get the value*/
32229831Ssam 			locxp->e_xvalue = ((struct symtab *)np)->s_value;
32329831Ssam 			locxp->e_xname = NULL;
32429831Ssam 		}
32529831Ssam 		break;
32629831Ssam 	default:
32729831Ssam 		yyerror("Internal Error in yukkyexpr");
32829831Ssam 		/* FALLTHROUGH */
32929831Ssam 
33029831Ssam 	case INSTn:
33129831Ssam 	case INST0:
33229831Ssam 	case REG:
33329831Ssam 		locxp->e_xtype = XABS;
33429831Ssam 		locxp->e_xvalue = ( (int)np) & 0xFF;
33529831Ssam 		locxp->e_xloc = 0;
33629831Ssam 		locxp->e_xname = NULL;
33729831Ssam 		break;
33829831Ssam 	}
33929831Ssam 
34029831Ssam 	return(locxp);
34129831Ssam }
34229831Ssam 
34329831Ssam /*
34429831Ssam  *	Print definitions for token kinds
34529831Ssam  */
34629831Ssam static char pdirect[]	= "directive";
34729831Ssam static char pinstr[]	= "instruction";
34829831Ssam static char phunk[]	= "lexeme";
34929831Ssam static char psmall[]	= "small symbol";
35029831Ssam static char pcntrl[]	= "control token";
35129831Ssam 
35229831Ssam #define	DIRECT	pdirect
35329831Ssam #define	INSTR	pinstr
35429831Ssam #define	HUNK	phunk
35529831Ssam #define	SMALL	psmall
35629831Ssam #define	CNTRL	pcntrl
35729831Ssam 
35829831Ssam struct Tok_Desc{
35929831Ssam 	int		tok_which;
36029831Ssam 	char		*tok_kind;
36129831Ssam 	char		*tok_name;
36229831Ssam };
36329831Ssam struct Tok_Desc *tok_name[LASTTOKEN - FIRSTTOKEN + 1];
36429831Ssam 
36529831Ssam struct Tok_Desc tok_desc[] = {
36629831Ssam 	FIRSTTOKEN,	DIRECT,	"first token",
36729831Ssam 
36829831Ssam 	IBYTE,		DIRECT,	".byte",
36929831Ssam 	IWORD,		DIRECT,	".word",
37029831Ssam 	IINT,		DIRECT,	".int",
37129831Ssam 	ILONG,		DIRECT,	".long",
37229831Ssam 	IQUAD,		DIRECT,	".quad",
37329831Ssam 	IFFLOAT,	DIRECT,	".ffloat",
37429831Ssam 	IDFLOAT,	DIRECT,	".dfloat",
37529831Ssam 	IASCII,		DIRECT,	".ascii",
37629831Ssam 	IASCIZ,		DIRECT,	".asciz",
37729831Ssam 	IFILL,		DIRECT,	".fill",
37829831Ssam 	ISPACE,		DIRECT,	".space",
37929831Ssam 
38029831Ssam 	IDATA,		DIRECT,	".data",
38129831Ssam 	ITEXT,		DIRECT,	".text",
38229831Ssam 	IGLOBAL,	DIRECT,	".global",
38329831Ssam 	IALIGN,		DIRECT,	".align",
38429831Ssam 
38529831Ssam 	ISET,		DIRECT,	".set",
38629831Ssam 	ICOMM,		DIRECT,	".comm",
38729831Ssam 	ILCOMM,		DIRECT,	".lcomm",
38829831Ssam 	IORG,		DIRECT,	".org",
38929831Ssam 	ILSYM,		DIRECT,	".lsym",
39029831Ssam 
39129831Ssam 	ISTAB,		DIRECT,	".stab",
39229831Ssam 	ISTABSTR,	DIRECT,	".stabstr",
39329831Ssam 	ISTABNONE,	DIRECT,	".stabnone",
39429831Ssam 	ISTABDOT,	DIRECT,	".stabdot",
39529831Ssam 
39629831Ssam 	IFILE,		DIRECT,	".file",
39729831Ssam 	ILINENO,	DIRECT,	".lineno",
39829831Ssam 	IABORT,		DIRECT,	".abort",
39929831Ssam 
40029831Ssam 	IJXXX,		INSTR,	"jump pseudo",
40129831Ssam 	INST0,		INSTR,	"0 argument inst",
40229831Ssam 	INSTn,		INSTR,	"n argument inst",
40329831Ssam 
40429831Ssam 	PARSEEOF,	CNTRL,	"parse end of file",
40529831Ssam 	ILINESKIP,	CNTRL,	"skip lines",
40629831Ssam 	VOID,		CNTRL,	"void",
40729831Ssam 	SKIP,		CNTRL,	"skip",
40829831Ssam 	NL,		CNTRL,	"new line",
40929831Ssam 	SCANEOF,	CNTRL,	"scanner end of file",
41029831Ssam 	BADCHAR,	CNTRL,	"bad character",
41129831Ssam 	SH,		CNTRL,	"comment, #",
41229831Ssam 
41329831Ssam 	INT,		HUNK,	"int",
41429831Ssam 	BFINT,		HUNK,	"local label",
41529831Ssam 	BIGNUM,		HUNK,	"big number",
41629831Ssam 	NAME,		HUNK,	"name",
41729831Ssam 	STRING,		HUNK,	"string",
41829831Ssam 	REG,		HUNK,	"register specifier",
41929831Ssam 
42029831Ssam 	SIZESPEC,	SMALL,	"size specifier, [BWLbwl]",
42129831Ssam 	SIZEQUOTE,	SMALL,	"sizequote, [^']",
42229831Ssam 	LITOP,		SMALL,	"litop",
42329831Ssam 
42429831Ssam 	MP,		SMALL,	"minus parenthesis, -(",
42529831Ssam 	REGOP,		SMALL,	"register operator, %",
42629831Ssam 
42729831Ssam 	SP,		SMALL,	"space",
42829831Ssam 	ALPH,		SMALL,	"alphabetic character, [A-Za-z_]",
42929831Ssam 	DIG,		SMALL,	"digit character, [A-Fa-f0-9]",
43029831Ssam 
43129831Ssam 	SQ,		SMALL,	"single quote, '",
43229831Ssam 	DQ,		SMALL,	"double quote, \"",
43329831Ssam 
43429831Ssam 	LSH,		SMALL,	"arithmetic left shift, <",
43529831Ssam 	RSH,		SMALL,	"arithmetic right shift, >",
43629831Ssam 	XOR,		SMALL,	"exclusive or, ^",
43729831Ssam 
43829831Ssam 	PLUS,		SMALL,	"plus, +",
43929831Ssam 	MINUS,		SMALL,	"minus, -",
44029831Ssam 	MUL,		SMALL,	"multiply, *",
44129831Ssam 	DIV,		SMALL,	"divide, /",
44229831Ssam 	SEMI,		SMALL,	"semi colon, ;",
44329831Ssam 	COLON,		SMALL,	"colon, :",
44429831Ssam 	IOR,		SMALL,	"inclusive or, |",
44529831Ssam 	AND,		SMALL,	"and, &",
44629831Ssam 
44729831Ssam 	TILDE,		SMALL,	"one's complement, ~",
44829831Ssam 	ORNOT,		SMALL,	"ornot, !",
44929831Ssam 	CM,		SMALL,	"comma",
45029831Ssam 
45129831Ssam 	LB,		SMALL,	"left bracket, [",
45229831Ssam 	RB,		SMALL,	"right bracket, ]",
45329831Ssam 	LP,		SMALL,	"left parenthesis, (",
45429831Ssam 	RP,		SMALL,	"right parentheis, )",
45529831Ssam 
45629831Ssam 	LASTTOKEN,	SMALL,	"last token",
45729831Ssam };
45829831Ssam /*
45929831Ssam  *	turn a token type into a string
46029831Ssam  */
tok_to_name(token)46129831Ssam char *tok_to_name(token)
46229831Ssam {
46329831Ssam 	static	int	fixed = 0;
46429831Ssam 	static	char	buf[64];
46529831Ssam 	static	struct	Tok_Desc 	NA = {0, (char *)0, "NOT ASSIGNED"};
46629831Ssam 		int	i;
46729831Ssam 
46829831Ssam 	if (!fixed){
46929831Ssam 		for (i = FIRSTTOKEN; i <= LASTTOKEN; i++)
47029831Ssam 			tok_name[i] = &NA;
47129831Ssam 		for (i = 0; i <= sizeof(tok_desc)/sizeof(struct Tok_Desc); i++){
47229831Ssam 			tok_name[tok_desc[i].tok_which] = &tok_desc[i];
47329831Ssam 		}
47429831Ssam 		fixed = 1;
47529831Ssam 	}
47629831Ssam 	if (FIRSTTOKEN <= token && token <= LASTTOKEN){
477*32433Sbostic 		(void)sprintf(buf, "%s %s", tok_name[token]->tok_kind,
47829831Ssam 			tok_name[token]->tok_name);
47929831Ssam 		return(buf);
48029831Ssam 	} else {
48129831Ssam 		panic("Unknown token number, %d\n", token);
48229831Ssam 		/*NOTREACHED*/
48329831Ssam 	}
48429831Ssam }
485