blob: 32b9c741c74c5b781ea6c598c3e514f4928095c5 [file] [log] [blame]
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +00001//
2// Copyright (c) 2002-2010 The ANGLE Project Authors. All rights reserved.
3// Use of this source code is governed by a BSD-style license that can be
4// found in the LICENSE file.
5//
6/****************************************************************************\
7Copyright (c) 2002, NVIDIA Corporation.
8
9NVIDIA Corporation("NVIDIA") supplies this software to you in
10consideration of your agreement to the following terms, and your use,
11installation, modification or redistribution of this NVIDIA software
12constitutes acceptance of these terms. If you do not agree with these
13terms, please do not use, install, modify or redistribute this NVIDIA
14software.
15
16In consideration of your agreement to abide by the following terms, and
17subject to these terms, NVIDIA grants you a personal, non-exclusive
18license, under NVIDIA's copyrights in this original NVIDIA software (the
19"NVIDIA Software"), to use, reproduce, modify and redistribute the
20NVIDIA Software, with or without modifications, in source and/or binary
21forms; provided that if you redistribute the NVIDIA Software, you must
22retain the copyright notice of NVIDIA, this notice and the following
23text and disclaimers in all such redistributions of the NVIDIA Software.
24Neither the name, trademarks, service marks nor logos of NVIDIA
25Corporation may be used to endorse or promote products derived from the
26NVIDIA Software without specific prior written permission from NVIDIA.
27Except as expressly stated in this notice, no other rights or licenses
28express or implied, are granted by NVIDIA herein, including but not
29limited to any patent rights that may be infringed by your derivative
30works or by other works in which the NVIDIA Software may be
31incorporated. No hardware is licensed hereunder.
32
33THE NVIDIA SOFTWARE IS BEING PROVIDED ON AN "AS IS" BASIS, WITHOUT
34WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED,
35INCLUDING WITHOUT LIMITATION, WARRANTIES OR CONDITIONS OF TITLE,
36NON-INFRINGEMENT, MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, OR
37ITS USE AND OPERATION EITHER ALONE OR IN COMBINATION WITH OTHER
38PRODUCTS.
39
40IN NO EVENT SHALL NVIDIA BE LIABLE FOR ANY SPECIAL, INDIRECT,
41INCIDENTAL, EXEMPLARY, CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
42TO, LOST PROFITS; PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
43USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) OR ARISING IN ANY WAY
44OUT OF THE USE, REPRODUCTION, MODIFICATION AND/OR DISTRIBUTION OF THE
45NVIDIA SOFTWARE, HOWEVER CAUSED AND WHETHER UNDER THEORY OF CONTRACT,
46TORT (INCLUDING NEGLIGENCE), STRICT LIABILITY OR OTHERWISE, EVEN IF
47NVIDIA HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
48\****************************************************************************/
49
50//
51// atom.c
52//
53
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000054#include <stdlib.h>
55#include <stdio.h>
56#include <string.h>
57
alokp@chromium.org91b72322010-06-02 15:50:56 +000058#include "compiler/debug.h"
daniel@transgaming.come6842292010-04-20 18:52:50 +000059#include "compiler/preprocessor/slglobals.h"
daniel@transgaming.com4f39fd92010-03-08 20:26:45 +000060
61#undef malloc
62#undef realloc
63#undef free
64
65///////////////////////////////////////////////////////////////////////////////////////////////
66////////////////////////////////////////// String table: //////////////////////////////////////
67///////////////////////////////////////////////////////////////////////////////////////////////
68
69static const struct {
70 int val;
71 const char *str;
72} tokens[] = {
73 { CPP_AND_OP, "&&" },
74 { CPP_AND_ASSIGN, "&=" },
75 { CPP_SUB_ASSIGN, "-=" },
76 { CPP_MOD_ASSIGN, "%=" },
77 { CPP_ADD_ASSIGN, "+=" },
78 { CPP_DIV_ASSIGN, "/=" },
79 { CPP_MUL_ASSIGN, "*=" },
80 { CPP_RIGHT_BRACKET, ":>" },
81 { CPP_EQ_OP, "==" },
82 { CPP_XOR_OP, "^^" },
83 { CPP_XOR_ASSIGN, "^=" },
84 { CPP_FLOATCONSTANT, "<float-const>" },
85 { CPP_GE_OP, ">=" },
86 { CPP_RIGHT_OP, ">>" },
87 { CPP_RIGHT_ASSIGN, ">>=" },
88 { CPP_IDENTIFIER, "<ident>" },
89 { CPP_INTCONSTANT, "<int-const>" },
90 { CPP_LE_OP, "<=" },
91 { CPP_LEFT_OP, "<<" },
92 { CPP_LEFT_ASSIGN, "<<=" },
93 { CPP_LEFT_BRACKET, "<:" },
94 { CPP_LEFT_BRACE, "<%" },
95 { CPP_DEC_OP, "--" },
96 { CPP_RIGHT_BRACE, "%>" },
97 { CPP_NE_OP, "!=" },
98 { CPP_OR_OP, "||" },
99 { CPP_OR_ASSIGN, "|=" },
100 { CPP_INC_OP, "++" },
101 { CPP_STRCONSTANT, "<string-const>" },
102 { CPP_TYPEIDENTIFIER, "<type-ident>" },
103};
104
105///////////////////////////////////////////////////////////////////////////////////////////////
106////////////////////////////////////////// String table: //////////////////////////////////////
107///////////////////////////////////////////////////////////////////////////////////////////////
108
109#define INIT_STRING_TABLE_SIZE 16384
110
111typedef struct StringTable_Rec {
112 char *strings;
113 int nextFree;
114 int size;
115} StringTable;
116
117/*
118 * InitStringTable() - Initialize the string table.
119 *
120 */
121
122static int InitStringTable(StringTable *stable)
123{
124 stable->strings = (char *) malloc(INIT_STRING_TABLE_SIZE);
125 if (!stable->strings)
126 return 0;
127 // Zero-th offset means "empty" so don't use it.
128 stable->nextFree = 1;
129 stable->size = INIT_STRING_TABLE_SIZE;
130 return 1;
131} // InitStringTable
132
133/*
134 * FreeStringTable() - Free the string table.
135 *
136 */
137
138static void FreeStringTable(StringTable *stable)
139{
140 if (stable->strings)
141 free(stable->strings);
142 stable->strings = NULL;
143 stable->nextFree = 0;
144 stable->size = 0;
145} // FreeStringTable
146
147/*
148 * HashString() - Hash a string with the base hash function.
149 *
150 */
151
152static int HashString(const char *s)
153{
154 int hval = 0;
155
156 while (*s) {
157 hval = (hval*13507 + *s*197) ^ (hval >> 2);
158 s++;
159 }
160 return hval & 0x7fffffff;
161} // HashString
162
163/*
164 * HashString2() - Hash a string with the incrimenting hash function.
165 *
166 */
167
168static int HashString2(const char *s)
169{
170 int hval = 0;
171
172 while (*s) {
173 hval = (hval*729 + *s*37) ^ (hval >> 1);
174 s++;
175 }
176 return hval;
177} // HashString2
178
179/*
180 * AddString() - Add a string to a string table. Return it's offset.
181 *
182 */
183
184static int AddString(StringTable *stable, const char *s)
185{
186 int len, loc;
187 char *str;
188
189 len = (int) strlen(s);
190 if (stable->nextFree + len + 1 >= stable->size) {
191 assert(stable->size < 1000000);
192 str = (char *) malloc(stable->size*2);
193 memcpy(str, stable->strings, stable->size);
194 free(stable->strings);
195 stable->strings = str;
196 }
197 loc = stable->nextFree;
198 strcpy(&stable->strings[loc], s);
199 stable->nextFree += len + 1;
200 return loc;
201} // AddString
202
203///////////////////////////////////////////////////////////////////////////////////////////////
204/////////////////////////////////////////// Hash table: ///////////////////////////////////////
205///////////////////////////////////////////////////////////////////////////////////////////////
206
207#define INIT_HASH_TABLE_SIZE 2047
208#define HASH_TABLE_MAX_COLLISIONS 3
209
210typedef struct HashEntry_Rec {
211 int index; // String table offset of string representation
212 int value; // Atom (symbol) value
213} HashEntry;
214
215typedef struct HashTable_Rec {
216 HashEntry *entry;
217 int size;
218 int entries;
219 int counts[HASH_TABLE_MAX_COLLISIONS + 1];
220} HashTable;
221
222/*
223 * InitHashTable() - Initialize the hash table.
224 *
225 */
226
227static int InitHashTable(HashTable *htable, int fsize)
228{
229 int ii;
230
231 htable->entry = (HashEntry *) malloc(sizeof(HashEntry)*fsize);
232 if (!htable->entry)
233 return 0;
234 htable->size = fsize;
235 for (ii = 0; ii < fsize; ii++) {
236 htable->entry[ii].index = 0;
237 htable->entry[ii].value = 0;
238 }
239 htable->entries = 0;
240 for (ii = 0; ii <= HASH_TABLE_MAX_COLLISIONS; ii++)
241 htable->counts[ii] = 0;
242 return 1;
243} // InitHashTable
244
245/*
246 * FreeHashTable() - Free the hash table.
247 *
248 */
249
250static void FreeHashTable(HashTable *htable)
251{
252 if (htable->entry)
253 free(htable->entry);
254 htable->entry = NULL;
255 htable->size = 0;
256 htable->entries = 0;
257} // FreeHashTable
258
259/*
260 * Empty() - See if a hash table entry is empty.
261 *
262 */
263
264static int Empty(HashTable *htable, int hashloc)
265{
266 assert(hashloc >= 0 && hashloc < htable->size);
267 if (htable->entry[hashloc].index == 0) {
268 return 1;
269 } else {
270 return 0;
271 }
272} // Empty
273
274/*
275 * Match() - See if a hash table entry is matches a string.
276 *
277 */
278
279static int Match(HashTable *htable, StringTable *stable, const char *s, int hashloc)
280{
281 int strloc;
282
283 strloc = htable->entry[hashloc].index;
284 if (!strcmp(s, &stable->strings[strloc])) {
285 return 1;
286 } else {
287 return 0;
288 }
289} // Match
290
291///////////////////////////////////////////////////////////////////////////////////////////////
292/////////////////////////////////////////// Atom table: ///////////////////////////////////////
293///////////////////////////////////////////////////////////////////////////////////////////////
294
295#define INIT_ATOM_TABLE_SIZE 1024
296
297
298struct AtomTable_Rec {
299 StringTable stable; // String table.
300 HashTable htable; // Hashes string to atom number and token value. Multiple strings can
301 // have the same token value but each unique string is a unique atom.
302 int *amap; // Maps atom value to offset in string table. Atoms all map to unique
303 // strings except for some undefined values in the lower, fixed part
304 // of the atom table that map to "<undefined>". The lowest 256 atoms
305 // correspond to single character ASCII values except for alphanumeric
306 // characters and '_', which can be other tokens. Next come the
307 // language tokens with their atom values equal to the token value.
308 // Then come predefined atoms, followed by user specified identifiers.
309 int *arev; // Reversed atom for symbol table use.
310 int nextFree;
311 int size;
312};
313
314static AtomTable latable = { { 0 } };
315AtomTable *atable = &latable;
316
317static int AddAtomFixed(AtomTable *atable, const char *s, int atom);
318
319/*
320 * GrowAtomTable() - Grow the atom table to at least "size" if it's smaller.
321 *
322 */
323
324static int GrowAtomTable(AtomTable *atable, int size)
325{
326 int *newmap, *newrev;
327
328 if (atable->size < size) {
329 if (atable->amap) {
330 newmap = realloc(atable->amap, sizeof(int)*size);
331 newrev = realloc(atable->arev, sizeof(int)*size);
332 } else {
333 newmap = malloc(sizeof(int)*size);
334 newrev = malloc(sizeof(int)*size);
335 atable->size = 0;
336 }
337 if (!newmap || !newrev) {
338 /* failed to grow -- error */
339 if (newmap)
340 atable->amap = newmap;
341 if (newrev)
342 atable->amap = newrev;
343 return -1;
344 }
345 memset(&newmap[atable->size], 0, (size - atable->size) * sizeof(int));
346 memset(&newrev[atable->size], 0, (size - atable->size) * sizeof(int));
347 atable->amap = newmap;
348 atable->arev = newrev;
349 atable->size = size;
350 }
351 return 0;
352} // GrowAtomTable
353
354/*
355 * lReverse() - Reverse the bottom 20 bits of a 32 bit int.
356 *
357 */
358
359static int lReverse(int fval)
360{
361 unsigned int in = fval;
362 int result = 0, cnt = 0;
363
364 while(in) {
365 result <<= 1;
366 result |= in&1;
367 in >>= 1;
368 cnt++;
369 }
370
371 // Don't use all 31 bits. One million atoms is plenty and sometimes the
372 // upper bits are used for other things.
373
374 if (cnt < 20)
375 result <<= 20 - cnt;
376 return result;
377} // lReverse
378
379/*
380 * AllocateAtom() - Allocate a new atom. Associated with the "undefined" value of -1.
381 *
382 */
383
384static int AllocateAtom(AtomTable *atable)
385{
386 if (atable->nextFree >= atable->size)
387 GrowAtomTable(atable, atable->nextFree*2);
388 atable->amap[atable->nextFree] = -1;
389 atable->arev[atable->nextFree] = lReverse(atable->nextFree);
390 atable->nextFree++;
391 return atable->nextFree - 1;
392} // AllocateAtom
393
394/*
395 * SetAtomValue() - Allocate a new atom associated with "hashindex".
396 *
397 */
398
399static void SetAtomValue(AtomTable *atable, int atomnumber, int hashindex)
400{
401 atable->amap[atomnumber] = atable->htable.entry[hashindex].index;
402 atable->htable.entry[hashindex].value = atomnumber;
403} // SetAtomValue
404
405/*
406 * FindHashLoc() - Find the hash location for this string. Return -1 it hash table is full.
407 *
408 */
409
410static int FindHashLoc(AtomTable *atable, const char *s)
411{
412 int hashloc, hashdelta, count;
413 int FoundEmptySlot = 0;
414 int collision[HASH_TABLE_MAX_COLLISIONS + 1];
415
416 hashloc = HashString(s) % atable->htable.size;
417 if (!Empty(&atable->htable, hashloc)) {
418 if (Match(&atable->htable, &atable->stable, s, hashloc))
419 return hashloc;
420 collision[0] = hashloc;
421 hashdelta = HashString2(s);
422 count = 0;
423 while (count < HASH_TABLE_MAX_COLLISIONS) {
424 hashloc = ((hashloc + hashdelta) & 0x7fffffff) % atable->htable.size;
425 if (!Empty(&atable->htable, hashloc)) {
426 if (Match(&atable->htable, &atable->stable, s, hashloc)) {
427 return hashloc;
428 }
429 } else {
430 FoundEmptySlot = 1;
431 break;
432 }
433 count++;
434 collision[count] = hashloc;
435 }
436
437 if (!FoundEmptySlot) {
438 if (cpp->options.DumpAtomTable) {
439 int ii;
440 char str[200];
441 sprintf(str, "*** Hash failed with more than %d collisions. Must increase hash table size. ***",
442 HASH_TABLE_MAX_COLLISIONS);
443 CPPShInfoLogMsg(str);
444
445 sprintf(str, "*** New string \"%s\", hash=%04x, delta=%04x", s, collision[0], hashdelta);
446 CPPShInfoLogMsg(str);
447 for (ii = 0; ii <= HASH_TABLE_MAX_COLLISIONS; ii++) {
448 sprintf(str, "*** Collides on try %d at hash entry %04x with \"%s\"",
449 ii + 1, collision[ii], GetAtomString(atable, atable->htable.entry[collision[ii]].value));
450 CPPShInfoLogMsg(str);
451 }
452 }
453 return -1;
454 } else {
455 atable->htable.counts[count]++;
456 }
457 }
458 return hashloc;
459} // FindHashLoc
460
461/*
462 * IncreaseHashTableSize()
463 *
464 */
465
466static int IncreaseHashTableSize(AtomTable *atable)
467{
468 int ii, strloc, oldhashloc, value, size;
469 AtomTable oldtable;
470 char *s;
471
472 // Save the old atom table and create a new one:
473
474 oldtable = *atable;
475 size = oldtable.htable.size*2 + 1;
476 if (!InitAtomTable(atable, size))
477 return 0;
478
479 // Add all the existing values to the new atom table preserving their atom values:
480
481 for (ii = atable->nextFree; ii < oldtable.nextFree; ii++) {
482 strloc = oldtable.amap[ii];
483 s = &oldtable.stable.strings[strloc];
484 oldhashloc = FindHashLoc(&oldtable, s);
485 assert(oldhashloc >= 0);
486 value = oldtable.htable.entry[oldhashloc].value;
487 AddAtomFixed(atable, s, value);
488 }
489 FreeAtomTable(&oldtable);
490 return 1;
491} // IncreaseHashTableSize
492
493/*
494 * LookUpAddStringHash() - Lookup a string in the hash table. If it's not there, add it and
495 * initialize the atom value in the hash table to 0. Return the hash table index.
496 */
497
498static int LookUpAddStringHash(AtomTable *atable, const char *s)
499{
500 int hashloc, strloc;
501
502 while(1) {
503 hashloc = FindHashLoc(atable, s);
504 if (hashloc >= 0)
505 break;
506 IncreaseHashTableSize(atable);
507 }
508
509 if (Empty(&atable->htable, hashloc)) {
510 atable->htable.entries++;
511 strloc = AddString(&atable->stable, s);
512 atable->htable.entry[hashloc].index = strloc;
513 atable->htable.entry[hashloc].value = 0;
514 }
515 return hashloc;
516} // LookUpAddStringHash
517
518/*
519 * LookUpAddString() - Lookup a string in the hash table. If it's not there, add it and
520 * initialize the atom value in the hash table to the next atom number.
521 * Return the atom value of string.
522 */
523
524int LookUpAddString(AtomTable *atable, const char *s)
525{
526 int hashindex, atom;
527
528 hashindex = LookUpAddStringHash(atable, s);
529 atom = atable->htable.entry[hashindex].value;
530 if (atom == 0) {
531 atom = AllocateAtom(atable);
532 SetAtomValue(atable, atom, hashindex);
533 }
534 return atom;
535} // LookUpAddString
536
537/*
538 * GetAtomString()
539 *
540 */
541
542const char *GetAtomString(AtomTable *atable, int atom)
543{
544 int soffset;
545
546 if (atom > 0 && atom < atable->nextFree) {
547 soffset = atable->amap[atom];
548 if (soffset > 0 && soffset < atable->stable.nextFree) {
549 return &atable->stable.strings[soffset];
550 } else {
551 return "<internal error: bad soffset>";
552 }
553 } else {
554 if (atom == 0) {
555 return "<null atom>";
556 } else {
557 if (atom == EOF) {
558 return "<EOF>";
559 } else {
560 return "<invalid atom>";
561 }
562 }
563 }
564} // GetAtomString
565
566/*
567 * GetReversedAtom()
568 *
569 */
570
571int GetReversedAtom(AtomTable *atable, int atom)
572{
573 if (atom > 0 && atom < atable->nextFree) {
574 return atable->arev[atom];
575 } else {
576 return 0;
577 }
578} // GetReversedAtom
579
580/*
581 * AddAtom() - Add a string to the atom, hash and string tables if it isn't already there.
582 * Return it's atom index.
583 */
584
585int AddAtom(AtomTable *atable, const char *s)
586{
587 int atom;
588
589 atom = LookUpAddString(atable, s);
590 return atom;
591} // AddAtom
592
593/*
594 * AddAtomFixed() - Add an atom to the hash and string tables if it isn't already there.
595 * Assign it the atom value of "atom".
596 */
597
598static int AddAtomFixed(AtomTable *atable, const char *s, int atom)
599{
600 int hashindex, lsize;
601
602 hashindex = LookUpAddStringHash(atable, s);
603 if (atable->nextFree >= atable->size || atom >= atable->size) {
604 lsize = atable->size*2;
605 if (lsize <= atom)
606 lsize = atom + 1;
607 GrowAtomTable(atable, lsize);
608 }
609 atable->amap[atom] = atable->htable.entry[hashindex].index;
610 atable->htable.entry[hashindex].value = atom;
611 //if (atom >= atable->nextFree)
612 // atable->nextFree = atom + 1;
613 while (atom >= atable->nextFree) {
614 atable->arev[atable->nextFree] = lReverse(atable->nextFree);
615 atable->nextFree++;
616 }
617 return atom;
618} // AddAtomFixed
619
620/*
621 * InitAtomTable() - Initialize the atom table.
622 *
623 */
624
625int InitAtomTable(AtomTable *atable, int htsize)
626{
627 int ii;
628
629 htsize = htsize <= 0 ? INIT_HASH_TABLE_SIZE : htsize;
630 if (!InitStringTable(&atable->stable))
631 return 0;
632 if (!InitHashTable(&atable->htable, htsize))
633 return 0;
634
635 atable->nextFree = 0;
636 atable->amap = NULL;
637 atable->size = 0;
638 GrowAtomTable(atable, INIT_ATOM_TABLE_SIZE);
639 if (!atable->amap)
640 return 0;
641
642 // Initialize lower part of atom table to "<undefined>" atom:
643
644 AddAtomFixed(atable, "<undefined>", 0);
645 for (ii = 0; ii < FIRST_USER_TOKEN_SY; ii++)
646 atable->amap[ii] = atable->amap[0];
647
648 // Add single character tokens to the atom table:
649
650 {
651 const char *s = "~!%^&*()-+=|,.<>/?;:[]{}#";
652 char t[2];
653
654 t[1] = '\0';
655 while (*s) {
656 t[0] = *s;
657 AddAtomFixed(atable, t, s[0]);
658 s++;
659 }
660 }
661
662 // Add multiple character scanner tokens :
663
664 for (ii = 0; ii < sizeof(tokens)/sizeof(tokens[0]); ii++)
665 AddAtomFixed(atable, tokens[ii].str, tokens[ii].val);
666
667 // Add error symbol if running in error mode:
668
669 if (cpp->options.ErrorMode)
670 AddAtomFixed(atable, "error", ERROR_SY);
671
672 AddAtom(atable, "<*** end fixed atoms ***>");
673
674 return 1;
675} // InitAtomTable
676
677///////////////////////////////////////////////////////////////////////////////////////////////
678////////////////////////////////// Debug Printing Functions: //////////////////////////////////
679///////////////////////////////////////////////////////////////////////////////////////////////
680
681/*
682 * PrintAtomTable()
683 *
684 */
685
686void PrintAtomTable(AtomTable *atable)
687{
688 int ii;
689 char str[200];
690
691 for (ii = 0; ii < atable->nextFree; ii++) {
692 sprintf(str, "%d: \"%s\"", ii, &atable->stable.strings[atable->amap[ii]]);
693 CPPDebugLogMsg(str);
694 }
695 sprintf(str, "Hash table: size=%d, entries=%d, collisions=",
696 atable->htable.size, atable->htable.entries);
697 CPPDebugLogMsg(str);
698 for (ii = 0; ii < HASH_TABLE_MAX_COLLISIONS; ii++) {
699 sprintf(str, " %d", atable->htable.counts[ii]);
700 CPPDebugLogMsg(str);
701 }
702
703} // PrintAtomTable
704
705
706/*
707 * GetStringOfAtom()
708 *
709 */
710
711char* GetStringOfAtom(AtomTable *atable, int atom)
712{
713 char* chr_str;
714 chr_str=&atable->stable.strings[atable->amap[atom]];
715 return chr_str;
716} // GetStringOfAtom
717
718/*
719 * FreeAtomTable() - Free the atom table and associated memory
720 *
721 */
722
723void FreeAtomTable(AtomTable *atable)
724{
725 FreeStringTable(&atable->stable);
726 FreeHashTable(&atable->htable);
727 if (atable->amap)
728 free(atable->amap);
729 if (atable->arev)
730 free(atable->arev);
731 atable->amap = NULL;
732 atable->arev = NULL;
733 atable->nextFree = 0;
734 atable->size = 0;
735} // FreeAtomTable
736
737///////////////////////////////////////////////////////////////////////////////////////////////
738///////////////////////////////////////// End of atom.c ///////////////////////////////////////
739///////////////////////////////////////////////////////////////////////////////////////////////
740