685 lines
10 KiB
C
685 lines
10 KiB
C
/* $Id$ */
|
|
/*
|
|
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
|
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
|
*/
|
|
/* @(#)comm5.c 1.1 */
|
|
|
|
#include "comm0.h"
|
|
#include "comm1.h"
|
|
#include "y.tab.h"
|
|
|
|
extern YYSTYPE yylval;
|
|
|
|
static void readcode(int);
|
|
static int induo(int);
|
|
static int inident(int);
|
|
static int innumber(int);
|
|
static int instring(int);
|
|
static int inescape(void);
|
|
static int infbsym(const char*);
|
|
|
|
static int maxstring = 0;
|
|
|
|
int yylex(void)
|
|
{
|
|
int c, c0, c1;
|
|
|
|
if (pass == PASS_1)
|
|
{
|
|
/* scan the input file */
|
|
do
|
|
c = nextchar();
|
|
while (isspace(c) && c != '\n');
|
|
if (ISALPHA(c))
|
|
c = inident(c);
|
|
else if (isdigit(c))
|
|
c = innumber(c);
|
|
else
|
|
switch (c)
|
|
{
|
|
case '=':
|
|
case '<':
|
|
case '>':
|
|
case '|':
|
|
case '&':
|
|
c = induo(c);
|
|
break;
|
|
case ASC_SQUO:
|
|
case ASC_DQUO:
|
|
c = instring(c);
|
|
break;
|
|
case ASC_COMM:
|
|
do
|
|
c = nextchar();
|
|
while (c != '\n' && c != '\0');
|
|
break;
|
|
case CTRL('A'):
|
|
c = CODE1;
|
|
readcode(1);
|
|
break;
|
|
case CTRL('B'):
|
|
c = CODE2;
|
|
readcode(2);
|
|
break;
|
|
case CTRL('C'):
|
|
c = CODE4;
|
|
readcode(4);
|
|
break;
|
|
}
|
|
|
|
/* produce the intermediate token file */
|
|
if (c <= 0)
|
|
return (0);
|
|
if (c < 256)
|
|
{
|
|
putc(c, tempfile);
|
|
putc(0, tempfile);
|
|
}
|
|
else
|
|
{
|
|
putval(c);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
/* read from intermediate token file */
|
|
c0 = getc(tempfile);
|
|
if (c0 == EOF)
|
|
return (0);
|
|
c1 = getc(tempfile);
|
|
if (c1 == EOF)
|
|
return (0);
|
|
|
|
c = c0 + (c1 << 8);
|
|
if (c >= 256)
|
|
c = getval(c);
|
|
}
|
|
curr_token = c;
|
|
return (c);
|
|
}
|
|
|
|
void putval(int c)
|
|
{
|
|
valu_t v;
|
|
int n = 0;
|
|
char* p = 0;
|
|
|
|
assert(c == (c & 0xffff));
|
|
switch (c)
|
|
{
|
|
case CODE1:
|
|
n = 1;
|
|
goto putnum;
|
|
case CODE2:
|
|
n = 2;
|
|
goto putnum;
|
|
case CODE4:
|
|
n = 4;
|
|
goto putnum;
|
|
case NUMBER:
|
|
v = yylval.y_valu;
|
|
for (n = 0; n < sizeof(v); n++)
|
|
{
|
|
if (v == 0)
|
|
break;
|
|
v >>= 8;
|
|
}
|
|
assert(n <= 4);
|
|
c = NUMBER0 + n;
|
|
putnum:
|
|
putc(c, tempfile);
|
|
putc(c >> 8, tempfile);
|
|
v = yylval.y_valu;
|
|
while (--n >= 0)
|
|
putc((int)(v >> (n * 8)), tempfile);
|
|
return;
|
|
case IDENT:
|
|
case FBSYM:
|
|
n = sizeof(item_t*);
|
|
p = (char*)&yylval.y_item;
|
|
break;
|
|
#ifdef ASLD
|
|
case MODULE:
|
|
n = sizeof(char*);
|
|
p = (char*)&yylval.y_strp;
|
|
break;
|
|
#endif
|
|
case STRING:
|
|
case NUMBERF:
|
|
v = stringlen;
|
|
putc(c, tempfile);
|
|
putc(c >> 8, tempfile);
|
|
for (n = 0; n < sizeof(v); n++)
|
|
{
|
|
if (v == 0)
|
|
break;
|
|
v >>= 8;
|
|
}
|
|
assert(n <= 4);
|
|
putc(n, tempfile);
|
|
v = stringlen;
|
|
while (--n >= 0)
|
|
putc((int)(v >> (n * 8)), tempfile);
|
|
p = stringbuf;
|
|
n = stringlen;
|
|
while (--n >= 0)
|
|
putc(*p++, tempfile);
|
|
return;
|
|
case OP_EQ:
|
|
case OP_NE:
|
|
case OP_LE:
|
|
case OP_GE:
|
|
case OP_LL:
|
|
case OP_RR:
|
|
case OP_OO:
|
|
case OP_AA:
|
|
break;
|
|
default:
|
|
n = sizeof(word_t);
|
|
p = (char*)&yylval.y_word;
|
|
break;
|
|
}
|
|
putc(c, tempfile);
|
|
putc(c >> 8, tempfile);
|
|
while (--n >= 0)
|
|
putc(*p++, tempfile);
|
|
}
|
|
|
|
int getval(int c)
|
|
{
|
|
int n = 0;
|
|
valu_t v;
|
|
char* p = 0;
|
|
|
|
switch (c)
|
|
{
|
|
case CODE1:
|
|
n = 1;
|
|
goto getnum;
|
|
case CODE2:
|
|
n = 2;
|
|
goto getnum;
|
|
case CODE4:
|
|
n = 4;
|
|
goto getnum;
|
|
case NUMBER0:
|
|
c = NUMBER;
|
|
goto getnum;
|
|
case NUMBER1:
|
|
n = 1;
|
|
c = NUMBER;
|
|
goto getnum;
|
|
case NUMBER2:
|
|
n = 2;
|
|
c = NUMBER;
|
|
goto getnum;
|
|
case NUMBER3:
|
|
n = 3;
|
|
c = NUMBER;
|
|
goto getnum;
|
|
case NUMBER:
|
|
n = 4;
|
|
getnum:
|
|
v = 0;
|
|
while (--n >= 0)
|
|
{
|
|
v <<= 8;
|
|
v |= getc(tempfile);
|
|
}
|
|
yylval.y_valu = v;
|
|
return (c);
|
|
case IDENT:
|
|
case FBSYM:
|
|
n = sizeof(item_t*);
|
|
p = (char*)&yylval.y_item;
|
|
break;
|
|
#ifdef ASLD
|
|
case MODULE:
|
|
n = sizeof(char*);
|
|
p = (char*)&yylval.y_strp;
|
|
break;
|
|
#endif
|
|
case STRING:
|
|
case NUMBERF:
|
|
getval(getc(tempfile) + NUMBER0);
|
|
stringlen = n = yylval.y_valu;
|
|
p = stringbuf;
|
|
p[n] = '\0';
|
|
break;
|
|
case OP_EQ:
|
|
case OP_NE:
|
|
case OP_LE:
|
|
case OP_GE:
|
|
case OP_LL:
|
|
case OP_RR:
|
|
case OP_OO:
|
|
case OP_AA:
|
|
break;
|
|
default:
|
|
n = sizeof(word_t);
|
|
p = (char*)&yylval.y_word;
|
|
break;
|
|
}
|
|
while (--n >= 0)
|
|
*p++ = getc(tempfile);
|
|
return (c);
|
|
}
|
|
|
|
/* ---------- lexical scan in pass 1 ---------- */
|
|
|
|
int nextchar(void)
|
|
{
|
|
int c;
|
|
|
|
if (peekc != -1)
|
|
{
|
|
c = peekc;
|
|
peekc = -1;
|
|
return (c);
|
|
}
|
|
#ifdef ASLD
|
|
if (archmode && --archsize < 0)
|
|
return (0);
|
|
#endif
|
|
if ((c = getc(input)) == EOF)
|
|
return (0);
|
|
if (isascii(c) == 0)
|
|
fatal("non-ascii character");
|
|
#ifdef LISTING
|
|
if (listflag & 0440)
|
|
putc(c, listfile);
|
|
#endif
|
|
return (c);
|
|
}
|
|
|
|
static void readcode(int n)
|
|
{
|
|
int c;
|
|
|
|
yylval.y_valu = 0;
|
|
do
|
|
{
|
|
if (
|
|
#ifdef ASLD
|
|
(archmode && --archsize < 0) ||
|
|
#endif
|
|
(c = getc(input)) == EOF)
|
|
fatal("unexpected EOF in compact input");
|
|
yylval.y_valu <<= 8;
|
|
yylval.y_valu |= c;
|
|
} while (--n);
|
|
}
|
|
|
|
static int induo(int c)
|
|
{
|
|
static short duo[] = {
|
|
('=' << 8) | '=',
|
|
OP_EQ,
|
|
('<' << 8) | '>',
|
|
OP_NE,
|
|
('<' << 8) | '=',
|
|
OP_LE,
|
|
('>' << 8) | '=',
|
|
OP_GE,
|
|
('<' << 8) | '<',
|
|
OP_LL,
|
|
('>' << 8) | '>',
|
|
OP_RR,
|
|
('|' << 8) | '|',
|
|
OP_OO,
|
|
('&' << 8) | '&',
|
|
OP_AA,
|
|
0 /* terminates array */
|
|
};
|
|
short* p;
|
|
|
|
c = (c << 8) | nextchar();
|
|
for (p = duo; *p; p++)
|
|
if (*p++ == c)
|
|
return (*p++);
|
|
peekc = c & 0377;
|
|
return (c >> 8);
|
|
}
|
|
|
|
static char name[NAMEMAX + 1];
|
|
|
|
static int inident(int c)
|
|
{
|
|
char* p = name;
|
|
item_t* ip;
|
|
int n = NAMEMAX;
|
|
|
|
do
|
|
{
|
|
if (--n >= 0)
|
|
*p++ = c;
|
|
c = nextchar();
|
|
} while (ISALNUM(c));
|
|
*p = '\0';
|
|
peekc = c;
|
|
ip = item_search(name);
|
|
if (ip == 0)
|
|
{
|
|
ip = item_alloc(S_UND);
|
|
ip->i_name = remember(name);
|
|
/* printf("ident %s %o\n", ip->i_name, ip); */
|
|
unresolved++;
|
|
item_insert(ip, H_LOCAL + (hashindex % H_SIZE));
|
|
}
|
|
else if (hashindex < H_SIZE)
|
|
{
|
|
assert(H_KEY == 0);
|
|
yylval.y_word = (word_t)ip->i_valu;
|
|
return (ip->i_type);
|
|
}
|
|
yylval.y_item = ip;
|
|
return (IDENT);
|
|
}
|
|
|
|
#ifdef ASLD
|
|
char* readident(int c)
|
|
{
|
|
int n = NAMEMAX;
|
|
char* p = name;
|
|
|
|
do
|
|
{
|
|
if (--n >= 0)
|
|
*p++ = c;
|
|
c = nextchar();
|
|
} while (ISALNUM(c));
|
|
*p++ = '\0';
|
|
peekc = c;
|
|
return (name);
|
|
}
|
|
#endif
|
|
|
|
static int innumber(int c)
|
|
{
|
|
char* p;
|
|
int radix;
|
|
static char num[40 + 1];
|
|
|
|
p = num;
|
|
radix = 40;
|
|
if (c == '.')
|
|
goto floatconstant;
|
|
do
|
|
{
|
|
if (--radix < 0)
|
|
fatal("number too long");
|
|
if (isupper(c))
|
|
c += ('a' - 'A');
|
|
*p++ = c;
|
|
c = nextchar();
|
|
if (c == '.')
|
|
goto floatconstant;
|
|
} while (isalnum(c));
|
|
peekc = c;
|
|
*p = '\0';
|
|
c = *--p;
|
|
p = num;
|
|
radix = 10;
|
|
if (*p == '0')
|
|
{
|
|
radix = 8;
|
|
p++;
|
|
if (*p == 'x')
|
|
{
|
|
radix = 16;
|
|
p++;
|
|
}
|
|
else if (*p == 'b')
|
|
{
|
|
radix = 2;
|
|
p++;
|
|
}
|
|
}
|
|
if (radix != 16 && (c == 'f' || c == 'b'))
|
|
return (infbsym(num));
|
|
yylval.y_valu = 0;
|
|
while ((c = *p++))
|
|
{
|
|
if (c > '9')
|
|
c -= ('a' - '9' - 1);
|
|
c -= '0';
|
|
if ((unsigned)c >= radix)
|
|
serror("digit exceeds radix");
|
|
yylval.y_valu = yylval.y_valu * radix + c;
|
|
}
|
|
return (NUMBER);
|
|
|
|
floatconstant:
|
|
do
|
|
{
|
|
if (--radix < 0)
|
|
fatal("number too long");
|
|
*p++ = c;
|
|
c = nextchar();
|
|
if (isupper(c))
|
|
c = tolower(c);
|
|
} while (isdigit(c) || (c == '.') || (c == 'e') || (c == '+') || (c == '-'));
|
|
peekc = c;
|
|
|
|
*p = '\0';
|
|
stringlen = p - num;
|
|
if (stringlen > maxstring)
|
|
{
|
|
maxstring = stringlen;
|
|
stringbuf = realloc(stringbuf, maxstring);
|
|
}
|
|
strcpy(stringbuf, num);
|
|
return NUMBERF;
|
|
}
|
|
|
|
static int instring(int termc)
|
|
{
|
|
char* p;
|
|
int c;
|
|
|
|
if (!maxstring)
|
|
{
|
|
maxstring = STRINGMAX;
|
|
if ((stringbuf = malloc(maxstring)) == 0)
|
|
{
|
|
fatal("out of memory");
|
|
}
|
|
}
|
|
p = stringbuf;
|
|
for (;;)
|
|
{
|
|
c = nextchar();
|
|
if (c == '\n' || c == '\0')
|
|
{
|
|
peekc = c;
|
|
serror("non-terminated string");
|
|
break;
|
|
}
|
|
if (c == termc)
|
|
break;
|
|
if (c == '\\')
|
|
c = inescape();
|
|
if (p >= &stringbuf[maxstring - 1])
|
|
{
|
|
int cnt = p - stringbuf;
|
|
|
|
if ((stringbuf = realloc(stringbuf, maxstring += 256)) == 0)
|
|
{
|
|
fatal("out of memory");
|
|
}
|
|
p = stringbuf + cnt;
|
|
}
|
|
*p++ = c;
|
|
}
|
|
stringlen = p - stringbuf;
|
|
*p = '\0';
|
|
return (STRING);
|
|
}
|
|
|
|
static int inescape(void)
|
|
{
|
|
int c, j, r;
|
|
|
|
c = nextchar();
|
|
if (c >= '0' && c <= '7')
|
|
{
|
|
r = c - '0';
|
|
for (j = 0; j < 2; j++)
|
|
{
|
|
c = nextchar();
|
|
if (c < '0' || c > '7')
|
|
{
|
|
peekc = c;
|
|
return (r);
|
|
}
|
|
r <<= 3;
|
|
r += (c - '0');
|
|
}
|
|
return (r);
|
|
}
|
|
switch (c)
|
|
{
|
|
case 'b':
|
|
return ('\b');
|
|
case 'f':
|
|
return ('\f');
|
|
case 'n':
|
|
return ('\n');
|
|
case 'r':
|
|
return ('\r');
|
|
case 't':
|
|
return ('\t');
|
|
case '\'':
|
|
return ('\'');
|
|
case '"':
|
|
return ('"');
|
|
}
|
|
return (c);
|
|
}
|
|
|
|
static int infbsym(const char* p)
|
|
{
|
|
int lab;
|
|
item_t* ip;
|
|
|
|
lab = *p++ - '0';
|
|
if ((unsigned)lab < 10)
|
|
{
|
|
if (*p++ == 'f')
|
|
{
|
|
ip = fb_ptr[FB_FORW + lab];
|
|
if (ip == 0)
|
|
{
|
|
ip = fb_alloc(lab);
|
|
fb_ptr[FB_FORW + lab] = ip;
|
|
}
|
|
goto ok;
|
|
}
|
|
ip = fb_ptr[FB_BACK + lab];
|
|
if (ip != 0 && *p == 0)
|
|
goto ok;
|
|
}
|
|
serror("bad numeric label");
|
|
ip = fb_alloc(0);
|
|
ok:
|
|
yylval.y_item = ip;
|
|
return (FBSYM);
|
|
}
|
|
|
|
int hash(const char* p)
|
|
{
|
|
unsigned short h;
|
|
int c;
|
|
|
|
h = 0;
|
|
while ((c = *p++))
|
|
{
|
|
h <<= 2;
|
|
h += c;
|
|
}
|
|
return (h % H_SIZE);
|
|
}
|
|
|
|
item_t* item_search(const char* p)
|
|
{
|
|
int h;
|
|
item_t* ip;
|
|
|
|
for (h = hash(p); h < H_TOTAL; h += H_SIZE)
|
|
{
|
|
ip = hashtab[h];
|
|
while (ip != 0)
|
|
{
|
|
if (strcmp(p, ip->i_name) == 0)
|
|
goto done;
|
|
ip = ip->i_next;
|
|
}
|
|
}
|
|
done:
|
|
hashindex = h;
|
|
return (ip);
|
|
}
|
|
|
|
void item_insert(item_t* ip, int h)
|
|
{
|
|
ip->i_next = hashtab[h];
|
|
hashtab[h] = ip;
|
|
}
|
|
|
|
item_t* item_alloc(int typ)
|
|
{
|
|
item_t* ip;
|
|
static int nleft = 0;
|
|
static item_t* next;
|
|
|
|
if (--nleft < 0)
|
|
{
|
|
next = (item_t*)malloc(MEMINCR);
|
|
if (next == 0)
|
|
fatal("out of memory");
|
|
nleft += (MEMINCR / sizeof(item_t));
|
|
}
|
|
ip = next++;
|
|
ip->i_next = 0;
|
|
ip->i_type = typ;
|
|
ip->i_name = 0;
|
|
ip->i_valu = 0;
|
|
return (ip);
|
|
}
|
|
|
|
item_t* fb_alloc(int lab)
|
|
{
|
|
item_t *ip, *p;
|
|
|
|
ip = item_alloc(S_UND);
|
|
p = fb_ptr[FB_TAIL + lab];
|
|
if (p == 0)
|
|
fb_ptr[FB_HEAD + lab] = ip;
|
|
else
|
|
p->i_next = ip;
|
|
fb_ptr[FB_TAIL + lab] = ip;
|
|
return (ip);
|
|
}
|
|
|
|
item_t* fb_shift(int lab)
|
|
{
|
|
item_t* ip;
|
|
|
|
ip = fb_ptr[FB_FORW + lab];
|
|
if (ip == 0)
|
|
{
|
|
if (pass == PASS_1)
|
|
{
|
|
ip = fb_alloc(lab);
|
|
}
|
|
else
|
|
{
|
|
ip = fb_ptr[FB_HEAD + lab];
|
|
}
|
|
}
|
|
fb_ptr[FB_BACK + lab] = ip;
|
|
fb_ptr[FB_FORW + lab] = ip->i_next;
|
|
return (ip);
|
|
}
|