* Copyright (c) 1982 Regents of the University of California
static char sccsid
[] = "@(#)asparse.c 4.17 %G%";
int curlen
; /* current length of literals */
* The following three variables are communication between various
* modules to special case a number of things. They are properly
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*/
struct Opcode yyopcode
; /* lexical value for an opcode */
Bignum yybignum
; /* lexical value for a big number */
* 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*/
* loc1xp and ptrloc1xp are used in the
struct exp
*loc1xp
; /*must be non register*/
struct exp
**ptrloc1xp
= & loc1xp
;
struct exp
*pval
; /*hacking expr:expr*/
reg inttoktype val
; /*what yylex gives*/
reg inttoktype auxval
; /*saves val*/
reg
struct arg
*ap
; /*first free argument*/
struct strdesc
*stringp
; /*handles string lists*/
int regno
; /*handles arguments*/
int sawindex
; /*saw [rn]*/
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 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 toconv
; /* how to convert bignums */
int incasetable
; /* set if in a case table */
while (val
!= PARSEEOF
){ /* primary loop */
while (INTOKSET(val
, LINSTBEGIN
)){
int i
= ((struct exp
*)yylval
)->e_xvalue
;
yyerror("Local label %d is not followed by a ':' for a label definition",
yyerror("Local labels are 0-9");
(void)sprintf(yytext
, "L%d\001%d", i
, lgensym
[i
]);
yylval
= (int)*lookup(passno
== 1);
np
= (struct symtab
*)yylval
;
else { /*its a name, so we have a label or def */
ERROR("Name expected for a label");
np
= (struct symtab
*)yylval
;
yyerror("\"%s\" is not followed by a ':' for a label definition",
if ((np
->s_type
&XTYPE
)!=XUNDEF
) {
if( (np
->s_type
&XTYPE
)!=dotp
->e_xtype
|| np
->s_value
!=dotp
->e_xvalue
&&(np
->s_index
!= dotp
->e_xloc
)
if (FETCHNAME(np
)[0] != 'L')
yyerror("%s redefined: PHASE ERROR, 1st: %d, 2nd: %d",
np
->s_type
&= ~(XTYPE
|XFORW
);
np
->s_type
|= dotp
->e_xtype
;
np
->s_value
= dotp
->e_xvalue
;
np
->s_index
= dotp
-usedot
;
if (FETCHNAME(np
)[0] == 'L'){
} /*end of this being a label*/
} /*end of to consuming all labels, NLs and SEMIS */
* process the INSTRUCTION body
ERROR("Unrecognized instruction or directive");
tokptr
-= sizeof(bytetoktype
);
stringp
= (struct strdesc
*)yylval
;
dotsname
= &UDotsname
[0];
movestr(dotsname
, stringp
->sd_string
,
min(stringp
->sd_strlen
, sizeof(UDotsname
)));
shift
; /*over the ILINENO*/
lineno
= locxp
->e_xvalue
;
case ISET
: /* .set <name> , <expr> */
np
= (struct symtab
*)yylval
;
np
->s_type
&= (XXTRN
|XFORW
);
np
->s_type
|= locxp
->e_xtype
&(XTYPE
|XFORW
);
np
->s_value
= locxp
->e_xvalue
;
np
->s_index
= locxp
->e_xloc
;
if ((locxp
->e_xtype
&XTYPE
) == XUNDEF
)
case ILSYM
: /*.lsym name , expr */
np
= (struct symtab
*)yylval
;
* Build the unique occurance of the
* The character scanner will have
* already entered it into the symbol
* table, but we should remove it
stpt
= (struct symtab
*)symalloc();
stpt
->s_name
= np
->s_name
;
np
->s_tag
= OBSOLETE
; /*invalidate original */
if ( (locxp
->e_xtype
& XTYPE
) != XABS
)
yyerror("Illegal second argument to lsym");
np
->s_value
= locxp
->e_xvalue
;
case IGLOBAL
: /*.globl <name> */
np
= (struct symtab
*)yylval
;
case IDATA
: /*.data [ <expr> ] */
case ITEXT
: /*.text [ <expr> ] */
if (INTOKSET(val
, EBEGOPS
+YUKKYEXPRBEG
+SAFEEXPRBEG
)){
seg_type
= -seg_type
; /*now, it is positive*/
if (seg_type
< 0) { /*there wasn't an associated expr*/
if ( ((locxp
->e_xtype
& XTYPE
) != XABS
) /* tekmdp */
|| (seg_number
= locxp
->e_xvalue
) >= NLOC
) {
yyerror("illegal location counter");
dotp
= &usedot
[seg_number
];
if (passno
==2) { /* go salt away in pass 2*/
txtfil
= usefile
[seg_number
];
relfil
= rusefile
[seg_number
];
* Storage filler directives:
* 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
;
* Expression List processing
if (INTOKSET(val
, EBEGOPS
+YUKKYEXPRBEG
+SAFEEXPRBEG
)){
* expression list consists of a list of :
* (pack expr2 into expr1 bits
* now, pointing at the next token
if ((locxp
->e_xtype
& XTYPE
) != XABS
) /* tekmdp */
yyerror("Width not absolute");
field_width
= locxp
->e_xvalue
;
if (bitoff
+ field_width
> curlen
)
if (field_width
> curlen
)
yyerror("Expression crosses field boundary");
if ((locxp
->e_xtype
& XTYPE
) != XABS
) {
yyerror("Illegal relocation in field");
case NBPW
/4: reloc_how
= TYPB
; break;
case NBPW
/2: reloc_how
= TYPW
; break;
case NBPW
: reloc_how
= TYPL
; break;
dotp
->e_xvalue
+= ty_nbyte
[reloc_how
];
outrel(locxp
, reloc_how
);
* See if we are doing a case instruction.
* If so, then see if the branch distance,
* is going to loose sig bits.
if (passno
== 2 && incasetable
){
if ( (locxp
->e_xvalue
< -32768)
||(locxp
->e_xvalue
> 32767)){
yyerror("Case will branch too far");
field_value
= locxp
->e_xvalue
& ( (1L << field_width
)-1);
bitfield
|= field_value
<< bitoff
;
if (auxval
= (val
== CM
))
} /* there existed an expression at all */
if ( ( curlen
== NBPW
/4) && bitoff
)
/*end of case IBYTE, IWORD, ILONG, IINT*/
case ISPACE
: /* .space <expr> */
if ((locxp
->e_xtype
& XTYPE
) != XABS
) /* tekmdp */
yyerror("Space size not absolute");
space_value
= locxp
->e_xvalue
;
static char spacebuf
[128];
while (space_value
> sizeof(spacebuf
)){
outs(spacebuf
, sizeof(spacebuf
));
space_value
-= sizeof(spacebuf
);
outs(spacebuf
, space_value
);
* repeat rep times: fill size bytes with (truncated) value
* size must be between 1 and 8
if ( (locxp
->e_xtype
& XTYPE
) != XABS
) /* tekmdp */
yyerror("Fill repetition count not absolute");
fill_rep
= locxp
->e_xvalue
;
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");
if (passno
== 2 && (locxp
->e_xtype
& XTYPE
) != XABS
) /* tekmdp */
yyerror("Fill value not absolute");
dotp
->e_xvalue
+= fill_rep
* fill_size
;
bwrite((char *)&locxp
->e_xvalue
, fill_size
, txtfil
);
case IASCII
: /* .ascii [ <stringlist> ] */
case IASCIZ
: /* .asciz [ <stringlist> ] */
* Code to consume a string list
* stringlist: empty | STRING | stringlist STRING
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 (stringp
->sd_place
& STR_CORE
){
outs(stringp
->sd_string
, mystrlen
);
fseek(strfile
, stringp
->sd_stroff
, 0);
for (i
= 0; i
< mystrlen
;/*VOID*/){
sizeof(yytext
)), strfile
);
dotp
->e_xvalue
+= mystrlen
;
shift
; /*over the STRING*/
if (val
== CM
) /*could be a split string*/
case IORG
: /* .org <expr> */
if ((locxp
->e_xtype
& XTYPE
) == XABS
) /* tekmdp */
else if ((locxp
->e_xtype
& ~XXTRN
) != dotp
->e_xtype
)
yyerror("Illegal expression to set origin");
space_value
= locxp
->e_xvalue
- dotp
->e_xvalue
;
yyerror("Backwards 'org'");
* 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
* .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> # .
yyerror(".stab directive no longer supported");
if (! (locxp
->e_xvalue
& STABTYPS
)){
yyerror("Invalid type in %s", stabname
);
stpt
->s_ptype
= locxp
->e_xvalue
;
stpt
->s_other
= locxp
->e_xvalue
;
stpt
->s_desc
= locxp
->e_xvalue
;
if (p
== NULL
) { /*absolute expr to begin with*/
stpt
->s_value
= locxp
->e_xvalue
;
stpt
->s_index
= dotp
- usedot
;
stpt
->s_tag
= STABFLOATING
;
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
* 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
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*/
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
shift
; /*over the ISTABDOT*/
if (! (locxp
->e_xvalue
& STABTYPS
)){
yyerror("Invalid type in .stabd");
stpt
->s_ptype
= locxp
->e_xvalue
;
stpt
->s_other
= locxp
->e_xvalue
;
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*/
case ISTABNONE
: stabname
= ".stabn"; goto shortstab
;
case ISTABSTR
: stabname
= ".stabs";
if (passno
== 2) goto errorfix
;
stpt
= (struct symtab
*)yylval
;
(bytetoktype
*)stabstart
-= sizeof(struct symtab
*);
(bytetoktype
*)stabstart
-= sizeof(bytetoktype
);
stringp
= (struct strdesc
*)yylval
;
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
stpt
->s_name
= (char *)savestr("\0", 0, STR_BOTH
);
case ICOMM
: /* .comm <name> , <expr> */
case ILCOMM
: /* .lcomm <name> , <expr> */
np
= (struct symtab
*)yylval
;
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
));
np
->s_value
= locxp
->e_xvalue
;
case IALIGN
: /* .align <expr> */
stpt
= (struct symtab
*)yylval
;
case INST0
: /* instructions w/o arguments*/
insout(yyopcode
, (struct arg
*)0, 0);
case INSTn
: /* instructions with arguments*/
case IJXXX
: /* UNIX style jump instructions */
* Code to process an argument list
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;
ERROR("expression expected");
if ( val
== LP
|| sawsize
){
if (val
== LP
) goto base
;
if (val
== LITOP
) goto imm
;
if (val
== SIZESPEC
) goto sizespec
;
+SAFEEXPRBEG
)) goto disp
;
ERROR("expression, '(' or '$' expected");
shift
; /*consume the LP*/
* 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
){
val
= exprparse(val
, &(ap
->a_xp
));
index
: /*look for [reg] */
} /*end of the switch to process an arg*/
} /*end of processing an argument*/
* Make a concession for *(%r)
if (ap
->a_atype
== ABASE
) {
xp
->e_number
.num_tag
= TYPL
;
ap
->a_dispsize
= sawsize
== 0 ? d124
: sawsize
;
} /*processing all the arguments*/
yyerror("More than 6 arguments");
* See if this is a case instruction,
* so we can set up tests on the following
* vector of branch displacements
if (yyopcode
.Op_eopcode
== CORE
){
switch(yyopcode
.Op_popcode
){
insout(yyopcode
, arglist
,
auxval
== INSTn
? argcnt
: - argcnt
);
case IQUAD
: toconv
= TYPQ
; goto bignumlist
;
case IOCTA
: toconv
= TYPO
; goto bignumlist
;
case IFFLOAT
: toconv
= TYPF
; goto bignumlist
;
case IDFLOAT
: toconv
= TYPD
; goto bignumlist
;
case IGFLOAT
: toconv
= TYPG
; goto bignumlist
;
case IHFLOAT
: toconv
= TYPH
; goto bignumlist
;
* eat a list of non 32 bit numbers.
* IQUAD and IOCTA 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
)){
if ((val
!= BIGNUM
) && (val
!= INT
)){
? "floating number expected"
: "integer number expected" );
dotp
->e_xvalue
+= ty_nbyte
[toconv
];
((struct exp
*)yylval
)->e_number
,
shift
; /* over this number */
if (auxval
= (val
== CM
))
shift
; /* over the comma */
} while (auxval
); /* as long as there are commas */
/* end of the case for initialized big numbers */
} /*end of the switch for looking at each reserved word*/
* got here by either requesting to skip to the
* end of this statement, or by erroring out and
* wanting to apply panic mode recovery
} /*end of the loop to read the entire file, line by line*/
* Process a register declaration of the form
* 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
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*/
struct exp
**ptrloc1xp
= & loc1xp
;
expr(locxp
, val
); /*and leave the current read head with value*/
( (locxp
->e_xtype
& XTYPE
) != XABS
|| (locxp
->e_xvalue
>= 16)
yyerror("Illegal register");
*regnoback
= locxp
->e_xvalue
;
yyerror("%s expected", tok_to_name(token
));
yyerror(s
, a1
, a2
,a3
,a4
,a5
)
if (anyerrs
== 0 && anywarnings
== 0 && ! silent
)
fprintf(sink
, "Assembler:\n");
fprintf(sink
, "\"%s\", line %d: ", dotsname
, lineno
);
fprintf(sink
, s
, a1
, a2
,a3
,a4
,a5
);
yywarning(s
, a1
, a2
,a3
,a4
,a5
)
if (anyerrs
== 0 && anywarnings
== 0 && ! silent
)
fprintf(sink
, "Assembler:\n");
fprintf(sink
, "\"%s\", line %d: WARNING: ", dotsname
, lineno
);
fprintf(sink
, s
, a1
, a2
,a3
,a4
,a5
);