OLD | NEW |
1 // Copyright 2006-2008 the V8 project authors. All rights reserved. | 1 // Copyright 2006-2008 the V8 project authors. All rights reserved. |
2 // Redistribution and use in source and binary forms, with or without | 2 // Redistribution and use in source and binary forms, with or without |
3 // modification, are permitted provided that the following conditions are | 3 // modification, are permitted provided that the following conditions are |
4 // met: | 4 // met: |
5 // | 5 // |
6 // * Redistributions of source code must retain the above copyright | 6 // * Redistributions of source code must retain the above copyright |
7 // notice, this list of conditions and the following disclaimer. | 7 // notice, this list of conditions and the following disclaimer. |
8 // * Redistributions in binary form must reproduce the above | 8 // * Redistributions in binary form must reproduce the above |
9 // copyright notice, this list of conditions and the following | 9 // copyright notice, this list of conditions and the following |
10 // disclaimer in the documentation and/or other materials provided | 10 // disclaimer in the documentation and/or other materials provided |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
48 #undef T | 48 #undef T |
49 | 49 |
50 | 50 |
51 #define T(name, string, precedence) precedence, | 51 #define T(name, string, precedence) precedence, |
52 int8_t Token::precedence_[NUM_TOKENS] = { | 52 int8_t Token::precedence_[NUM_TOKENS] = { |
53 TOKEN_LIST(T, T, IGNORE_TOKEN) | 53 TOKEN_LIST(T, T, IGNORE_TOKEN) |
54 }; | 54 }; |
55 #undef T | 55 #undef T |
56 | 56 |
57 | 57 |
58 // A perfect (0 collision) hash table of keyword token values. | |
59 | |
60 // larger N will reduce the number of collisions (power of 2 for fast %) | |
61 const unsigned int N = 128; | |
62 // make this small since we have <= 256 tokens | |
63 static uint8_t Hashtable[N]; | |
64 static bool IsInitialized = false; | |
65 | |
66 | |
67 static unsigned int Hash(const char* s) { | |
68 // The following constants have been found using trial-and-error. If the | |
69 // keyword set changes, they may have to be recomputed (make them flags | |
70 // and play with the flag values). Increasing N is the simplest way to | |
71 // reduce the number of collisions. | |
72 | |
73 // we must use at least 4 or more chars ('const' and 'continue' share | |
74 // 'con') | |
75 const unsigned int L = 5; | |
76 // smaller S tend to reduce the number of collisions | |
77 const unsigned int S = 4; | |
78 // make this a prime, or at least an odd number | |
79 const unsigned int M = 3; | |
80 | |
81 unsigned int h = 0; | |
82 for (unsigned int i = 0; s[i] != '\0' && i < L; i++) { | |
83 h += (h << S) + s[i]; | |
84 } | |
85 // unsigned int % by a power of 2 (otherwise this will not be a bit mask) | |
86 return h * M % N; | |
87 } | |
88 | |
89 | |
90 Token::Value Token::Lookup(const char* str) { | |
91 ASSERT(IsInitialized); | |
92 Value k = static_cast<Value>(Hashtable[Hash(str)]); | |
93 const char* s = string_[k]; | |
94 ASSERT(s != NULL || k == IDENTIFIER); | |
95 if (s == NULL || strcmp(s, str) == 0) { | |
96 return k; | |
97 } | |
98 return IDENTIFIER; | |
99 } | |
100 | |
101 | |
102 #ifdef DEBUG | |
103 // We need this function because C++ doesn't allow the expression | |
104 // NULL == NULL, which is a result of macro expansion below. What | |
105 // the hell? | |
106 static bool IsNull(const char* s) { | |
107 return s == NULL; | |
108 } | |
109 #endif | |
110 | |
111 | |
112 void Token::Initialize() { | |
113 if (IsInitialized) return; | |
114 | |
115 // A list of all keywords, terminated by ILLEGAL. | |
116 #define T(name, string, precedence) name, | |
117 static Value keyword[] = { | |
118 TOKEN_LIST(IGNORE_TOKEN, T, IGNORE_TOKEN) | |
119 ILLEGAL | |
120 }; | |
121 #undef T | |
122 | |
123 // Assert that the keyword array contains the 25 keywords, 3 future | |
124 // reserved words (const, debugger, and native), and the 3 named literals | |
125 // defined by ECMA-262 standard. | |
126 ASSERT(ARRAY_SIZE(keyword) == 25 + 3 + 3 + 1); // +1 for ILLEGAL sentinel | |
127 | |
128 // Initialize Hashtable. | |
129 ASSERT(NUM_TOKENS <= 256); // Hashtable contains uint8_t elements | |
130 for (unsigned int i = 0; i < N; i++) { | |
131 Hashtable[i] = IDENTIFIER; | |
132 } | |
133 | |
134 // Insert all keywords into Hashtable. | |
135 int collisions = 0; | |
136 for (int i = 0; keyword[i] != ILLEGAL; i++) { | |
137 Value k = keyword[i]; | |
138 unsigned int h = Hash(string_[k]); | |
139 if (Hashtable[h] != IDENTIFIER) collisions++; | |
140 Hashtable[h] = k; | |
141 } | |
142 | |
143 if (collisions > 0) { | |
144 PrintF("%d collisions in keyword hashtable\n", collisions); | |
145 FATAL("Fix keyword lookup!"); | |
146 } | |
147 | |
148 IsInitialized = true; | |
149 | |
150 // Verify hash table. | |
151 #define T(name, string, precedence) \ | |
152 ASSERT(IsNull(string) || Lookup(string) == IDENTIFIER); | |
153 | |
154 #define K(name, string, precedence) \ | |
155 ASSERT(Lookup(string) == name); | |
156 | |
157 TOKEN_LIST(T, K, IGNORE_TOKEN) | |
158 | |
159 #undef K | |
160 #undef T | |
161 } | |
162 | |
163 } } // namespace v8::internal | 58 } } // namespace v8::internal |
OLD | NEW |