239 lines
4.8 KiB
C
239 lines
4.8 KiB
C
/*
|
|
* (c) copyright 1983 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
|
*
|
|
* This product is part of the Amsterdam Compiler Kit.
|
|
*
|
|
* Permission to use, sell, duplicate or disclose this software must be
|
|
* obtained in writing. Requests for such permissions may be sent to
|
|
*
|
|
* Dr. Andrew S. Tanenbaum
|
|
* Wiskundig Seminarium
|
|
* Vrije Universiteit
|
|
* Postbox 7161
|
|
* 1007 MC Amsterdam
|
|
* The Netherlands
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* L L G E N
|
|
*
|
|
* An Extended LL(1) Parser Generator
|
|
*
|
|
* Author : Ceriel J.H. Jacobs
|
|
*/
|
|
|
|
/*
|
|
* name.c
|
|
* Defines the symboltable search routine and an initialising routine
|
|
*/
|
|
|
|
# include "types.h"
|
|
# include "tunable.h"
|
|
# include "extern.h"
|
|
# include "assert.h"
|
|
# include "io.h"
|
|
|
|
static string rcsid = "$Header$";
|
|
|
|
# define HASHSIZE 128
|
|
|
|
static char name[NAMESZ]; /* space for names */
|
|
static int iname; /* index in nametable */
|
|
static p_entry h_root[HASHSIZE]; /* hash table */
|
|
static string e_literal = "Illegal literal";
|
|
|
|
/* Defined in this file are: */
|
|
extern string store();
|
|
extern name_init();
|
|
STATIC int hash();
|
|
extern t_gram search();
|
|
|
|
string
|
|
store(s) register string s; {
|
|
/*
|
|
* Store a string s in the name table
|
|
*/
|
|
register string t,u;
|
|
|
|
u = t = &name[iname];
|
|
do { if (u > &name[NAMESZ-1]) fatal(linecount,"name table overflow");
|
|
else *u++ = *s;
|
|
} while (*s++);
|
|
iname = u - name;
|
|
return t;
|
|
}
|
|
|
|
name_init() {
|
|
/*
|
|
* Initialise hash-table and enter special terminal EOFILE
|
|
*/
|
|
register p_entry *p;
|
|
t_gram search();
|
|
|
|
for(p = h_root; p<= &h_root[HASHSIZE-1]; p++) *p = 0;
|
|
search(TERMINAL,"EOFILE",ENTERING);
|
|
}
|
|
|
|
STATIC int
|
|
hash(str) string str; {
|
|
/*
|
|
* Compute the hash for string str
|
|
*/
|
|
register i;
|
|
register string l;
|
|
|
|
l = str;
|
|
i = 0;
|
|
while (*l != '\0') i += *l++ & 0377;
|
|
i += l - str;
|
|
return i % HASHSIZE;
|
|
}
|
|
|
|
t_gram
|
|
search(type,str,option) register string str; {
|
|
/*
|
|
* Search for object str.
|
|
* It has type UNKNOWN, LITERAL, TERMINAL or NONTERM.
|
|
* option can be ENTERING, JUSTLOOKING or BOTH.
|
|
*/
|
|
register int val;
|
|
register p_entry p;
|
|
t_gram r;
|
|
register int i;
|
|
|
|
g_init(&r);
|
|
g_setcont(&r,UNDEFINED);
|
|
r.g_lineno = linecount;
|
|
i = hash(str);
|
|
/*
|
|
* Walk hash chain
|
|
*/
|
|
for (p = h_root[i]; p != (p_entry) 0; p = p->h_next) {
|
|
if(!strcmp(p->h_name,str)) {
|
|
val = p - h_entry;
|
|
if (type == LITERAL &&
|
|
(val >= NTERMINALS || p->h_num >= 0400)) continue;
|
|
if (val>=NTERMINALS) {
|
|
/* Should be a nonterminal */
|
|
if (type == TERMINAL) {
|
|
error(linecount,
|
|
"%s : terminal expected",
|
|
str);
|
|
}
|
|
g_settype(&r,NONTERM);
|
|
g_setnont(&r,val - NTERMINALS);
|
|
} else {
|
|
if (type != LITERAL && p->h_num < 0400) {
|
|
continue;
|
|
}
|
|
if (type == NONTERM) {
|
|
error(linecount,
|
|
"%s : nonterminal expected",
|
|
str);
|
|
continue;
|
|
}
|
|
g_setnont(&r, val);
|
|
g_settype(&r, TERMINAL);
|
|
}
|
|
if (option==ENTERING) {
|
|
error(linecount,
|
|
"%s : already defined",str);
|
|
}
|
|
return r;
|
|
}
|
|
}
|
|
if (option == JUSTLOOKING) return r;
|
|
if (type == TERMINAL || type == LITERAL) {
|
|
if (nterminals == NTERMINALS) {
|
|
fatal(linecount,"too many terminals");
|
|
}
|
|
p = &h_entry[nterminals];
|
|
} else {
|
|
/*
|
|
* type == NONTERM || type == UNKNOWN
|
|
* UNKNOWN and not yet declared means : NONTERM
|
|
*/
|
|
if (nnonterms == NNONTERMS) {
|
|
fatal(linecount,"too many nonterminals");
|
|
}
|
|
p = &h_entry[NTERMINALS+nnonterms];
|
|
}
|
|
p->h_name = store(str);
|
|
p->h_next = h_root[i];
|
|
h_root[i] = p;
|
|
if (type == NONTERM || type == UNKNOWN) {
|
|
register p_nont q;
|
|
|
|
q = &nonterms[nnonterms];
|
|
q->n_rule = 0;
|
|
q->n_string = f_input;
|
|
q->n_follow = 0;
|
|
q->n_flags = 0;
|
|
q->n_contains = 0;
|
|
p->h_num = 0;
|
|
g_settype(&r, NONTERM);
|
|
g_setnont(&r, nnonterms);
|
|
nnonterms++;
|
|
return r;
|
|
}
|
|
if (type == LITERAL) {
|
|
if (str[0] == '\\') {
|
|
/*
|
|
* Handle escapes in literals
|
|
*/
|
|
if (str[2] == '\0') {
|
|
switch(str[1]) {
|
|
case 'n' :
|
|
val = '\n';
|
|
break;
|
|
case 'r' :
|
|
val = '\r';
|
|
break;
|
|
case 'b' :
|
|
val = '\b';
|
|
break;
|
|
case 'f' :
|
|
val = '\f';
|
|
break;
|
|
case 't' :
|
|
val = '\t';
|
|
break;
|
|
case '\'':
|
|
val = '\'';
|
|
break;
|
|
case '\\':
|
|
val = '\\';
|
|
break;
|
|
default :
|
|
error(linecount,e_literal);
|
|
}
|
|
} else {
|
|
/*
|
|
* Here, str[2] != '\0'
|
|
*/
|
|
if (str[1] > '3' || str[1] < '0' ||
|
|
str[2] > '7' || str[2] < '0' ||
|
|
str[3] > '7' || str[3] < '0' ||
|
|
str[4] != '\0') error(linecount,e_literal);
|
|
val = 64*str[1] - 73*'0' + 8*str[2] + str[3];
|
|
}
|
|
} else {
|
|
/*
|
|
* No escape in literal
|
|
*/
|
|
if (str[1] == '\0') val = str[0];
|
|
else error(linecount,e_literal);
|
|
}
|
|
p->h_num = val;
|
|
} else {
|
|
/*
|
|
* Here, type = TERMINAL
|
|
*/
|
|
p->h_num = assval++;
|
|
}
|
|
g_settype(&r, TERMINAL);
|
|
g_setnont(&r, nterminals);
|
|
nterminals++;
|
|
return r;
|
|
}
|