January 1, 0001
为了符合「作用域」的定义,哈希表应该采用头插法。 这块我写得真的是非常诡异……为了暴露哈希表的细节,还假装自己模拟了一个友元出来。
错用container_of
导致ASAN在某次成员访问的时候报了一个heap-buffer-overflow
,一开始还以为是误报。这个错用的过程真的是环环相扣。
最终决定元信息(level
和scope
)还是要暴露在公共类型里,具体来说,是直接放到symbols_t
里,而不是仅仅作为view暴露出来。
事实上比较数学的处理变量作用域的思路应该是类似LISP和ML的let...in
关键字,这是一个完全递归的、完备的思路,而且和树同构,但是可以预想到内存占用多、搜索效率差——但其实我这个破烂十字链表应该也高不到哪去吧……
做到发现迭代式的思路甚至还需要用栈记录Stmt
的index
的时候就做不下去了。很明显,迭代式的思路无法满足lexical scope的要求(或者至少复杂度非常高),必然要在一定程度上借助let...in
的思路。
最终实际的scope(和其数据结构)其实是这样的:
// (-, -)
( int main() // (0, 0)
{ // (1, 0)
( int a = 1; // (2, 0)
{ // (3, 0)
( int a = 2; // | (4, 0)
a = 3; // | |
) // | |
} // V |
{ // (3, 1)
a = a + 4; // V
( int b = a; // (4, 1)
( int c = b + 5, d; // (5, 0)
a = c + 6;
d = 7;
)
)
}
return a;
)
}
)
每次leave()
或者dedent()
都会直接回到该层的{ ... }
结尾处;同时把对同层不同序(order)的scope的访问用队强行串起来了……
我一开始分了64K给bump allocator,结果在跑06_complex_scopes
的时候竟然不够了……我写了个什么怪物出来,怎么能做到这么占内存的。我估计raw->ty
没有作压缩应该占很大一部分原因。
最后还是终于搞明白了used_by
到底是个什么机制——其实很简单,在kind
里用到了谁就往谁里面加。这是什么意思?是后序遍历!
有一个问题死活找不出来,结果发现是把strcmp()
的比较条件「写反了」:
#if 0
if (strcmp(a, b)) { ... }
#else
if (strcmp(a, b) == 0) { ... }
#endif
这个,呃……行吧。