BSD 4_3_Tahoe development
[unix-history] / usr / src / bin / as / as.tahoe / asparse.c
/*
* Copyright (c) 1982 Regents of the University of California
*/
#ifndef lint
static char sccsid[] = "$W$ (Berkeley) 5/31/88";
#endif not lint
#include <stdio.h>
#include "as.h"
#include "asscan.h"
#include "assyms.h"
#include "asexpr.h"
int lgensym[10];
char genref[10];
long bitfield;
int bitoff;
int curlen; /* current length of literals */
int printblank;
/*
* The following three variables are communication between various
* modules to special case a number of things. They are properly
* categorized as hacks.
*/
extern struct symtab *lastnam;/*last name seen by the lexical analyzer*/
int exprisname; /*last factor in an expression was a name*/
int droppedLP; /*one is analyzing an expression beginning with*/
/*a left parenthesis, which has already been*/
/*shifted. (Used to parse (<expr>)(rn)*/
char yytext[NCPName+2]; /*the lexical image*/
int yylval; /*the lexical value; sloppy typing*/
u_char yyopcode; /* lexical value for an opcode */
Bignum yybignum; /* lexical value for a big number */
int num_type; /* type of bignums */
/*
* Expression and argument managers
*/
struct exp *xp; /*next free expression slot, used by expr.c*/
struct exp explist[NEXP]; /*max of 20 expressions in one opcode*/
struct arg arglist[NARG]; /*building up operands in instructions*/
/*
* Sets to accelerate token discrimination
*/
char tokensets[(LASTTOKEN) - (FIRSTTOKEN) + 1];
static char UDotsname[64]; /*name of the assembly source*/
yyparse()
{
reg struct exp *locxp;
/*
* loc1xp and ptrloc1xp are used in the
* expression lookahead
*/
struct exp *loc1xp; /*must be non register*/
struct exp **ptrloc1xp = & loc1xp;
struct exp *pval; /*hacking expr:expr*/
reg struct symtab *np;
reg int argcnt;
reg inttoktype val; /*what yylex gives*/
reg inttoktype auxval; /*saves val*/
reg struct arg *ap; /*first free argument*/
reg struct symtab *p;
reg struct symtab *stpt;
struct strdesc *stringp; /*handles string lists*/
int regno; /*handles arguments*/
int *ptrregno = &regno;
int sawmul; /*saw * */
int sawindex; /*saw [rn]*/
int sawsize;
int seg_type; /*the kind of segment: data or text*/
int seg_number; /*the segment number*/
int space_value; /*how much .space needs*/
int fill_rep; /*how many reps for .fill */
int rep_fill; /*the same - temprary */
int fill_size; /*how many bytes for .fill */
int field_width; /*how wide a field is to be*/
int field_value; /*the value to stuff in a field*/
char *stabname; /*name of stab dealing with*/
ptrall stabstart; /*where the stab starts in the buffer*/
int reloc_how; /* how to relocate expressions */
int incasetable; /* set if in a case table */
int j, k;
char ch;
int length; /* for printout */
union twolong
{
long lpart[2];
char strpart [8];
}fillval;
incasetable = 0;
xp = explist;
ap = arglist;
val = yylex();
while (val != PARSEEOF){ /* primary loop */
while (INTOKSET(val, LINSTBEGIN)){
if (val == INT) {
int i = ((struct exp *)yylval)->e_xvalue;
shift;
if (val != COLON){
yyerror("Local label %d is not followed by a ':' for a label definition",
i);
goto errorfix;
}
if (i < 0 || i > 9) {
yyerror("Local labels are 0-9");
goto errorfix;
}
(void)sprintf(yytext, "L%d\001%d", i, lgensym[i]);
lgensym[i]++;
genref[i] = 0;
yylval = (int)*lookup(passno == 1);
val = NAME;
np = (struct symtab *)yylval;
goto restlab;
}
if (val == NL){
lineno++;
if (liston && (passno == 2) && (! endofsource))
{
/* printing previous line & layout */
length = strlen (layout);
fprintf (listfile, "%*.*s", LHEAD, LHEAD, layout);
if (length <= LHEAD+LLEN)
j = LLEN;
else { /* break line at last blank */
j = LHEAD+LLEN;
while(j>LHEAD && layout[j]!= ' ')
j--;
if(j == LHEAD)
j = LLEN;
else
j -= LHEAD;
}
k = LHEAD+j;
fprintf (listfile, "%-*.*s", LLEN, j, &layout[LHEAD]);
fprintf (listfile, " ");
do {
ch = getc (source);
putc (ch, listfile);
} while (ch != '\n');
while (k < length)
{
fprintf (listfile, "%*s", LHEAD, "");
/* break line at last blank */
if(layout[k] == ' ')
k++;
if((j = k+LLEN) >= length)
j = length;
else
while(j>k && layout[j]!= ' ')
j--;
if(j == k)
j = LLEN;
else
j -= k;
fprintf (listfile, "%-*.*s\n", j, j, &layout[k]);
k += j;
}
k = 0;
while (layout[k] != '\0')
layout[k++] = '\0';
ch = getc (source);
if (ch == EOF)
{
if (ind == ninfiles)
endofsource = 1;
else
{
source = fopen (innames[ind++], "r");
lineno = 1;
}
}
else
ungetc (ch, source);
layoutpos = layout;
(void)sprintf (layoutpos, "%4ld ", lineno);
layoutpos += 6;
long_out (dotp->e_xvalue);
if (dotp->e_xvalue >= datbase)
(void)sprintf (layoutpos," * ");
else
(void)sprintf (layoutpos," ");
layoutpos += 4;
}
shift;
} else
if (val == SEMI)
shift;
else { /*its a name, so we have a label or def */
if (val != NAME){
ERROR("Name expected for a label");
}
np = (struct symtab *)yylval;
shiftover(NAME);
if (val != COLON) {
yyerror("\"%s\" is not followed by a ':' for a label definition",
FETCHNAME(np));
goto errorfix;
}
restlab:
shift;
flushfield(NBPW/4);
if ((np->s_type&XTYPE)!=XUNDEF) {
if( (np->s_type&XTYPE)!=dotp->e_xtype
|| np->s_value!=dotp->e_xvalue
|| ( (passno==1)
&&(np->s_index != dotp->e_xloc)
)
){
#ifndef DEBUG
if (FETCHNAME(np)[0] != 'L')
#endif not DEBUG
{
if (passno == 1)
yyerror("%s redefined",
FETCHNAME(np));
else
yyerror("%s redefined: PHASE ERROR, 1st: %d, 2nd: %d",
FETCHNAME(np),
np->s_value,
dotp->e_xvalue);
}
}
}
np->s_type &= ~(XTYPE|XFORW);
np->s_type |= dotp->e_xtype;
np->s_value = dotp->e_xvalue;
if (passno == 1){
np->s_index = dotp-usedot;
if (FETCHNAME(np)[0] == 'L'){
nlabels++;
}
np->s_tag = LABELID;
}
} /*end of this being a label*/
} /*end of to consuming all labels, NLs and SEMIS */
xp = explist;
ap = arglist;
/*
* process the INSTRUCTION body
*/
switch(val){
default:
ERROR("Unrecognized instruction or directive");
case IABORT:
shift;
sawabort();
/*NOTREACHED*/
break;
case PARSEEOF:
tokptr -= sizeof(bytetoktype);
*tokptr++ = VOID;
tokptr[1] = VOID;
tokptr[2] = PARSEEOF;
break;
case IFILE:
shift;
stringp = (struct strdesc *)yylval;
shiftover(STRING);
dotsname = &UDotsname[0];
movestr(dotsname, stringp->sd_string,
min(stringp->sd_strlen, sizeof(UDotsname)));
break;
case ILINENO:
shift; /*over the ILINENO*/
expr(locxp, val);
lineno = locxp->e_xvalue;
break;
case ISET: /* .set <name> , <expr> */
shift;
np = (struct symtab *)yylval;
shiftover(NAME);
shiftover(CM);
expr(locxp, val);
np->s_type &= (XXTRN|XFORW);
np->s_type |= locxp->e_xtype&(XTYPE|XFORW);
np->s_value = locxp->e_xvalue;
if (passno==1)
np->s_index = locxp->e_xloc;
if ((locxp->e_xtype&XTYPE) == XUNDEF)
yyerror("Illegal set?");
break;
case ILSYM: /*.lsym name , expr */
shift;
np = (struct symtab *)yylval;
shiftover(NAME);
shiftover(CM);
expr(locxp, val);
/*
* Build the unique occurance of the
* symbol.
* The character scanner will have
* already entered it into the symbol
* table, but we should remove it
*/
if (passno == 1){
stpt = (struct symtab *)symalloc();
stpt->s_name = np->s_name;
np->s_tag = OBSOLETE; /*invalidate original */
nforgotten++;
np = stpt;
if ( (locxp->e_xtype & XTYPE) != XABS)
yyerror("Illegal second argument to lsym");
np->s_value = locxp->e_xvalue;
np->s_type = XABS;
np->s_tag = ILSYM;
}
break;
case IGLOBAL: /*.globl <name> */
shift;
np = (struct symtab *)yylval;
shiftover(NAME);
np->s_type |= XXTRN;
break;
case IDATA: /*.data [ <expr> ] */
case ITEXT: /*.text [ <expr> ] */
incasetable = 0;
seg_type = -val;
shift;
if (INTOKSET(val, EBEGOPS+YUKKYEXPRBEG+SAFEEXPRBEG)){
expr(locxp, val);
seg_type = -seg_type; /*now, it is positive*/
}
if (seg_type < 0) { /*there wasn't an associated expr*/
seg_number = 0;
seg_type = -seg_type;
} else {
if ( ((locxp->e_xtype & XTYPE) != XABS) /* tekmdp */
|| (seg_number = locxp->e_xvalue) >= NLOC) {
yyerror("illegal location counter");
seg_number = 0;
}
}
if (seg_type == IDATA)
seg_number += NLOC;
flushfield(NBPW/4);
dotp = &usedot[seg_number];
if (passno==2) { /* go salt away in pass 2*/
txtfil = usefile[seg_number];
relfil = rusefile[seg_number];
}
break;
/*
* Storage filler directives:
*
* .byte [<exprlist>]
*
* exprlist: empty | exprlist outexpr
* outexpr: <expr> | <expr> : <expr>
*/
case IBYTE: curlen = NBPW/4; goto elist;
case IWORD: curlen = NBPW/2; goto elist;
case IINT: curlen = NBPW; goto elist;
case ILONG: curlen = NBPW; goto elist;
elist:
seg_type = val;
shift;
/*
* Expression List processing
*/
if (INTOKSET(val, EBEGOPS+YUKKYEXPRBEG+SAFEEXPRBEG)){
do{
/*
* expression list consists of a list of :
* <expr>
* <expr> : <expr>
* (pack expr2 into expr1 bits
*/
expr(locxp, val);
/*
* now, pointing at the next token
*/
/* if (val == COLON){ */
/* shiftover(COLON); */
/* expr(pval, val); */
/* if ((locxp->e_xtype & XTYPE) != XABS) */
/* yyerror("Width not absolute"); */
/* field_width = locxp->e_xvalue; */
/* locxp = pval; */
/* if (bitoff + field_width > curlen) */
/* flushfield(curlen); */
/* if (field_width > curlen) */
/* yyerror("Expression crosses field boundary"); */
/* } else { */
field_width = curlen;
if (bitoff == 0) printblank = 0;
else printblank = 1;
flushfield(curlen);
if (liston && (passno == 2) && printblank)
*layoutpos++ = ' ';
/* } */
if ((locxp->e_xtype & XTYPE) != XABS) {
if (bitoff)
yyerror("Illegal relocation in field");
switch(curlen){
case NBPW/4: reloc_how = TYPB; break;
case NBPW/2: reloc_how = TYPW; break;
case NBPW: reloc_how = TYPL; break;
}
if (passno == 1){
dotp->e_xvalue += ty_nbyte[reloc_how];
} else {
outrel(locxp, reloc_how);
if (liston)
*layoutpos++ = ' ';
}
} else {
/*
*
* See if we are doing a case instruction.
* If so, then see if the branch distance,
* stored as a word,
* is going to loose sig bits.
*/
if (passno == 2 && incasetable){
if ( !(ISWORD(locxp->e_xvalue)))
yyerror("Case will branch too far");
}
field_value = locxp->e_xvalue & ( (1L << field_width)-1);
bitfield |= field_value << bitoff;
bitoff += field_width;
}
xp = explist;
if (auxval = (val == CM))
shift;
} while (auxval);
} /* there existed an expression at all */
flushfield(curlen);
if ( ( curlen == NBPW/4) && bitoff)
dotp->e_xvalue ++;
break;
/*end of case IBYTE, IWORD, ILONG, IINT*/
case ISPACE: /* .space <expr> */
shift;
expr(locxp, val);
if ((locxp->e_xtype & XTYPE) != XABS) /* tekmdp */
yyerror("Space size not absolute");
if (locxp->e_xvalue < 0)
yyerror("Space size not positive");
space_value = locxp->e_xvalue;
ospace:
flushfield(NBPW/4);
{
static char spacebuf[128];
while (space_value > sizeof(spacebuf)){
outs(spacebuf, sizeof(spacebuf));
space_value -= sizeof(spacebuf);
}
outs(spacebuf, space_value);
}
if (liston && (passno == 2))
(void)sprintf (layoutpos, "****");
break;
/*
* .fill rep, size, value
* repeat rep times: fill size bytes with (truncated) value
* size must be between 1 and 8
*/
case IFILL:
shift;
expr(locxp, val);
if ( (locxp->e_xtype & XTYPE) != XABS) /* tekmdp */
yyerror("Fill repetition count not absolute");
rep_fill = fill_rep = locxp->e_xvalue;
shiftover(CM);
expr(locxp, val);
if ( (locxp->e_xtype & XTYPE) != XABS) /* tekmdp */
yyerror("Fill size not absolute");
fill_size = locxp->e_xvalue;
if (fill_size <= 0 || fill_size > 8)
yyerror("Fill count not in in 1..8");
shiftover(CM);
expr(locxp, val);
if (passno == 2 && (locxp->e_xtype & XTYPE) != XABS) /* tekmdp */
yyerror("Fill value not absolute");
flushfield(NBPW/4);
dotp->e_xvalue += fill_rep * fill_size;
if (passno == 1) {
locxp->e_xvalue += fill_rep * fill_size;
} else {
fillval.lpart[0] = locxp->e_yvalue;
fillval.lpart[1] = locxp->e_xvalue;
while (fill_rep-- > 0)
bwrite(&(fillval.strpart[8-fill_size]),fill_size,txtfil);
if (liston) {
while (rep_fill-- > 0)
{
switch (fill_size)
{
case 1:
byte_out (locxp->e_xvalue);
*layoutpos++ = ' ';
break;
case 2:
word_out (locxp->e_xvalue);
*layoutpos++ = ' ';
break;
case 3:
byte_out (locxp->e_xvalue >> 16);
byte_out (locxp->e_xvalue >> 8);
byte_out (locxp->e_xvalue);
*layoutpos++ = ' ';
break;
case 4:
long_out (locxp->e_xvalue);
*layoutpos++ = ' ';
break;
case 5:
byte_out (locxp->e_yvalue);
long_out (locxp->e_xvalue);
*layoutpos++ = ' ';
break;
case 6:
word_out (locxp->e_yvalue);
long_out (locxp->e_xvalue);
*layoutpos++ = ' ';
break;
case 7:
byte_out (locxp->e_yvalue >> 16);
byte_out (locxp->e_yvalue >> 8);
byte_out (locxp->e_yvalue);
long_out (locxp->e_xvalue);
*layoutpos++ = ' ';
break;
case 8:
long_out (locxp->e_yvalue);
long_out (locxp->e_xvalue);
*layoutpos++ = ' ';
break;
}
}
}
}
break;
case IASCII: /* .ascii [ <stringlist> ] */
case IASCIZ: /* .asciz [ <stringlist> ] */
auxval = val;
shift;
/*
* Code to consume a string list
*
* stringlist: empty | STRING | stringlist STRING
*/
while (val == STRING){
int mystrlen;
flushfield(NBPW/4);
if (bitoff)
dotp->e_xvalue++;
stringp = (struct strdesc *)yylval;
/*
* utilize the string scanner cheat;
* the scanner appended a null byte on the string,
* but didn't charge it to sd_strlen
*/
mystrlen = stringp->sd_strlen;
mystrlen += (auxval == IASCIZ) ? 1 : 0;
if (passno == 2){
if (stringp->sd_place & STR_CORE){
outs(stringp->sd_string, mystrlen);
if (liston)
{
int i;
for (i = 0;i < mystrlen; i++)
{
(void)sprintf (layoutpos, "%02x",
stringp->sd_string[i]);
layoutpos += 2;
}
}
} else {
int i, nread;
fseek(strfile, stringp->sd_stroff, 0);
for (i = 0; i < mystrlen;/*VOID*/){
nread = fread(yytext, 1,
min(mystrlen - i,
sizeof(yytext)), strfile);
outs(yytext, nread);
if (liston)
{
int k;
for (k = 0;k < nread; k++)
{
(void)sprintf (layoutpos,
"%02x", yytext[k]);
layoutpos += 2;
}
}
i += nread;
}
}
} else {
dotp->e_xvalue += mystrlen;
}
shift; /*over the STRING*/
if (val == CM) /*could be a split string*/
shift;
}
break;
case IORG: /* .org <expr> */
shift;
expr(locxp, val);
if ((locxp->e_xtype & XTYPE) == XABS) /* tekmdp */
orgwarn++;
else if ((locxp->e_xtype & ~XXTRN) != dotp->e_xtype)
yyerror("Illegal expression to set origin");
if ((unsigned)locxp->e_xvalue < (unsigned)dotp->e_xvalue)
{
ERROR("Backwards 'org'");
}
space_value = locxp->e_xvalue - dotp->e_xvalue;
goto ospace;
break;
/*
*
* Process stabs. Stabs are created only by the f77
* and the C compiler with the -g flag set.
* We only look at the stab ONCE, during pass 1, and
* virtually remove the stab from the intermediate file
* so it isn't seen during pass2. This makes for some
* hairy processing to handle labels occuring in
* stab entries, but since most expressions in the
* stab are integral we save lots of time in the second
* pass by not looking at the stabs.
* A stab that is tagged floating will be bumped during
* the jxxx resolution phase. A stab tagged fixed will
* not be be bumped.
*
* .stab: Old fashioned stabs
* .stabn: For stabs without names
* .stabs: For stabs with string names
* .stabd: For stabs for line numbers or bracketing,
* without a string name, without
* a final expression. The value of the
* final expression is taken to be the current
* location counter, and is patched by the 2nd pass
*
* .stab{<expr>,}*NCPName,<expr>, <expr>, <expr>, <expr>
* .stabn <expr>, <expr>, <expr>, <expr>
* .stabs STRING, <expr>, <expr>, <expr>, <expr>
* .stabd <expr>, <expr>, <expr> # .
*/
case ISTAB:
yyerror(".stab directive no longer supported");
goto errorfix;
tailstab:
expr(locxp, val);
if (! (locxp->e_xvalue & STABTYPS)){
yyerror("Invalid type in %s", stabname);
goto errorfix;
}
stpt->s_ptype = locxp->e_xvalue;
shiftover(CM);
expr(locxp, val);
stpt->s_other = locxp->e_xvalue;
shiftover(CM);
expr(locxp, val);
stpt->s_desc = locxp->e_xvalue;
shiftover(CM);
exprisname = 0;
expr(locxp, val);
p = locxp->e_xname;
if (p == NULL) { /*absolute expr to begin with*/
stpt->s_value = locxp->e_xvalue;
stpt->s_index = dotp - usedot;
if (exprisname){
stpt->s_type = locxp->e_xtype;
switch(stpt->s_ptype){
case N_LCSYM:
stpt->s_dest = (struct symtab *)exprisname;
stpt->s_type |= STABFLAG;
case N_GSYM:
case N_FNAME:
case N_RSYM:
case N_SSYM:
case N_LSYM:
case N_PSYM:
case N_BCOMM:
case N_ECOMM:
case N_LENG:
stpt->s_tag = STABFIXED;
break;
default:
stpt->s_tag = STABFLOATING;
break;
}
} else
stpt->s_tag = STABFIXED;
}
else { /*really have a name*/
stpt->s_dest = locxp->e_xname;
stpt->s_index = p->s_index;
stpt->s_type = p->s_type | STABFLAG;
/*
* We will assign a more accruate
* guess of locxp's location when
* we sort the symbol table
* The final value of value is
* given by stabfix()
*/
/*
* For exprs of the form (name + value) one needs to remember locxp->e_xvalue
* for use in stabfix. The right place to keep this is in stpt->s_value
* however this gets corrupted at an unknown point.
* As a bandaid hack the value is preserved in s_desc and s_other (a
* short and a char). This destroys these two values and will
* be fixed. May 19 ,1983 Alastair Fyfe
*/
if(locxp->e_xvalue) {
stpt->s_other = (locxp->e_xvalue >> 16);
stpt->s_desc = (locxp->e_xvalue & 0x0000ffff);
stpt->s_tag = STABFLOATING;
}
}
/*
* tokptr now points at one token beyond
* the current token stored in val and yylval,
* which are the next tokens after the end of
* this .stab directive. This next token must
* be either a SEMI or NL, so is of width just
* one. Therefore, to point to the next token
* after the end of this stab, just back up one..
*/
buildskip(stabstart, (bytetoktype *)tokptr - sizeof(bytetoktype));
break; /*end of the .stab*/
case ISTABDOT:
stabname = ".stabd";
stpt = (struct symtab *)yylval;
/*
* We clobber everything after the
* .stabd and its pointer... we MUST
* be able to get back to this .stabd
* so that we can resolve its final value
*/
stabstart = tokptr;
shift; /*over the ISTABDOT*/
if (passno == 1){
expr(locxp, val);
if (! (locxp->e_xvalue & STABTYPS)){
yyerror("Invalid type in .stabd");
goto errorfix;
}
stpt->s_ptype = locxp->e_xvalue;
shiftover(CM);
expr(locxp, val);
stpt->s_other = locxp->e_xvalue;
shiftover(CM);
expr(locxp, val);
stpt->s_desc = locxp->e_xvalue;
/*
*
* Now, clobber everything but the
* .stabd pseudo and the pointer
* to its symbol table entry
* tokptr points to the next token,
* build the skip up to this
*/
buildskip(stabstart, (bytetoktype *)tokptr - sizeof(bytetoktype));
}
/*
* pass 1: Assign a good guess for its position
* (ensures they are sorted into right place)/
* pass 2: Fix the actual value
*/
stpt->s_value = dotp->e_xvalue;
stpt->s_index = dotp - usedot;
stpt->s_tag = STABFLOATING; /*although it has no effect in pass 2*/
break;
case ISTABNONE: stabname = ".stabn"; goto shortstab;
case ISTABSTR: stabname = ".stabs";
shortstab:
auxval = val;
if (passno == 2) goto errorfix;
stpt = (struct symtab *)yylval;
stabstart = tokptr;
(bytetoktype *)stabstart -= sizeof(struct symtab *);
(bytetoktype *)stabstart -= sizeof(bytetoktype);
shift;
if (auxval == ISTABSTR){
stringp = (struct strdesc *)yylval;
shiftover(STRING);
stpt->s_name = (char *)stringp;
/*
* We want the trailing null included in this string.
* We utilize the cheat the string scanner used,
* and merely increment the string length
*/
stringp->sd_strlen += 1;
shiftover(CM);
} else {
stpt->s_name = (char *)savestr("\0", 0, STR_BOTH);
}
goto tailstab;
break;
case ICOMM: /* .comm <name> , <expr> */
case ILCOMM: /* .lcomm <name> , <expr> */
auxval = val;
shift;
np = (struct symtab *)yylval;
shiftover(NAME);
shiftover(CM);
expr(locxp, val);
if ( (locxp->e_xtype & XTYPE) != XABS) /* tekmdp */
yyerror("comm size not absolute");
if (passno == 1 && (np->s_type&XTYPE) != XUNDEF)
yyerror("Redefinition of %s", FETCHNAME(np));
if (passno==1) {
np->s_value = locxp->e_xvalue;
if (auxval == ICOMM)
np->s_type |= XXTRN;
else {
np->s_type &= ~XTYPE;
np->s_type |= XBSS;
}
}
break;
case IALIGN: /* .align <expr> */
stpt = (struct symtab *)yylval;
shift;
expr(locxp, val);
if ((dotp->e_xtype & XTYPE) == XDATA)
djalign(locxp, stpt);
else
jalign(locxp, stpt);
break;
case INST0: /* instructions w/o arguments*/
incasetable = 0;
insout(yyopcode, (struct arg *)0, 0);
shift;
break;
case INSTn: /* instructions with arguments*/
case IJXXX: /* UNIX style jump instructions */
auxval = val;
/*
* Code to process an argument list
*/
ap = arglist;
xp = explist;
shift; /* bring in the first token for the arg list*/
for (argcnt = 1; argcnt <= 6; argcnt++, ap++){
/*
* code to process an argument proper
*/
sawindex = sawmul = sawsize = 0;
{
switch(val) {
default:
disp:
if( !(INTOKSET(val,
EBEGOPS
+YUKKYEXPRBEG
+SAFEEXPRBEG)) ) {
ERROR("expression expected");
}
expr(ap->a_xp,val);
overdisp:
if ( val == LP || sawsize){
shiftover(LP);
findreg(regno);
shiftover(RP);
ap->a_atype = ADISP;
ap->a_areg1 = regno;
} else {
ap->a_atype = AEXP;
ap->a_areg1 = 0;
}
goto index;
case SIZESPEC:
sizespec:
sawsize = yylval;
shift;
goto disp;
case REG:
case REGOP:
findreg(regno);
ap->a_atype = AREG;
ap->a_areg1 = regno;
break;
case MUL:
sawmul = 1;
shift;
if (val == LP) goto base;
if (val == LITOP) goto imm;
if (val == SIZESPEC) goto sizespec;
if (INTOKSET(val,
EBEGOPS
+YUKKYEXPRBEG
+SAFEEXPRBEG)) goto disp;
ERROR("expression, '(' or '$' expected");
break;
case LP:
base:
shift; /*consume the LP*/
/*
* hack the ambiguity of
* movl (expr) (rn), ...
* note that (expr) could also
* be (rn) (by special hole in the
* grammar), which we ensure
* means register indirection, instead
* of an expression with value n
*/
if (val != REG && val != REGOP){
droppedLP = 1;
val = exprparse(val, &(ap->a_xp));
droppedLP = 0;
goto overdisp;
}
findreg(regno);
shiftover(RP);
if (val == PLUS){
shift;
ap->a_atype = AINCR;
if (sawmul && regno != 0xE)
yyerror ("Autoincrement deferred register must be SP");
if (!(sawmul || regno == 0xE))
yyerror ("Autoincrement register must be SP");
} else
ap->a_atype = ABASE;
ap->a_areg1 = regno;
goto index;
case LITOP:
imm:
shift;
expr(locxp, val);
ap->a_atype = AIMM;
ap->a_areg1 = 0;
ap->a_xp = locxp;
goto index;
case MP:
shift; /* -(reg) */
findreg(regno);
if (regno != 0xE)
yyerror ("Autodecrement register must be SP");
shiftover(RP);
ap->a_atype = ADECR;
ap->a_areg1 = regno;
index: /*look for [reg] */
if (val == LB){
shift;
findreg(regno);
shiftover(RB);
sawindex = 1;
ap->a_areg2 = regno;
}
break;
} /*end of the switch to process an arg*/
} /*end of processing an argument*/
if (sawmul){
/*
* Make a concession for *(%r)
* meaning *0(%r)
*/
if (ap->a_atype == ABASE) {
ap->a_atype = ADISP;
xp->e_xtype = XABS;
xp->e_number = Znumber;
xp->e_number.num_tag = TYPL;
xp->e_xloc = 0;
ap->a_xp = xp++;
}
ap->a_atype |= ASTAR;
sawmul = 0;
}
if (sawindex){
ap->a_atype |= AINDX;
sawindex = 0;
}
ap->a_dispsize = sawsize == 0 ? d124 : sawsize;
if (val != CM) break;
shiftover(CM);
} /*processing all the arguments*/
if (argcnt > 6){
yyerror("More than 6 arguments");
goto errorfix;
}
/*
* See if this is a case instruction,
* so we can set up tests on the following
* vector of branch displacements
*/
if (yyopcode == 0xfc) /* 'casel' instruction */
incasetable++;
else
incasetable = 0;
insout(yyopcode, arglist,
auxval == INSTn ? argcnt : - argcnt);
break;
case IQUAD: num_type = TYPQ; goto bignumlist;
case IFFLOAT: num_type = TYPF; goto bignumlist;
case IDFLOAT: num_type = TYPD;
bignumlist:
/*
* eat a list of non 32 bit numbers.
* IQUAD can, possibly, return
* INT's, if the numbers are "small".
*
* The value of the numbers is coming back
* as an expression, NOT in yybignum.
*/
shift; /* over the opener */
if ((val == BIGNUM) || (val == INT)){
do{
if ((val != BIGNUM) && (val != INT)){
ERROR(ty_float[num_type]
? "floating number expected"
: "integer number expected" );
}
dotp->e_xvalue += ty_nbyte[num_type];
if (passno == 2){
switch (num_type) {
case TYPF:
bwrite(((struct exp *)yylval)->e_number.num_num.numFf_float.Ff_ulong,
ty_nbyte[num_type], txtfil);
if (liston)
{
long_out(((struct exp *)yylval)->e_number.num_num.numFf_float.Ff_ulong[0]);
*layoutpos++ = ' ';
}
break;
case TYPD:
bwrite(&((struct exp *)yylval)->e_number.num_num.numFd_float.Fd_ulong[0],
sizeof (long), txtfil);
bwrite(&((struct exp *)yylval)->e_number.num_num.numFd_float.Fd_ulong[1],
sizeof (long), txtfil);
if (liston)
{
long_out(((struct exp *)yylval)->e_number.num_num.numIq_int.Iq_ulong[0]);
long_out(((struct exp *)yylval)->e_number.num_num.numIq_int.Iq_ulong[1]);
*layoutpos++ = ' ';
}
break;
case TYPQ:
bwrite(&((struct exp *)yylval)->e_number.num_num.numIq_int.Iq_ulong[1],
sizeof (long), txtfil);
bwrite(&((struct exp *)yylval)->e_number.num_num.numIq_int.Iq_ulong[0],
sizeof (long), txtfil);
if (liston)
{
long_out(((struct exp *)yylval)->e_number.num_num.numIq_int.Iq_ulong[1]);
long_out(((struct exp *)yylval)->e_number.num_num.numIq_int.Iq_ulong[0]);
*layoutpos++ = ' ';
}
break;
}
}
xp = explist;
shift; /* over this number */
if (auxval = (val == CM))
shift; /* over the comma */
} while (auxval); /* as long as there are commas */
}
break;
/* end of the case for initialized big numbers */
} /*end of the switch for looking at each reserved word*/
continue;
errorfix:
/*
* got here by either requesting to skip to the
* end of this statement, or by erroring out and
* wanting to apply panic mode recovery
*/
while ( (val != NL)
&& (val != SEMI)
&& (val != PARSEEOF)
){
shift;
}
if (val == NL)
lineno++;
shift;
} /*end of the loop to read the entire file, line by line*/
} /*end of yyparse*/
/*
* Process a register declaration of the form
* % <expr>
*
* Note:
* The scanner has already processed funny registers of the form
* %dd[+-]*, where dd is a decimal number in the range 00 to 15 (optional
* preceding zero digit). If there was any space between the % and
* the digit, the scanner wouldn't have recognized it, so we
* hack it out here.
*/
inttoktype funnyreg(val, regnoback) /*what the read head will sit on*/
inttoktype val; /*what the read head is sitting on*/
int *regnoback; /*call by return*/
{
reg struct exp *locxp;
struct exp *loc1xp;
struct exp **ptrloc1xp = & loc1xp;
expr(locxp, val); /*and leave the current read head with value*/
if ( (passno == 2) &&
( (locxp->e_xtype & XTYPE) != XABS
|| (locxp->e_xvalue < 0)
|| (locxp->e_xvalue >= 16)
)
){
yyerror("Illegal register");
return(0);
}
*regnoback = locxp->e_xvalue;
return(val);
}
/*
* Shift over error
*/
shiftoerror(token)
int token;
{
char *tok_to_name();
yyerror("%s expected", tok_to_name(token));
}
/*VARARGS1*/
yyerror(s, a1, a2,a3,a4,a5)
char *s;
{
#define sink stdout
if (anyerrs == 0 && anywarnings == 0 && ! silent)
fprintf(sink, "Assembler:\n");
anyerrs++;
if (silent)
return;
fprintf(sink, "\"%s\", line %d: ", dotsname, lineno);
fprintf(sink, s, a1, a2,a3,a4,a5);
fprintf(sink, "\n");
#undef sink
}
/*VARARGS1*/
yywarning(s, a1, a2,a3,a4,a5)
char *s;
{
#define sink stdout
if (anyerrs == 0 && anywarnings == 0 && ! silent)
fprintf(sink, "Assembler:\n");
anywarnings++;
if (silent)
return;
fprintf(sink, "\"%s\", line %d: WARNING: ", dotsname, lineno);
fprintf(sink, s, a1, a2,a3,a4,a5);
fprintf(sink, "\n");
#undef sink
}