ack/mach/proto/as/comm2.y
George Koehler 054b9c87e1 Add .data8 for 8-byte literal integers to the assembler.
This takes literal integers, not expressions, because each machine
defines its own valu_t for expressions, but valu_t can be too narrow
for an 8-byte integer, and I don't want to change all the machines to
use a wider valu_t.  Instead, change how the assembler parses literal
integers.  Remove the NUMBER token and add a NUMBER8 token for an
int64_t.  The new .data8 pseudo emits all 8 bytes of the int64_t;
expressions narrow the int64_t to a valu_t.  Don't add any checks for
integer overflow; expressions and .data* pseudos continue to ignore
overflow when a number is too wide.

This commit requires int64_t and uint64_t in the C compiler to build
the assembler.  The ACK's own C compiler doesn't have these.

For the assembler's temporary file, add NUMBER4 to store 4-byte
integers.  NUMBER4 acts like NUMBER[0-3] and only stores a
non-negative integer.  Each negative integer now takes 8 bytes (up
from 4) in the temporary file.

Move the `\fI` and `\fP` in the uni_ass(6) manual, so the square
brackets in `thing [, thing]*` are not italic.  This looks nicer in my
terminal, where italic text is underlined.
2019-08-13 11:47:44 -04:00

465 lines
8.7 KiB
Plaintext

/* $Id$ */
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
/* @(#)comm2.y 1.7 */
/*
* delay inclusion of machine dependent stuff (see comm0.h)
*/
#define _include #include
%{
#include "comm0.h"
#include "comm1.h"
static item_t *last_it, *o_it;
%}
/* ========== Machine independent Yacc definitions ========== */
%union {
word_t y_word;
valu_t y_valu;
int64_t y_valu8;
expr_t y_expr;
item_t *y_item;
#ifdef ASLD
char *y_strp;
#endif
};
#ifdef ASLD
%token <y_strp> MODULE
#endif
%token STRING
%token <y_item> IDENT
%token <y_item> FBSYM
%token <y_valu> CODE1
%token <y_valu> CODE2
%token <y_valu> CODE4
%token NUMBER0 /* keep NUMBER[0-4] in this order */
%token NUMBER1
%token NUMBER2
%token NUMBER3
%token NUMBER4
%token <y_valu8> NUMBER8
%token NUMBERF
%token DOT
%token EXTERN
%token <y_word> DATA
%token DATA8
%token <y_word> DATAF
%token <y_word> ASCII
%token SECTION
%token COMMON
%token BASE
%token SYMB
%token SYMD
%token ALIGN
%token ASSERT
%token SPACE
%token <y_word> LINE
%token FILe
%token <y_word> LIST
%left OP_OO
%left OP_AA
%left '|'
%left '^'
%left '&'
%left OP_EQ OP_NE
%left '<' '>' OP_LE OP_GE
%left OP_LL OP_RR
%left '+' '-'
%left '*' '/' '%'
%nonassoc '~'
%type <y_valu> absexp optabs1 optabs2
%type <y_valu8> datum8
%type <y_expr> expr
%type <y_item> id_fb
/* ========== Machine dependent Yacc definitions ========== */
#include "mach2.c"
%%
/* ========== Machine independent rules ========== */
#ifdef LISTING
#define LISTLINE(n) if (listflag) listline(n); \
else if (listtemp) { listflag = listtemp; listeoln = 1; }
#else
#define LISTLINE(n) /* empty */
#endif /* LISTING */
#ifdef ASLD
#define RELODONE /* empty */
#else
#define RELODONE assert(relonami == 0)
#endif
program : /* empty */
#ifdef ASLD
| program MODULE /* not in PASS_1 */
{ newmodule($2);}
#endif
| program IDENT ':'
{ newident($2, DOTTYP); newlabel($2);}
| program NUMBER8 ':'
{ if ($2 < 0 || $2 > 9) {
serror("bad f/b label");
$2 = 0;
}
newlabel(fb_shift((int)$2));
}
| program CODE1
{ emit1((int)$2); LISTLINE(0);}
| program CODE2
{ emit2((int)$2); LISTLINE(0);}
| program CODE4
{ emit4((long)$2); LISTLINE(0);}
| program operation ';'
| program operation '\n'
{ lineno++; LISTLINE(1); RELODONE;}
| program '#' NUMBER8 STRING '\n'
{ lineno = $3; /* long = int64_t */
if (modulename) strncpy(modulename, stringbuf, STRINGMAX-1);
LISTLINE(1); RELODONE;
}
| program error '\n'
{ serror("syntax error"); yyerrok;
lineno++; LISTLINE(1); RELODONE;
}
;
#undef LISTLINE
#undef RELODONE
operation
: /* empty */
| IDENT '=' expr
{
#ifdef LISTING
if (listflag & 1)
listcolm += printx(VALWIDTH, $3.val);
#endif
newequate($1, $3.typ);
store($1, $3.val);
}
#ifdef LISTING
| LIST
{ if ($1)
listtemp = listmode;
else if ((dflag & 01000) == 0)
listtemp = 0;
}
#endif
| SECTION IDENT
{ newsect($2);}
| COMMON IDENT ',' absexp
{ newcomm($2, $4);}
| BASE absexp
{ if (pass == PASS_1) newbase($2);}
| ASSERT expr
{ if ($2.val == 0 && pass == PASS_3)
warning("assertion failed");
}
| SYMB STRING ',' expr { o_it = last_it; }
optabs2 optabs2
{ if ((sflag & SYM_SMB) && PASS_SYMB) {
#ifndef ASLD
if (
pass == PASS_3
&&
($4.typ & S_TYP) == S_UND
) {
serror("expression undefined");
relonami = -1;
}
if (
PASS_SYMB
&&
($4.typ & S_COM)
) {
/* No value is known at
assembler time.
Generate reference to other
entry in name table
*/
$4.typ = S_CRS;
$4.val = new_string(o_it->i_name);
relonami = 0;
}
#endif
newsymb(
*stringbuf ? stringbuf : (char *) 0,
(short)(
($4.typ & (S_EXT|S_TYP))
|
((unsigned short)$6<<8)
),
(short)$7,
$4.val
);
}
}
| SYMD STRING ',' absexp ',' absexp
{ if ((sflag & SYM_SMB) && PASS_SYMB) {
newsymb(
*stringbuf ? stringbuf : (char *) 0,
(short)(
(DOTTYP & (S_EXT|S_TYP))
|
((unsigned short)$4<<8)
),
(short)$6,
(valu_t)DOTVAL
);
}
}
| LINE optabs1
{ if ((sflag & SYM_LIN) && PASS_SYMB) {
if ($2)
hllino = (short)$2;
else
hllino++;
newsymb(
(char *)0,
(DOTTYP | S_LIN),
hllino,
(valu_t)DOTVAL
);
}
}
| FILe STRING
{ if ((sflag & SYM_LIN) && PASS_SYMB) {
hllino = 0;
newsymb(
stringbuf,
(DOTTYP | S_FIL),
0,
(valu_t)DOTVAL
);
}
}
| EXTERN externlist
| ALIGN optabs1
{ align($2);}
| SPACE absexp
{ if (DOTSCT == NULL)
nosect();
DOTVAL += $2;
DOTSCT->s_zero += $2;
}
| DATA datalist
| DATA8 data8list
| DATAF dataflist
| ASCII STRING
{ emitstr($1);}
;
externlist
: IDENT
{ $1->i_type |= S_EXT;}
| externlist ',' IDENT
{ $3->i_type |= S_EXT;}
;
datalist
: expr
{
#ifdef RELOCATION
if (rflag != 0 && PASS_RELO)
newrelo($1.typ, (int)$<y_word>0|MACHREL_BWR);
#endif
emitx($1.val, (int)$<y_word>0);
}
| datalist ',' expr
{
#ifdef RELOCATION
if (rflag != 0 && PASS_RELO)
newrelo($3.typ, (int)$<y_word>0|MACHREL_BWR);
#endif
emitx($3.val, (int)$<y_word>0);
}
;
/* datum8 isn't expr, because int64_t may be wider than valu_t. */
datum8 : NUMBER8
{ $$ = $1;}
| '-' NUMBER8
{ $$ = -$2;}
;
data8list
: datum8
{ emit8($1);}
| data8list ',' datum8
{ emit8($3);}
;
numberf
: NUMBERF
{
emitf((int)$<y_word>-1, 0);
}
| '-' NUMBERF
{
emitf((int)$<y_word>-1, 1);
}
;
dataflist
: numberf
| dataflist ',' numberf
;
expr : error
{ serror("expr syntax err");
$$.val = 0; $$.typ = S_UND;
}
| NUMBER8
{ $$.val = $1; /* valu_t = int64_t */
$$.typ = S_ABS;
}
| id_fb
{ $$.val = load($1);
last_it = $1;
$$.typ = $1->i_type & ~S_EXT;
}
| STRING
{ if (stringlen != 1)
serror("too many chars");
$$.val = stringbuf[0];
$$.typ = S_ABS;
}
| ASC_LPAR expr ASC_RPAR
{ $$ = $2;}
| expr OP_OO expr
{ $$.val = ($1.val || $3.val);
$$.typ = combine($1.typ, $3.typ, 0);
}
| expr OP_AA expr
{ $$.val = ($1.val && $3.val);
$$.typ = combine($1.typ, $3.typ, 0);
}
| expr '|' expr
{ $$.val = ($1.val | $3.val);
$$.typ = combine($1.typ, $3.typ, 0);
}
| expr '^' expr
{ $$.val = ($1.val ^ $3.val);
$$.typ = combine($1.typ, $3.typ, 0);
}
| expr '&' expr
{ $$.val = ($1.val & $3.val);
$$.typ = combine($1.typ, $3.typ, 0);
}
| expr OP_EQ expr
{ $$.val = ($1.val == $3.val);
$$.typ = combine($1.typ, $3.typ, '>');
}
| expr OP_NE expr
{ $$.val = ($1.val != $3.val);
$$.typ = combine($1.typ, $3.typ, '>');
}
| expr '<' expr
{ $$.val = ($1.val < $3.val);
$$.typ = combine($1.typ, $3.typ, '>');
}
| expr '>' expr
{ $$.val = ($1.val > $3.val);
$$.typ = combine($1.typ, $3.typ, '>');
}
| expr OP_LE expr
{ $$.val = ($1.val <= $3.val);
$$.typ = combine($1.typ, $3.typ, '>');
}
| expr OP_GE expr
{ $$.val = ($1.val >= $3.val);
$$.typ = combine($1.typ, $3.typ, '>');
}
| expr OP_RR expr
{ $$.val = ($1.val >> $3.val);
$$.typ = combine($1.typ, $3.typ, 0);
}
| expr OP_LL expr
{ $$.val = ($1.val << $3.val);
$$.typ = combine($1.typ, $3.typ, 0);
}
| expr '+' expr
{ $$.val = ($1.val + $3.val);
$$.typ = combine($1.typ, $3.typ, '+');
}
| expr '-' expr
{ $$.val = ($1.val - $3.val);
$$.typ = combine($1.typ, $3.typ, '-');
}
| expr '*' expr
{ $$.val = ($1.val * $3.val);
$$.typ = combine($1.typ, $3.typ, 0);
}
| expr '/' expr
{ if ($3.val == 0) {
if (pass == PASS_3)
serror("divide by zero");
$$.val = 0;
} else
$$.val = ($1.val / $3.val);
$$.typ = combine($1.typ, $3.typ, 0);
}
| expr '%' expr
{ if ($3.val == 0) {
if (pass == PASS_3)
serror("divide by zero");
$$.val = 0;
} else
$$.val = ($1.val % $3.val);
$$.typ = combine($1.typ, $3.typ, 0);
}
| '+' expr %prec '*'
{ $$.val = $2.val;
$$.typ = combine(S_ABS, $2.typ, 0);
}
| '-' expr %prec '*'
{ $$.val = -$2.val;
$$.typ = combine(S_ABS, $2.typ, 0);
}
| '~' expr
{ $$.val = ~$2.val;
$$.typ = combine(S_ABS, $2.typ, 0);
}
| DOT
{ $$.val = DOTVAL;
$$.typ = DOTTYP|S_DOT;
}
;
id_fb : IDENT
| FBSYM
;
absexp : expr
{ if (($1.typ & ~S_EXT) != S_ABS)
serror("must be absolute");
$$ = $1.val;
}
;
optabs1
: /* empty */
{ $$ = 0;}
| absexp
{ $$ = $1;}
;
optabs2
: /* empty */
{ $$ = 0;}
| ',' absexp
{ $$ = $2;}
;
/* ========== Machine dependent rules ========== */
#include "mach4.c"
%%