Interdata_v6/usr/source/as/as4.c
/*
* Assembler input & lexical scan routines
*
*
* Copyright (C) 1978, Richard Miller
*/
#define EXTERN extern
#include "as.h"
/*
* Character types
*/
#define C_ALPHA 0x80 /* Alphabetic (i.e. legal within symbol) */
#define C_UPPER 0x40 /* Upper-case alpha */
#define C_HEXDIGIT 0x20 /* Hexadecimal digit [0-9 a-f A-F] */
#define C_SPECIAL 0x00 /* Other special characters */
#define C_VALUE 0x0f /* C_HEXDIGIT - numerical value of digit
C_SPECIAL - lexical token for character */
/*
* Character type table
*/
char ctab[128] {
0, 0, 0, 0, 0, 0, 0, 0,
0, SPACE, EOL, 0, EOL, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0,
SPACE, OR, 0, 0, 0x80, 0, AND, 0,
LPAREN, RPAREN, STAR, PLUS, COMMA, MINUS, 0x80, SLASH,
0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
0x28, 0x29, 0, 0, 0, 0, 0, 0,
0x80, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xc0,
0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0,
0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0, 0xc0,
0xc0, 0xc0, 0xc0, 0, 0, 0, 0, 0x80,
0, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
0x80, 0x80, 0x80, 0, 0, 0, 0, 0
};
/*
* Read next input line, truncating to 71 chars
* - resets scan pointer to start of line
* - initializes listing buffer
* - returns 0 at end-of-file, '\n' otherwise
*/
char linebuf[74]; /* input line buffer */
char *scanp; /* input scan cursor */
getline()
{
static char ibuf[512], *next;
static int nleft;
register char *nx; register nl;
register char *p;
register c, ncol;
scanp = p = linebuf;
lstinit();
/*
* If previous statement was DO, decrement the count and re-use
* the same buffer
*/
if (docount-- > 0)
return('\n');
else
docount = 0;
ncol = 71;
for (nx = next, nl = nleft; ;) {
if (--nl < 0) {
while ((nl = read(0, ibuf, sizeof ibuf)-1) < 0)
if (!nextfile())
return(0);
nx = ibuf;
}
if ((*p = *nx++) == '\n') {
p[1] = '\0';
next = nx;
nleft = nl;
line++;
return('\n');
}
if (--ncol > 0)
p++;
}
}
/*
* Return next lexical token from input line
* - if constant, value is in conbuf
* - if symbol, symbol pointer is in cursym
*/
token()
{
register ret, c;
register ctype;
register char *p;
if (ret = nexttoken) {
nexttoken = 0;
return(ret);
}
/*
* first character "alphabetic"
*/
p = scanp;
if ((ctype = ctab[c = *p])&C_ALPHA) {
/*
* quoted numerical constants
*/
if (p[1] == '\'') {
scanp = (p += 2);
ret = CON;
switch (c) {
case 'x':
case 'X':
ret = HCON;
case 'y':
case 'Y':
conbuf = getnum(16);
break;
case 'h':
case 'H':
ret = HCON;
case 'f':
case 'F':
conbuf = getnum(10);
break;
case 'c':
case 'C':
ret = STRING;
conbuf = getstr();
break;
default:
xerror(errx);
}
if (*scanp++ != '\'')
xerror(errq);
return(ret);
}
/*
* address constants
*/
if (dcflag && p[1] == '(') {
scanp = (p += 2);
switch (c) {
case 'a':
case 'A':
return(APAR);
case 'z':
case 'Z':
return(ZPAR);
default:
scanp -= 2;
}
}
/*
* symbol
*/
getsym();
symlook(2);
return(SYMBOL);
}
/*
* first character numeric -- decimal constant
*/
if (ctype&C_HEXDIGIT) {
conbuf = getnum(10);
return(CON);
}
/*
* special characters
*/
scanp = ++p;
switch (ctype &= C_VALUE) {
/*
* garbage character
*/
case 0:
xerror(errg);
/*
* white space
*/
case SPACE:
while ((c = *p) == ' ' || c == '\t')
p++;
scanp = p;
return(SPACE);
/*
* don't scan past end of line
*/
case EOL:
scanp = --p;
return(EOL);
/*
* stupid special case: "//" is a legal label in a COMN statement
*/
case SLASH:
if (*p == '/' && p == &linebuf[1]) {
enter("//");
scanp = ++p;
return(SYMBOL);
}
return(SLASH);
/*
* single-character tokens
*/
default:
return(ctype);
}
}
/*
* Scan a decimal or hexadecimal number (with optional sign)
* from input line
*/
getnum(base)
register base;
{
register char *p;
register c, n, sign;
p = scanp;
sign = 1;
if ((c = *p) == '-') {
sign = -1;
c = *++p;
}
else if (c == '+')
c = *++p;
if (((c = ctab[c])&C_HEXDIGIT) == 0 || (n = c&C_VALUE) >= base)
xerror(errn);
while ((c = ctab[*++p])&C_HEXDIGIT && (c &= C_VALUE) < base) {
n *= base;
n += c;
}
scanp = p;
return(n*sign);
}
/*
* Scan a character string from input line until ending quote
* - translate pairs of quotes to single quote
* - pad string with extra blank
* - leave string in strbuf, and length in strlen
*/
getstr()
{
register char *s, *p;
register c;
s = strbuf;
for (p = scanp; ; p++) {
if ((c = *p) == '\'') {
if (p[1] == '\'')
p++;
else
break;
}
else if (c == '\n')
xerror(errq);
*s++ = c;
}
*s = ' ';
strlen = s - strbuf;
scanp = p;
return(strbuf);
}
/*
* Scan a symbol from the input line into symbuf
* if -u mode, translate to lowercase
* truncate long symbols to 8 characters (without warning)
*
* returns 0: no legal symbol found
* 1: symbol found
*/
getsym()
{
register c, ctype;
register char *p, *s;
p = scanp;
if (!((ctype = ctab[c = *p]) & C_ALPHA))
return(0);
s = symbuf;
((int *)s)[0] = ((int *)s)[1] = 0;
do {
if (s < &symbuf[sizeof symbuf]) {
if (ucase && (ctype&C_UPPER))
c += 'a'-'A';
*s++ = c;
}
} while ((ctype = ctab[c = *++p])&(C_ALPHA|C_HEXDIGIT));
scanp = p;
return(1);
}
/*
* Determine whether scan pointer is at end of line
*/
eol()
{
register c;
return((c = ctab[*scanp]) == EOL || c== SPACE);
}
/*
* Save / restore scan pointer (for backtracking)
*/
static char *scansave;
sscan()
{
scansave = scanp;
}
rscan()
{
scanp = scansave;
}