1. UCC字符串管理
UCC在处理C源文件中,需要进行大量的字符串处理,因此高效的字符串处理对于编译效率的提高有很大的作用。
UCC处理的堆不同种类的字符串标识符和字符串常量采用不同的策略。
2. UCC字符串的表示
2.1 标识符的表示
标识符使用NameBucket来表示,
typedef struct nameBucket
{
char *name;
int len;
struct nameBucket *link;
} *NameBucket;
name, 字符串指针.
len, 字符串长度.
link, 下一个标识符.
2.2 标识符的集合
UCC中标识符使用哈希表来高效存储查询, 相同的标识符在哈希表中只有一个实体存在,因此标识符的比较只需要比较指针即可.
2.3 标识符的管理
上节提到, UCC的标识符使用哈希表进行管理,
在遇到新的标识符时,先使用char* InternName(char *id, int len)函数进行查询, 如果已经在哈希表中, 返回表中的字符串指针,
如果不在哈希表中, 分配新的NameBucket, 用标识符进行初始化并加入哈希表, 返回新加入的字符串.
h = ELFHash(id, len) & NAME_HASH_MASK;
计算标识符的哈希值, 然后计算所在的bucket的值,
for (p = NameBuckets[h]; p != NULL; p = p->link)
{
if (len == p->len && strncmp(id, p->name, len) == 0)
return p->name;
在相应的bucket中, 查找字符串, 若有相同的字符串,
返回找到的字符串.
}
p = HeapAllocate(&StringHeap, sizeof(*p));
若没有找到相同的字符串, 则分配新的bucket,
p->name = HeapAllocate(&StringHeap, len + 1);
并且从字符串的Heap中分配字符串等长的内存,
for (i = 0; i < len; ++i)
{
p->name[i] = id[i];
}
复制字符串到分配的内存,
p->name[len] = 0;
p->len = len;
设置字符串长度,
p->link = NameBuckets[h];
NameBuckets[h] = p;
将bucket加入到对应的链表中,
2.4 字符串常量的表示
typedef struct string
{
char *chs;
int len;
} *String;
chs, 字符串常量指针
len, 字符串常量长度
2.5 字符串常量的管理
UCC中字符串常量没有使用标识符相似的管理方式, 字符串常量是独立表示使用的.
2.6 字符串常量的合并
字符串常量的合并, 将一个字符串常量附加在另一个字符串常量的尾部,
在AppendSTR(String str, char *tmp, int len, int wide)中完成,
size = str->len + len + 1;
计算新的合并的字符串长度,
p = HeapAllocate(&StringHeap, size * times);
在字符串的Heap中分配对应长度的内存,
for (i = 0; i < str->len * times; ++i)
{
p[i] = str->chs[i];
}
首先复制目的字符串,
for (i = 0; i < len * times; ++i)
{
p[i] = tmp[i];
}
然后复制源字符串,
str->chs = p;
str->len = size - 1;
将新的字符串地址赋值给字符串指针, 设置新的长度.
注意, 没有有释放先前的字符串内存.