| /* |
| * 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); |
| } |