247 lines
4.8 KiB
C
247 lines
4.8 KiB
C
/*
|
|
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
|
|
* See the copyright notice in the ACK home directory, in the file "Copyright".
|
|
*
|
|
*/
|
|
|
|
/*
|
|
* L L G E N
|
|
*
|
|
* An Extended LL(1) Parser Generator
|
|
*
|
|
* Author : Ceriel J.H. Jacobs
|
|
*/
|
|
|
|
/*
|
|
* name.c
|
|
* Defines the symboltable search routine, a name store routine and an
|
|
* initialising routine.
|
|
*/
|
|
|
|
# include "types.h"
|
|
# include "extern.h"
|
|
# include "assert.h"
|
|
# include "io.h"
|
|
|
|
# ifndef NORCSID
|
|
static string rcsid7 = "$Header$";
|
|
# endif
|
|
|
|
# define HASHSIZE 128
|
|
# define NMSIZ 2048 /* Room for names allocated NMSIZ bytes at a time */
|
|
|
|
static char *name, *maxname;
|
|
static p_entry h_root[HASHSIZE]; /* hash table */
|
|
static string e_literal = "Illegal literal";
|
|
static p_entry entries, maxentries;
|
|
static t_info token_info, nont_info;
|
|
|
|
/* Defined in this file are: */
|
|
extern string store();
|
|
extern name_init();
|
|
STATIC int hash();
|
|
STATIC p_entry newentry();
|
|
extern p_gram search();
|
|
|
|
p_mem alloc();
|
|
p_mem new_mem();
|
|
|
|
name_init() {
|
|
token_info.i_esize = sizeof (t_token);
|
|
token_info.i_incr = 50;
|
|
nont_info.i_esize = sizeof (t_nont);
|
|
nont_info.i_incr = 50;
|
|
search(TERMINAL,"EOFILE",ENTERING);
|
|
}
|
|
|
|
STATIC p_entry
|
|
newentry(str, next) string str; p_entry next; {
|
|
register p_entry p;
|
|
|
|
if ((p = entries) == maxentries) {
|
|
p = (p_entry) alloc(50 * sizeof(t_entry));
|
|
maxentries = p + 50;
|
|
}
|
|
entries = p + 1;
|
|
p->h_name = str;
|
|
p->h_next = next;
|
|
p->h_type.g_lineno = linecount;
|
|
return p;
|
|
}
|
|
|
|
string
|
|
store(s) string s; {
|
|
/*
|
|
* Store a string s in the name table
|
|
*/
|
|
register string s1, t ,u;
|
|
|
|
u = name;
|
|
t = s;
|
|
s1 = u;
|
|
do {
|
|
if (u >= maxname) {
|
|
u = alloc(NMSIZ);
|
|
maxname = u + NMSIZ;
|
|
t = s;
|
|
s1 = u;
|
|
}
|
|
*u++ = *t;
|
|
} while (*t++);
|
|
name = u;
|
|
return s1;
|
|
}
|
|
|
|
STATIC int
|
|
hash(str) string str; {
|
|
/*
|
|
* Compute the hash for string str
|
|
*/
|
|
register int i;
|
|
register string l;
|
|
|
|
l = str;
|
|
i = 0;
|
|
while (*l != '\0') i += *l++ & 0377;
|
|
i += l - str;
|
|
return i % HASHSIZE;
|
|
}
|
|
|
|
p_gram
|
|
search(type,str,option) register string str; {
|
|
/*
|
|
* Search for object str.
|
|
* It has type UNKNOWN, LITERAL, TERMINAL or NONTERM.
|
|
* option can be ENTERING or BOTH (also looking).
|
|
*/
|
|
register int val;
|
|
register p_entry p;
|
|
register int i;
|
|
int type1;
|
|
|
|
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)) {
|
|
type1 = g_gettype(&(p->h_type));
|
|
if (type1 != type) {
|
|
if (type1 == LITERAL || type == LITERAL) {
|
|
continue;
|
|
}
|
|
if (type == TERMINAL) {
|
|
error(linecount,
|
|
"%s: is already a nonterminal",
|
|
str);
|
|
continue;
|
|
}
|
|
else if (type == NONTERM) {
|
|
error(linecount,
|
|
"%s : is already a token",
|
|
str);
|
|
continue;
|
|
}
|
|
}
|
|
if (option==ENTERING) {
|
|
error(linecount,
|
|
"%s : is already defined",str);
|
|
}
|
|
p->h_type.g_lineno = linecount;
|
|
return &(p->h_type);
|
|
}
|
|
}
|
|
p = newentry(store(str), h_root[i]);
|
|
h_root[i] = p;
|
|
if (type == TERMINAL || type == LITERAL) {
|
|
register p_token pt;
|
|
|
|
pt = (p_token) new_mem(&token_info);
|
|
tokens = (p_token) token_info.i_ptr;
|
|
pt->t_string = p->h_name;
|
|
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);
|
|
}
|
|
pt->t_tokno = val;
|
|
g_settype(&(p->h_type), LITERAL);
|
|
} else {
|
|
/*
|
|
* Here, type = TERMINAL
|
|
*/
|
|
pt->t_tokno = assval++;
|
|
g_settype(&(p->h_type), TERMINAL);
|
|
}
|
|
g_setcont(&(p->h_type), ntokens);
|
|
ntokens++;
|
|
return &(p->h_type);
|
|
}
|
|
/*
|
|
* type == NONTERM || type == UNKNOWN
|
|
* UNKNOWN and not yet declared means : NONTERM
|
|
*/
|
|
{
|
|
register p_nont q;
|
|
|
|
q = (p_nont) new_mem(&nont_info);
|
|
nonterms = (p_nont) nont_info.i_ptr;
|
|
q->n_name = p->h_name;
|
|
q->n_rule = 0;
|
|
q->n_lineno = linecount;
|
|
q->n_string = f_input;
|
|
q->n_follow = 0;
|
|
q->n_flags = 0;
|
|
q->n_contains = 0;
|
|
g_settype(&(p->h_type), NONTERM);
|
|
g_setcont(&(p->h_type), nnonterms);
|
|
g_setnpar(&(p->h_type), 0);
|
|
nnonterms++;
|
|
return &(p->h_type);
|
|
}
|
|
}
|