blob: ea78a3c0df8931830eae53fa0c66506fa40f800d [file] [log] [blame]
/*
* PUBLIC DOMAIN PCCTS-BASED C++ GRAMMAR (cplusplus.g, stat.g, expr.g)
*
* Authors: Sumana Srinivasan, NeXT Inc.; sumana_srinivasan@next.com
* Terence Parr, Parr Research Corporation; parrt@parr-research.com
* Russell Quong, Purdue University; quong@ecn.purdue.edu
*
* VERSION 1.1
*
* SOFTWARE RIGHTS
*
* This file is a part of the ANTLR-based C++ grammar and is free
* software. We do not reserve any LEGAL rights to its use or
* distribution, but you may NOT claim ownership or authorship of this
* grammar or support code. An individual or company may otherwise do
* whatever they wish with the grammar distributed herewith including the
* incorporation of the grammar or the output generated by ANTLR into
* commerical software. You may redistribute in source or binary form
* without payment of royalties to us as long as this header remains
* in all source distributions.
*
* We encourage users to develop parsers/tools using this grammar.
* In return, we ask that credit is given to us for developing this
* grammar. By "credit", we mean that if you incorporate our grammar or
* the generated code into one of your programs (commercial product,
* research project, or otherwise) that you acknowledge this fact in the
* documentation, research report, etc.... In addition, you should say nice
* things about us at every opportunity.
*
* As long as these guidelines are kept, we expect to continue enhancing
* this grammar. Feel free to send us enhancements, fixes, bug reports,
* suggestions, or general words of encouragement at parrt@parr-research.com.
*
* NeXT Computer Inc.
* 900 Chesapeake Dr.
* Redwood City, CA 94555
* 12/02/1994
*
* Restructured for public consumption by Terence Parr late February, 1995.
*
* Requires PCCTS 1.32b4 or higher to get past ANTLR.
*
* DISCLAIMER: we make no guarantees that this grammar works, makes sense,
* or can be used to do anything useful.
*/
/* 1999-2004 Version 3.0 July 2004
* Modified by David Wigg at London South Bank University for CPP_parser.g
*/
/* 2004-2005 Version 3.1 November 2005
* Modified by David Wigg at London South Bank University for CPP_parser.g
*
* See MyReadMe.txt for further information
*
* This file is best viewed in courier font with tabs set to 4 spaces
*
* See NotesScopes.txt for information about storing symbol names within scope
*levels
*
* Symbols names are stored in lists selected by hashing
*
* Symbols are also chained in lists for each scope level,
* [0] = template scope Note: Not used at present
* [1] = external scope Note: These symbols (types) are never deleted.
*"std" is allocated this scope in CPPParser::init()
* [2+]= function/variable scopes Note: These symbol references are
*deleted when they go out of scope.
*/
extern "C" {
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
}
#include "Dictionary.hpp"
/* Hashing function described in */
/* "Fast Hashing of Variable-Length Text Strings," */
/* by Peter K. Pearson, CACM, June 1990. */
/* Table from p. 678.*/
/* Pseudorandom Permutation of the Integers 0 through 255: */
unsigned char Dictionary::randomNumbers[] = {
1, 14, 110, 25, 97, 174, 132, 119, 138, 170, 125, 118, 27, 233, 140,
51, 87, 197, 177, 107, 234, 169, 56, 68, 30, 7, 173, 73, 188, 40,
36, 65, 49, 213, 104, 190, 57, 211, 148, 223, 48, 115, 15, 2, 67,
186, 210, 28, 12, 181, 103, 70, 22, 58, 75, 78, 183, 167, 238, 157,
124, 147, 172, 144, 176, 161, 141, 86, 60, 66, 128, 83, 156, 241, 79,
46, 168, 198, 41, 254, 178, 85, 253, 237, 250, 154, 133, 88, 35, 206,
95, 116, 252, 192, 54, 221, 102, 218, 255, 240, 82, 106, 158, 201, 61,
3, 89, 9, 42, 155, 159, 93, 166, 80, 50, 34, 175, 195, 100, 99,
26, 150, 16, 145, 4, 33, 8, 189, 121, 64, 77, 72, 208, 245, 130,
122, 143, 55, 105, 134, 29, 164, 185, 194, 193, 239, 101, 242, 5, 171,
126, 11, 74, 59, 137, 228, 108, 191, 232, 139, 6, 24, 81, 20, 127,
17, 91, 92, 251, 151, 225, 207, 21, 98, 113, 112, 84, 226, 18, 214,
199, 187, 13, 32, 94, 220, 224, 212, 247, 204, 196, 43, 249, 236, 45,
244, 111, 182, 153, 136, 129, 90, 217, 202, 19, 165, 231, 71, 230, 142,
96, 227, 62, 179, 246, 114, 162, 53, 160, 215, 205, 180, 47, 109, 44,
38, 31, 149, 135, 0, 216, 52, 63, 23, 37, 69, 39, 117, 146, 184,
163, 200, 222, 235, 248, 243, 219, 10, 152, 131, 123, 229, 203, 76, 120,
209};
char *Dictionary::strings = NULL;
char *Dictionary::strp = NULL;
unsigned Dictionary::strsize = 0;
Dictionary::Dictionary(int nb, int ns, int nc) {
int i;
// allocate buckets for names
bucket = new DictEntry *[nb];
if (bucket == NULL) panic((const char *)"can't alloc buckets");
// Initialize buckets for names
nbuckets = nb;
for (i = 0; i < nb; i++) bucket[i] = NULL;
// allocate a scope list for the start of each scope list
scope = new DictEntry *[ns];
if (scope == NULL) panic("can't alloc scopes");
// allocate an endScope list for the end of each scope list
endScope = new DictEntry *[ns];
if (endScope == NULL) panic("can't alloc endScope");
// Initialize scopes and endscopes
nscopes = ns;
for (i = 0; i < ns; i++) {
scope[i] = NULL;
endScope[i] = NULL;
}
currentScope = 0;
strsize = nc;
strings = new char[nc];
strp = strings;
}
Dictionary::~Dictionary() {
delete[] bucket;
delete[] scope;
delete[] endScope;
nbuckets = nscopes = 0;
currentScope = -1;
}
/* Hashing function described in */
/* "Fast Hashing of Variable-Length Text Strings," */
/* by Peter K. Pearson, CACM, June 1990. */
int Dictionary::hash(const char *string) {
int hash1 = 0;
int hash2 = 0;
int length = 0;
int r = 0;
while (*string != 0) {
length++;
/* Hash function is XOR of successive characters randomized by
* the hash table.
*/
hash1 ^= randomNumbers[static_cast<int>(*string++)];
if (*string != 0) hash2 ^= randomNumbers[static_cast<int>(*string++)];
}
r = (hash1 << 8) | hash2;
return r;
}
/* Return ptr to 1st entry found in table under key
* (return NULL if none found).
*/
DictEntry *Dictionary::lookup(const char *key, CPPSymbol::ObjectType tp) {
// tp is type to be looked for
// Default, 0, is to look for any symbol irrespective of type
// Each new DictEntry is stored at start of its list so most
// recent additions are reached first
// DictEntry *q;
CPPSymbol *q;
// int scope = getCurrentScopeIndex();
// if(sc != -1)
// scope = sc;
int h = hash(key) % nbuckets;
q = (CPPSymbol *)bucket[h];
for (; q != NULL; q = (CPPSymbol *)q->getNext()) {
// printf("Dictionary.cpp lookup symbol %s in scope %d current scope %d\n",
// q->getKey(),q->this_scope,getCurrentScopeIndex());
if (h != q->getHashCode()) {
fprintf(stderr,
"dictionary.cpp lookup, h not equal to q->getHashCode() for %s\n",
key);
}
if (h == q->getHashCode() && strcmp(key, q->getKey()) == 0) {
if (tp == 0) { // Search for first matching symbol
return q;
} else {
CPPSymbol::ObjectType type = q->getType();
if (tp == CPPSymbol::otTypename) // Search for first type name
{
if (type == CPPSymbol::otTypedef || type == CPPSymbol::otEnum ||
type == CPPSymbol::otClass || type == CPPSymbol::otStruct ||
type == CPPSymbol::otUnion) {
return q;
}
} else if (tp ==
CPPSymbol::otNonTypename) // Search for first non type name
{
if (type == CPPSymbol::otVariable || type == CPPSymbol::otFunction) {
return q;
}
} else if (type == tp) { // Search for first symbol with specific type
return q;
} else {
return NULL;
}
}
}
}
return NULL;
}
void Dictionary::define(const char *key, DictEntry *entry) {
defineInScope(key, entry, currentScope);
}
void Dictionary::defineInScope(const char *key, DictEntry *entry, int sc) {
int h = hash(key) % nbuckets; // July 2005, nbuckets = 4001 See CPP_parser.g
// printf("Dictionary.cpp defineInScope key %s hash(key) %d bucket %d scope
// %d\n",
// key,hash(key),h,sc);
entry->this_scope = sc;
entry->setKey(strdup(key)); // Make a local copy of key
entry->setHashCode(h);
entry->setNext(bucket[h]); // Set next pointer to current entry in bucket
bucket[h] = entry; // Replace current entry in bucket
if (endScope[sc] == NULL) {
scope[sc] = endScope[sc] = entry;
} else {
endScope[sc]->setScope(entry);
endScope[sc] = entry;
}
}
int Dictionary::getCurrentScopeIndex() { return currentScope; }
DictEntry *Dictionary::getCurrentScope() {
if (currentScope < 0 || currentScope > nscopes) {
panic("getCurrentScope: no scope");
}
return scope[currentScope];
}
void Dictionary::saveScope() {
// Advance scope number (for included scope)
if (currentScope < nscopes) currentScope++;
/*
if ( currentScope>=nscopes )
panic( "saveScope: overflow" );
*/
// printf("Dictionary saveScope entered. Scope now %d\n",currentScope);
}
void Dictionary::restoreScope() {
// Reduce scope number for next highest scope
// if ( currentScope==0 )
// panic( "restoreScope: underflow" );
if (currentScope > 0) currentScope--;
// printf("Dictionary restoreScope entered. Scope now %d\n",currentScope);
}
/* This unlinks all entries from the Dictionary that are members
* of the current scope. The scope level is not restored to the previous
* scope however. This requires use of restoreScope() above
*/
DictEntry *Dictionary::removeScope(int sc) {
DictEntry *de, *r;
if (sc == -1) { // removeScope() without parameter value defaults sc to -1
sc = currentScope;
}
for (de = scope[sc]; de != NULL; de = de->getNextInScope()) {
remove(de);
}
r = scope[sc];
scope[sc] = endScope[sc] = NULL;
return r;
}
// Remove this dictEntry from its bucket by unlinking it
DictEntry *Dictionary::remove(DictEntry *de) {
DictEntry *prev, *curr;
if (de == NULL) panic("Dictionary.cpp remove: NULL ptr");
int h = hash(de->getKey()) % nbuckets; // Find pointer to bucket
for (prev = NULL, curr = bucket[h]; curr != NULL;
prev = curr, curr = curr->getNext()) {
if (de == curr) {
if (prev == NULL) {
bucket[h] = de->getNext();
} else {
prev->setNext(de->getNext());
}
de->setNext(NULL);
return de;
}
}
return NULL; // should never get here...
}
/* Lookup the object referred to by 'key' and then physically remove
* it from the Dictionary. Return the object referred to by the key.
* If more than one definition is found for 'key', then only the
* first one is removed. Return NULL if not found.
* Note: DW 12/06/03 Probably not used
*/
DictEntry *Dictionary::remove(char *key) {
DictEntry *q, *prev;
int h = hash(key) % nbuckets;
for (prev = NULL, q = bucket[h]; q != NULL; prev = q, q = q->getNext()) {
if (h == q->getHashCode() && strcmp(key, q->getKey()) == 0) {
if (prev == NULL) {
bucket[h] = q->getNext();
} else {
prev->setNext(q->getNext());
}
q->setNext(NULL);
return q;
}
}
return NULL; // should never get here, but make compiler happy
}
void Dictionary::dumpScope(FILE *f, int sc) {
DictEntry *s;
if (sc == -1) { // dumpScope() without parameter value defaults sc to -1
sc = currentScope;
}
for (s = scope[sc]; s != NULL; s = s->getNextInScope()) {
dumpSymbol(f, s);
}
}
// This is overridden in CPPDictionary.hpp
void Dictionary::dumpSymbol(FILE *f, DictEntry *de) {
fprintf(f, "%s\n", de->getKey());
}
// Diagnostic function
// Contents of first 10 scopes printed
void Dictionary::dumpScopes() {
DictEntry *dictEntry;
int i;
printf("Scopes");
for (i = 0; i < 10; i++) {
printf(" %d ", i);
}
printf("\n");
printf(" first");
for (i = 0; i < 10; i++) {
if (scope[i] != NULL) {
dictEntry = scope[i];
printf("%10s ", dictEntry->getKey());
} else {
printf(" ");
}
}
printf("\n");
printf(" last ");
for (i = 0; i < 10; i++) {
if (endScope[i] != NULL) {
dictEntry = endScope[i];
printf("%10s ", dictEntry->getKey());
} else {
printf(" ");
}
}
printf("\n");
}
/* Add a string to the string table and return a pointer to it.
* Bump the pointer into the string table to next avail position.
*/
char *Dictionary::strdup(const char *s) {
char *start = strp;
if (s == NULL) panic("strdup: NULL string");
if (start + strlen(s) + 1 > &(strings[strsize - 2])) {
panic("string table overflow");
}
while (*s != '\0') {
*strp++ = *s++;
}
*strp++ = '\0';
return start;
}
void Dictionary::panic(const char *err) {
fprintf(stdout, "Dictionary panic: %s\n", err);
exit(-1);
}