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