1 module ddparser.symtab; 2 3 import std.bitmanip; 4 import ddparser.util; 5 6 import core.stdc.string; 7 import core.stdc.stdio; 8 9 enum INITIAL_SYMHASH_SIZE = 3137; 10 11 struct D_SymHash { 12 int index; 13 int grow; 14 Vec!(D_Sym*) syms; 15 } 16 17 alias D_UserSym = uint; 18 19 struct D_Sym { 20 string name; 21 uint hash; 22 D_Scope *scope_; 23 D_Sym *update_of; 24 D_Sym *next; 25 D_UserSym user; 26 } 27 28 enum D_SCOPE_INHERIT = 0; 29 enum D_SCOPE_RECURSIVE = 1; 30 enum D_SCOPE_PARALLEL = 2; 31 enum D_SCOPE_SEQUENTIAL = 3; 32 33 34 35 struct D_Scope { 36 mixin(bitfields!( 37 uint, "kind", 2, 38 uint, "owned_by_user", 1, /* don't automatically delete */ 39 uint, "", 29 40 )); 41 uint depth; 42 D_Sym *ll; 43 D_SymHash *hash; 44 D_Sym *updates; 45 D_Scope *search; /* scope to start search */ 46 D_Scope *dynamic; /* dynamic scope (e.g. methods) */ 47 D_Scope *up; /* enclosing scope */ 48 D_Scope *up_updates; /* prior scope in speculative parse */ 49 D_Scope *down; /* enclosed scopes (for FREE) */ 50 D_Scope *down_next; /* next enclosed scope */ 51 } 52 53 /* 54 How this works. In a normal symbol table there is simply 55 a stack of scopes representing the scoping structure of 56 the program. Because of speculative parsing, this symbol table 57 also has a tree of all 'updates' representing different 58 views of the state of scoped variables by each speculative 59 parse state. Periodically, when the parse state collapses 60 to a single state (we are nolonger speculating), these changes 61 are can be 'committed' and the changes pushed into the top 62 level hash table. 63 64 All D_Scope's except the top level just have a 'll' of symbols, the 65 top level has a 'hash'. 66 67 'updates' is a list of changes to symbols in other scopes. It is 68 searched to find the current version of a symbol with respect to the 69 speculative parse path represented by D_Scope. 70 71 'up' points to the enclosing scope, it isn't used much. 72 73 'up_updates' is the prior scope in speculative parsing, it is used find 74 the next D_Scope to look in for 'updates' after the current one has been 75 searched. 76 77 'down' and 'down_next' are used to hold enclosing scopes, or in the 78 case of the top level, sibling scopes (created by commmit). 79 */ 80 81 82 private void 83 symhash_add(D_SymHash *sh, D_Sym *s) { 84 uint i, h = s.hash % sh.syms.n, n; 85 D_Sym **v = sh.syms.v; 86 D_Sym *x; 87 Vec!(D_Sym*) vv, tv; 88 89 sh.index++; 90 s.next = v[h]; 91 v[h] = s; 92 93 if (sh.index > sh.grow) { 94 vv.v = sh.syms.v; 95 vv.n = sh.syms.n; 96 sh.syms.n = sh.grow; 97 sh.grow = sh.grow * 2 + 1; 98 sh.syms.v = (new D_Sym*[sh.syms.n]).ptr;// cast(D_Sym**)MALLOC(sh.syms.n * (void *).sizeof); 99 v = sh.syms.v; 100 n = sh.syms.n; 101 vec_clear(&tv); 102 for (i = 0; i < vv.n; i++) 103 /* use temporary to preserve order */ 104 while (vv.v[i]) { 105 x = vv.v[i]; 106 vv.v[i] = x.next; 107 vec_add(&tv, x); 108 } 109 while (tv.v[i]) { 110 x = tv.v[i]; 111 tv.v[i] = x.next; 112 h = x.hash % n; 113 x.next = v[h]; 114 v[h] = x; 115 } 116 FREE(vv.v); 117 } 118 } 119 120 private D_SymHash * 121 new_D_SymHash() { 122 D_SymHash *sh = new D_SymHash(); 123 sh.grow = INITIAL_SYMHASH_SIZE * 2 + 1; 124 sh.syms.n = INITIAL_SYMHASH_SIZE; 125 sh.syms.v = (new D_Sym*[sh.syms.n]).ptr; // cast(D_Sym**)MALLOC(sh.syms.n * (void *).sizeof); 126 return sh; 127 } 128 129 private void 130 free_D_SymHash(D_SymHash *sh) { 131 int i; 132 D_Sym *sym; 133 for (i = 0; i < sh.syms.n; i++) 134 for (; sh.syms.v[i]; sh.syms.v[i] = sym) { 135 sym = sh.syms.v[i].next; 136 free_D_Sym(sh.syms.v[i]); 137 } 138 FREE(sh.syms.v); 139 FREE(sh); 140 } 141 142 D_Scope * 143 new_D_Scope(D_Scope *parent) { 144 D_Scope *st = new D_Scope(); 145 if (parent) { 146 st.depth = parent.depth + 1; 147 st.kind = parent.kind; 148 st.search = parent; 149 st.up = parent; 150 st.up_updates = parent; 151 st.down_next = parent.down; 152 parent.down = st; 153 } else 154 st.hash = new_D_SymHash(); 155 return st; 156 } 157 158 D_Scope * 159 equiv_D_Scope(D_Scope *current) { 160 D_Scope *s = current, last = current; 161 D_Sym *sy; 162 if (!s) 163 return s; 164 while (s.depth >= current.depth) { 165 if (s.depth == last.depth) { 166 if (current.up == s.up) 167 last = s; 168 else 169 break; 170 } 171 if (s.ll || s.hash) 172 break; 173 if (s.dynamic) 174 break; 175 sy = s.updates; 176 while (sy) { 177 if (sy.scope_.depth <= current.depth) 178 break; 179 sy = sy.next; 180 } 181 if (sy) 182 break; 183 if (!s.up_updates) 184 break; 185 s = s.up_updates; 186 } 187 return last; 188 } 189 190 191 D_Scope * 192 enter_D_Scope(D_Scope *current, D_Scope *scope_) { 193 D_Scope *st = new D_Scope(), parent = scope_.up; 194 st.depth = scope_.depth; 195 st.up = parent; 196 st.kind = scope_.kind; 197 st.search = scope_; 198 st.up_updates = current; 199 st.down_next = current.down; 200 current.down = st; 201 return st; 202 } 203 204 D_Scope * 205 global_D_Scope(D_Scope *current) { 206 D_Scope *g = current; 207 while (g.up) g = g.search; 208 return enter_D_Scope(current, g); 209 } 210 211 D_Scope * 212 scope_D_Scope(D_Scope *current, D_Scope *scope_) { 213 D_Scope *st = new D_Scope(), parent = current.up; 214 st.depth = current.depth; 215 st.up = parent; 216 st.kind = current.kind; 217 st.search = current; 218 st.dynamic = scope_; 219 st.up_updates = current; 220 st.down_next = current.down; 221 current.down = st; 222 return st; 223 } 224 225 void 226 free_D_Scope(D_Scope *st, int force) { 227 D_Scope *s; 228 D_Sym *sym; 229 for (; st.down; st.down = s) { 230 s = st.down.down_next; 231 free_D_Scope(st.down, 0); 232 } 233 if (st.owned_by_user && !force) 234 return; 235 if (st.hash) 236 free_D_SymHash(st.hash); 237 else 238 for (; st.ll; st.ll = sym) { 239 sym = st.ll.next; 240 free_D_Sym(st.ll); 241 } 242 for (; st.updates; st.updates = sym) { 243 sym = st.updates.next; 244 free_D_Sym(st.updates); 245 } 246 FREE(st); 247 } 248 249 private void 250 commit_ll(D_Scope *st, D_SymHash *sh) { 251 D_Sym *sym; 252 if (st.search) { 253 commit_ll(st.search, sh); 254 for (; st.ll; st.ll = sym) { 255 sym = st.ll.next; 256 symhash_add(sh, st.ll); 257 } 258 } 259 } 260 261 /* make direct links to the latest update */ 262 private void 263 commit_update(D_Scope *st, D_SymHash *sh) { 264 int i; 265 D_Sym *s; 266 267 for (i = 0; i < sh.syms.n; i++) 268 for (s = sh.syms.v[i]; s; s = s.next) 269 s.update_of = current_D_Sym(st, s); 270 } 271 272 /* currently only commit the top level scope */ 273 D_Scope * 274 commit_D_Scope(D_Scope *st) { 275 D_Scope *x = st; 276 if (st.up) 277 return st; 278 while (x.search) x = x.search; 279 commit_ll(st, x.hash); 280 commit_update(st, x.hash); 281 return x; 282 } 283 284 D_Sym * 285 new_D_Sym(D_Scope *st, string name, int sizeof_D_Sym) { 286 D_Sym *s = cast(D_Sym*)MALLOC(sizeof_D_Sym); 287 memset(s, 0, sizeof_D_Sym); 288 s.name = name; 289 s.hash = strhashl(name); 290 s.scope_ = st; 291 if (st) { 292 if (st.hash) { 293 symhash_add(st.hash, s); 294 } else { 295 s.next = st.ll; 296 st.ll = s; 297 } 298 } 299 return s; 300 } 301 302 void 303 free_D_Sym(D_Sym *s) { 304 FREE(s); 305 } 306 307 D_Sym * 308 current_D_Sym(D_Scope *st, D_Sym *sym) { 309 D_Scope *sc; 310 D_Sym *uu; 311 312 if (sym.update_of) sym = sym.update_of; 313 /* return the last update */ 314 for (sc = st; sc; sc = sc.up_updates) { 315 for (uu = sc.updates; uu; uu = uu.next) 316 if (uu.update_of == sym) 317 return uu; 318 } 319 return sym; 320 } 321 322 private D_Sym * 323 find_D_Sym_in_Scope_internal(D_Scope *st, string name, uint h) { 324 D_Sym *ll; 325 for (;st ; st = st.search) { 326 if (st.hash) 327 ll = st.hash.syms.v[h % st.hash.syms.n]; 328 else 329 ll = st.ll; 330 while (ll) { 331 if (ll.hash == h && ll.name == name) 332 return ll; 333 ll = ll.next; 334 } 335 if (st.dynamic) 336 { 337 ll = find_D_Sym_in_Scope_internal(st.dynamic, name, h); 338 if (ll) 339 return ll; 340 } 341 if (!st.search || st.search.up != st.up) 342 break; 343 } 344 return null; 345 } 346 347 private D_Sym * 348 find_D_Sym_internal(D_Scope *cur, string name, uint h) { 349 D_Sym *ll; 350 if (!cur) 351 return null; 352 if (cur.hash) 353 ll = cur.hash.syms.v[h % cur.hash.syms.n]; 354 else 355 ll = cur.ll; 356 while (ll) { 357 if (ll.hash == h && ll.name == name) 358 break; 359 ll = ll.next; 360 } 361 if (!ll) { 362 if (cur.dynamic) 363 { 364 ll = find_D_Sym_in_Scope_internal(cur.dynamic, name, h); 365 if (ll) 366 return ll; 367 } 368 if (cur.search) 369 return find_D_Sym_internal(cur.search, name, h); 370 return ll; 371 } 372 return ll; 373 } 374 375 D_Sym * 376 find_D_Sym(D_Scope *st, string name) { 377 uint h = strhashl(name); 378 D_Sym *s = find_D_Sym_internal(st, name, h); 379 if (s) 380 return current_D_Sym(st, s); 381 return null; 382 } 383 384 D_Sym * 385 find_global_D_Sym(D_Scope *st, string name) { 386 uint h = strhashl(name); 387 D_Scope *cur = st; 388 while (cur.up) cur = cur.search; 389 D_Sym *s = find_D_Sym_internal(cur, name, h); 390 if (s) 391 return current_D_Sym(st, s); 392 return null; 393 } 394 395 D_Sym * 396 find_D_Sym_in_Scope(D_Scope *st, D_Scope *cur, string name) { 397 uint h = strhashl(name); 398 D_Sym *s = find_D_Sym_in_Scope_internal(cur, name, h); 399 if (s) 400 return current_D_Sym(st, s); 401 return null; 402 } 403 404 D_Sym * 405 next_D_Sym_in_Scope(D_Scope **scope_, D_Sym **sym) { 406 D_Sym *last_sym = *sym, ll = last_sym; 407 D_Scope *st = *scope_; 408 if (ll) { 409 ll = ll.next; 410 if (ll) 411 goto Lreturn; 412 } 413 for (;st ; st = st.search) { 414 if (st.hash) { 415 int i = last_sym ? ((last_sym.hash + 1) % st.hash.syms.n) : 0; 416 if (!last_sym || i) 417 ll = st.hash.syms.v[i]; 418 } else { 419 if (!last_sym) 420 ll = st.ll; 421 } 422 last_sym = null; 423 if (ll) 424 goto Lreturn; 425 if (!st.search || st.search.up != st.up) 426 break; 427 } 428 Lreturn: 429 if (ll) 430 *sym = ll; 431 *scope_ = st; 432 return ll; 433 } 434 435 D_Sym * 436 update_additional_D_Sym(D_Scope *st, D_Sym *sym, int sizeof_D_Sym) { 437 sym = current_D_Sym(st, sym); 438 D_Sym *s = cast(D_Sym*)MALLOC(sizeof_D_Sym); 439 memcpy(s, sym, (D_Sym).sizeof); 440 if (sym.update_of) sym = sym.update_of; 441 s.update_of = sym; 442 s.next = st.updates; 443 st.updates = s; 444 return s; 445 } 446 447 D_Sym * 448 update_D_Sym(D_Sym *sym, D_Scope **pst, int sizeof_D_Sym) { 449 *pst = enter_D_Scope(*pst, *pst); 450 return update_additional_D_Sym(*pst, sym, sizeof_D_Sym); 451 } 452 453 void 454 print_sym(D_Sym *s) { 455 logf("%s, ", s.name); 456 } 457 458 void 459 print_scope(D_Scope *st) { 460 printf("SCOPE %p: ", st); 461 printf(" owned: %d, kind: %d, ", st.owned_by_user, st.kind); 462 if (st.ll) printf(" LL\n"); 463 if (st.hash) printf(" HASH\n"); 464 if (st.hash) { 465 int i; 466 for (i = 0; i < st.hash.syms.n; i++) 467 if (st.hash.syms.v[i]) 468 print_sym(st.hash.syms.v[i]); 469 } else { 470 D_Sym *ll = st.ll; 471 while (ll) { 472 print_sym(ll); 473 ll = ll.next; 474 } 475 } 476 printf("\n\n"); 477 if (st.dynamic) print_scope(st.dynamic); 478 if (st.search) print_scope(st.search); 479 }