TCC(TinyC)编译器汉化(中文编译器、汉语编程)之九:核心库源码
程序员文章站
2022-03-30 20:17:17
...
hexinku.c核心库源码如下:
/*
* 核心库:hexinku.c生成hexinku.dll。此文件只在zhi.c第11行一个文件中引用,是知语言的基本库。
* 使用hexinku.c,您可以将ZHI用作动态代码生成的后端
*/
#如果 !已定义 是_源文件 || 是_源文件
#导入 "词法分析.c"
#导入 "语法分析.c"
#导入 "ELF文件处理.c"
#导入 "run开关.c"
#如果已定义 ZHI_TARGET_I386
#导入 "i386-gen.c"
#导入 "i386-link.c"
#导入 "i386-asm.c"
#否则如果 已定义(ZHI_TARGET_ARM)
#导入 "arm-gen.c"
#导入 "arm-link.c"
#导入 "arm-asm.c"
#否则如果 已定义(ZHI_TARGET_ARM64)
#导入 "arm64-gen.c"
#导入 "arm64-link.c"
#导入 "arm-asm.c"
#否则如果 已定义(ZHI_TARGET_C67)
#导入 "c67-gen.c"
#导入 "c67-link.c"
#导入 "COFF文件处理.c"
#否则如果 已定义(ZHI_TARGET_X86_64)
#导入 "x86_64-gen.c"
#导入 "x86_64-link.c"
#导入 "i386-asm.c"
#否则如果 已定义(ZHI_TARGET_RISCV64)
#导入 "riscv64-gen.c"
#导入 "riscv64-link.c"
#导入 "riscv64-asm.c"
#否则
#error unknown target
#结束如果
#如果已定义 配置_ZHI_汇编
#导入 "汇编处理.c"
#结束如果
#如果已定义 ZHI_TARGET_PE
#导入 "PE文件输出.c"
#结束如果
#如果已定义 ZHI_TARGET_MACHO
#导入 "MACH系统O文件处理.c"
#结束如果
#结束如果 /* 是_源文件 */
#导入 "zhi.h"
/********************************************************/
/* 全局变量 */
#如果已定义 内存_调试
静态 整数型 数量_states;
#结束如果
/*************************#如果已定义 _WIN32-开始*******************************/
#如果已定义 _WIN32
静态_函数 字符型 *WIN32规范化斜杠(字符型 *path)
{
字符型 *p;
循环 (p = path; *p; ++p)
如果 (*p == '\\')
*p = '/';
返回 path;
}
静态 HMODULE 应用程序载入的_模块;/*HMODULE:表示模块句柄。是代表应用程序载入的模块,win32系统下通常是被载入模块的线性地址。*/
/* 在Win32上,我们假设lib和include位于'zhi.exe'的位置 */
静态 无类型 WIN32设置库路径(知心状态机 *s)
{
字符型 path[1024], *p;
/*获取当前运行程序的绝对路径。如果“应用程序载入的_模块”该参数为NULL,函数会获取当前进程的运行文件(.exe文件)的全路径。
* path:一个指向接收存储模块的全路径的缓冲区的指针。
* 取大小 path:path缓冲区的长度。*/
GetModuleFileNameA(应用程序载入的_模块, path, 取大小 path);
p = 取_文件基本名(WIN32规范化斜杠(strlwr(path)));/*strlwr(path)将字符串转换为小写*/
如果 (p > path)
--p;
*p = 0;
设置库路径(s, path);
}
#如果已定义 ZHI_TARGET_PE
静态 无类型 WIN32添加系统目录(知心状态机 *s)
{
字符型 buf[1000];
/*获取系统目录GetSystemDirectoryA(lpBuffer,uSize);lpBuffer,缓冲区用于存放取得的系统目录,uSize缓冲区长度*/
GetSystemDirectory(buf, 取大小 buf);
添加库路径(s, WIN32规范化斜杠(buf));
}
#结束如果
#如果已定义 HEXINKU_AS_DLL
/*DllMain (hDll, dwReason,lpReserved)
* hDll参数:指向DLL本身的实例句柄;
* dwReason参数:指明了DLL被调用的原因
* (
* 1.DLL_PROCESS_ATTACH:当DLL被进程 <<第一次>> 调用时,导致DllMain函数被调用.
* 2.DLL_PROCESS_DETACH:当DLL被从进程的地址空间解除映射时,系统调用了它的DllMain.
* 3.DLL_THREAD_ATTACH:当进程创建一线程时,系统查看当前映射到进程地址空间中的所有DLL文件映像.
* 4.DLL_THREAD_DETACH:如果线程调用了ExitThread来结束线程(线程函数返回时,系统也会自动调用ExitThread).
* )*/
BOOL WINAPI DllMain (HINSTANCE hDll, DWORD dwReason, LPVOID lpReserved)
{
如果 (DLL_PROCESS_ATTACH == dwReason)
应用程序载入的_模块 = hDll;
返回 TRUE;
}
#结束如果
#结束如果
/*************************#如果已定义 _WIN32-结束*******************************/
#如果未定义 从线程_使用_核心库
#定义 WAIT_SEM()
#定义 POST_SEM()
#否则如果 已定义 _WIN32
静态 整数型 线程_临界区_初始化;
静态 CRITICAL_SECTION 线程_临界区;
/*如果某一时间点有线程在CriticalSection内的话,EnterCriticalSection()会让待进入CriticalSection区域内的其它线程处于等待状态.但是它会将待进入CriticalSection的线程切换到不占用CPU的状态,太棒了!
*InitializeCriticalSection(&cs);//初始化临界区,cs就是“线程_临界区”也就是厕所。
*EnterCriticalSection(&cs);//进入临界区
*LeaveCriticalSection(&cs);//离开临界区
*DeleteCriticalSection(&cs);//删除临界区
*通俗解释就像上厕所:
*门锁了,就等着,等到别人出来了,进去锁上,然后该干什么干什么,干完了,把门打开
*门没锁,就进去,锁上,然后该干什么干什么,干完了,把门打开
*/
静态 无类型 待进入_信号量(无类型)
{
如果 (!线程_临界区_初始化)
InitializeCriticalSection(&线程_临界区), 线程_临界区_初始化 = 1;
EnterCriticalSection(&线程_临界区);
}
#定义 WAIT_SEM() 待进入_信号量()
#定义 POST_SEM() LeaveCriticalSection(&线程_临界区);
#否则如果 已定义 __APPLE__
/* 半兼容的MacOS没有非共享(本地处理)信号灯。 将调度框架用于轻型锁。 */
#导入 <dispatch/dispatch.h>
静态 整数型 线程_临界区_初始化;
静态 调度_信号_t 临界区_信号量;
静态 无类型 待进入_信号量(无类型)
{
如果 (!线程_临界区_初始化)
临界区_信号量 = 调度_信号量_创建(1), 线程_临界区_初始化 = 1;
调度_信号量_等待降低(临界区_信号量, DISPATCH_TIME_FOREVER);
}
#定义 WAIT_SEM() 待进入_信号量()
#定义 POST_SEM() 调度_信号量_提高(临界区_信号量)
#否则
#导入 <semaphore.h>
静态 整数型 线程_临界区_初始化;
静态 sem_t 临界区_信号量;
静态 无类型 待进入_信号量(无类型)
{
如果 (!线程_临界区_初始化)
sem_init(&临界区_信号量, 0, 1), 线程_临界区_初始化 = 1;
判断 (sem_wait (&临界区_信号量) < 0 && errno == EINTR);
}
#定义 WAIT_SEM() 待进入_信号量()
#定义 POST_SEM() sem_post(&临界区_信号量)
#结束如果
/********************************************************/
/* 复制一个字符串并截断它。 */
静态_函数 字符型 *p字符串复制(字符型 *buf, size_t buf_size, 常量 字符型 *s)
{
字符型 *q, *q_end;
整数型 c;
如果 (buf_size > 0)
{
q = buf;
q_end = buf + buf_size - 1;
判断 (q < q_end)
{
c = *s++;
如果 (c == '\0')
跳出;
*q++ = c;
}
*q = '\0';
}
返回 buf;
}
/* 字符串连接和截断。*/
静态_函数 字符型 *连接_字符串(字符型 *buf, size_t buf_size, 常量 字符型 *s)
{
size_t len;
len = strlen(buf);/*获取字符串的实际长度*/
如果 (len < buf_size)
p字符串复制(buf + len, buf_size - len, s);
返回 buf;
}
静态_函数 字符型 *复制_字符串(字符型 *被覆盖输出, 常量 字符型 *被复制, size_t 字节数)
{
memcpy(被覆盖输出, 被复制, 字节数);
被覆盖输出[字节数] = '\0';
返回 被覆盖输出;
}
/*取_文件基本名包含扩展名*/
公共_函数 字符型 *取_文件基本名(常量 字符型 *name)
{
字符型 *p = strchr(name, 0);
判断 (p > name && !IS_DIRSEP(p[-1]))
--p;
返回 p;
}
/* (如果没有扩展名,则返回指向字符串结尾的指针)*/
公共_函数 字符型 *取_文件扩展名 (常量 字符型 *name)
{
字符型 *b = 取_文件基本名(name);
字符型 *e = strrchr(b, '.');/*strrchr(b, c)查找字符c在字符串b中最后出现的位置,返回此位置之后的所有的字符串。*/
返回 e ? e : strchr(b, 0);
}
/********************************************************/
/* 内存管理 */
#取消定义 free
#取消定义 malloc
#取消定义 realloc
#如果未定义 内存_调试
公共_函数 无类型 内存_释放(无类型 *ptr)
{
free(ptr);
}
/*基于malloc()函数优化。申请一块连续的指定大小的内存块区域以void*类型返回分配的内存区域地址*/
公共_函数 无类型 *内存_申请(无符号 long 内存容量)
{
无类型 *ptr;
ptr = malloc(内存容量);
如果 (!ptr && 内存容量)
错误("内存已满(重新分配)");
返回 ptr;
}
/*初始化内存块:返回一块“size”(参数)大小的空内存区域*/
公共_函数 无类型 *内存_初始化(无符号 long size)
{
无类型 *ptr;
ptr = 内存_申请(size);
/*memset(无类型 *s, 整数型 ch, size_t n);作用是将某一块内存中的内容全部设置为指定的值,
将s中当前位置后面的n个字节 用 ch 替换并返回 s */
memset(ptr, 0, size);
返回 ptr;
}
/*重新分配内存大小。ptr原内存大小,size为新内存大小(要返回的内存大小),*/
公共_函数 无类型 *内存_重分配容量(无类型 *ptr, 无符号 long size)
{
无类型 *ptr1;
ptr1 = realloc(ptr, size);
如果 (!ptr1 && size)
错误("内存已满(重新分配)");
返回 ptr1;
}
公共_函数 字符型 *字符串_宽度加1(常量 字符型 *str)
{
字符型 *ptr;
ptr = 内存_申请(strlen(str) + 1);/*strlen(str)求字符数组的长度*/
strcpy(ptr, str);/*strcpy(ptr, str);把str复制给ptr*/
返回 ptr;
}
#否则
#定义 MEM_DEBUG_MAGIC1 0xFEEDDEB1
#定义 MEM_DEBUG_MAGIC2 0xFEEDDEB2
#定义 MEM_DEBUG_MAGIC3 0xFEEDDEB3
#定义 MEM_DEBUG_FILE_LEN 40
#定义 MEM_DEBUG_CHECK3(header) \
((内存_调试_头_t*)((字符型*)header + header->size))->magic3
#定义 MEM_USER_PTR(header) \
((字符型 *)header + offsetof(内存_调试_头_t, magic3))
#定义 MEM_HEADER_PTR(ptr) \
(内存_调试_头_t *)((字符型*)ptr - offsetof(内存_调试_头_t, magic3))
结构体 内存_调试_header {
无符号 magic1;
无符号 size;
结构体 内存_调试_header *prev;
结构体 内存_调试_header *next;
整数型 line_num;
字符型 file_name[MEM_DEBUG_FILE_LEN + 1];
无符号 magic2;
ALIGNED(16) 无符号 magic3;
};
类型定义 结构体 内存_调试_header 内存_调试_头_t;
静态 内存_调试_头_t *内存_调试_链;
静态 无符号 内存_当前_大小;
静态 无符号 内存_最大_大小;
静态 内存_调试_头_t *malloc_check(无类型 *ptr, 常量 字符型 *msg)
{
内存_调试_头_t * header = MEM_HEADER_PTR(ptr);
如果 (header->magic1 != MEM_DEBUG_MAGIC1 ||
header->magic2 != MEM_DEBUG_MAGIC2 ||
MEM_DEBUG_CHECK3(header) != MEM_DEBUG_MAGIC3 ||
header->size == (无符号)-1) {
fprintf(stderr, "%s check failed\n", msg);
如果 (header->magic1 == MEM_DEBUG_MAGIC1)
fprintf(stderr, "%s:%u: 这里分配的块.\n",
header->file_name, header->line_num);
exit(1);
}
返回 header;
}
公共_函数 无类型 *zhi_分配_调试(无符号 long size, 常量 字符型 *file, 整数型 line)
{
整数型 ofs;
内存_调试_头_t *header;
header = malloc(取大小(内存_调试_头_t) + size);
如果 (!header)
错误("内存已满(重新分配)");
header->magic1 = MEM_DEBUG_MAGIC1;
header->magic2 = MEM_DEBUG_MAGIC2;
header->size = size;
MEM_DEBUG_CHECK3(header) = MEM_DEBUG_MAGIC3;
header->line_num = line;
ofs = strlen(file) - MEM_DEBUG_FILE_LEN;
strncpy(header->file_name, file + (ofs > 0 ? ofs : 0), MEM_DEBUG_FILE_LEN);
header->file_name[MEM_DEBUG_FILE_LEN] = 0;
header->next = 内存_调试_链;
header->prev = NULL;
如果 (header->next)
header->next->prev = header;
内存_调试_链 = header;
内存_当前_大小 += size;
如果 (内存_当前_大小 > 内存_最大_大小)
内存_最大_大小 = 内存_当前_大小;
返回 MEM_USER_PTR(header);
}
公共_函数 无类型 zhi_释放_调试(无类型 *ptr)
{
内存_调试_头_t *header;
如果 (!ptr)
返回;
header = malloc_check(ptr, "内存_释放");
内存_当前_大小 -= header->size;
header->size = (无符号)-1;
如果 (header->next)
header->next->prev = header->prev;
如果 (header->prev)
header->prev->next = header->next;
如果 (header == 内存_调试_链)
内存_调试_链 = header->next;
free(header);
}
公共_函数 无类型 *zhi_分配z_调试(无符号 long size, 常量 字符型 *file, 整数型 line)
{
无类型 *ptr;
ptr = zhi_分配_调试(size,file,line);
memset(ptr, 0, size);
返回 ptr;
}
公共_函数 无类型 *zhi_重新分配_调试(无类型 *ptr, 无符号 long size, 常量 字符型 *file, 整数型 line)
{
内存_调试_头_t *header;
整数型 mem_debug_chain_update = 0;
如果 (!ptr)
返回 zhi_分配_调试(size, file, line);
header = malloc_check(ptr, "内存_重分配容量");
内存_当前_大小 -= header->size;
mem_debug_chain_update = (header == 内存_调试_链);
header = realloc(header, 取大小(内存_调试_头_t) + size);
如果 (!header)
错误("内存已满(重新分配)");
header->size = size;
MEM_DEBUG_CHECK3(header) = MEM_DEBUG_MAGIC3;
如果 (header->next)
header->next->prev = header;
如果 (header->prev)
header->prev->next = header;
如果 (mem_debug_chain_update)
内存_调试_链 = header;
内存_当前_大小 += size;
如果 (内存_当前_大小 > 内存_最大_大小)
内存_最大_大小 = 内存_当前_大小;
返回 MEM_USER_PTR(header);
}
公共_函数 字符型 *zhi_字符串dup_调试(常量 字符型 *str, 常量 字符型 *file, 整数型 line)
{
字符型 *ptr;
ptr = zhi_分配_调试(strlen(str) + 1, file, line);
strcpy(ptr, str);
返回 ptr;
}
公共_函数 无类型 zhi_内存检查(无类型)
{
如果 (内存_当前_大小) {
内存_调试_头_t *header = 内存_调试_链;
fprintf(stderr, "内存_调试: 内存_泄漏= %d 个字节, 内存_最大_大小= %d 个字节\n",内存_当前_大小, 内存_最大_大小);
判断 (header) {fprintf(stderr, "%s:%u: 错误: %u 个字节泄漏\n",header->file_name, header->line_num, header->size);
header = header->next;
}
#如果 内存_调试-0 == 2
exit(2);
#结束如果
}
}
#结束如果 /* 内存_调试 */
#定义 free(p) 用_zhi_释放(p)
#定义 malloc(s) 用_zhi_内存分配(s)
#定义 realloc(p, s) 用_zhi_重新分配(p, s)
/********************************************************/
/* 动态字符串 */
静态_函数 无类型 动态数组_追加元素(无类型 *ptab, 整数型 *数量_ptr, 无类型 *data)
{
整数型 数组长度, 数量_alloc;
无类型 **数组;
数组长度 = *数量_ptr;
数组 = *(无类型 ***)ptab;
/* 每乘以2的幂就使数组大小加倍 */
如果 ((数组长度 & (数组长度 - 1)) == 0)
{
如果 (!数组长度)
数量_alloc = 1;
否则
数量_alloc = 数组长度 * 2;
数组 = 内存_重分配容量(数组, 数量_alloc * 取大小(无类型 *));
*(无类型***)ptab = 数组;
}
数组[数组长度++] = data;
*数量_ptr = 数组长度;
}
静态_函数 无类型 动态数组_重分配容量(无类型 *pp, 整数型 *n)
{
无类型 **p;
循环 (p = *(无类型***)pp; *n; ++p, --*n)
如果 (*p)
内存_释放(*p);
内存_释放(*(无类型**)pp);
*(无类型**)pp = NULL;
}
/*拆分路径*/
静态 无类型 拆分路径(知心状态机 *s, 无类型 *p_ary, 整数型 *p_nb_ary, 常量 字符型 *in)
{
常量 字符型 *p;
执行 {
整数型 c;
动态字符串 str;
动态字符串_初始化(&str);
循环 (p = in; c = *p, c != '\0' && c != PATHSEP[0]; ++p) {
如果 (c == '{' && p[1] && p[2] == '}') {
c = p[1], p += 2;
如果 (c == 'B')
动态字符串_cat(&str, s->zhi_库_路径, -1);
如果 (c == 'f' && file) {
/* 替换当前文件的目录 */
常量 字符型 *f = file->true_filename;
常量 字符型 *b = 取_文件基本名(f);
如果 (b > f)
动态字符串_cat(&str, f, b - f - 1);
否则
动态字符串_cat(&str, ".", 1);
}
} 否则 {
动态字符串_追加单个字符(&str, c);
}
}
如果 (str.字符串长度) {
动态字符串_追加单个字符(&str, '\0');
动态数组_追加元素(p_ary, p_nb_ary, 字符串_宽度加1(str.指向字符串的指针));
}
动态字符串_释放(&str);
in = p+1;
} 判断 (*p);
}
/********************************************************/
静态 无类型 可变参数列表格式化后输出到字符数组(字符型 *buf, 整数型 buf_size, 常量 字符型 *fmt, va_list ap)
{
整数型 len;
len = strlen(buf);
vsnprintf(buf + len, buf_size - len, fmt, ap);
}
静态 无类型 strcat_printf(字符型 *buf, 整数型 buf_size, 常量 字符型 *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
可变参数列表格式化后输出到字符数组(buf, buf_size, fmt, ap);
va_end(ap);
}
#定义 ERROR_WARN 0
#定义 ERROR_NOABORT 1
#定义 ERROR_ERROR 2
公共_函数 无类型 进入状态机(知心状态机 *状态机1)
{
WAIT_SEM();
zhi_状态 = 状态机1;
}
公共_函数 无类型 离开状态机(无类型)
{
zhi_状态 = NULL;
POST_SEM();
}
静态 无类型 错误1(整数型 mode, 常量 字符型 *fmt, va_list ap)
{
字符型 buf[2048];
缓冲文件 **pf, *f;
知心状态机 *状态机1 = zhi_状态;
buf[0] = '\0';
如果 (状态机1 == NULL)
/* 仅当从zhi_malloc()调用时才可能发生:'内存不足' */
去向 no_file;
如果 (状态机1 && !状态机1->错误_设置_jmp_启用)
/* zhi_state刚刚由zhi_enter_state()设置 */
离开状态机();
如果 (mode == ERROR_WARN) {
如果 (状态机1->警告_none)
返回;
如果 (状态机1->警告_错误)
mode = ERROR_ERROR;
}
f = NULL;
如果 (状态机1->错误_设置_jmp_启用) { /* we're called 判断 parsing a file */
/* use upper file 如果 内联 ":asm:" or 标识符 ":paste:" */
循环 (f = file; f && f->文件名[0] == ':'; f = f->prev)
;
}
如果 (f) {
循环(pf = 状态机1->包含_堆; pf < 状态机1->包含_堆_ptr; pf++)
strcat_printf(buf, 取大小(buf), "In file included from %s:%d:\n",
(*pf)->文件名, (*pf)->line_num);
strcat_printf(buf, 取大小(buf), "%s:%d: ",
f->文件名, f->line_num - !!(标识符_标记 & 符_标记_行开始前));
} 否则 如果 (状态机1->当前_文件名) {
strcat_printf(buf, 取大小(buf), "%s: ", 状态机1->当前_文件名);
}
no_file:
如果 (0 == buf[0])
strcat_printf(buf, 取大小(buf), "zhi: ");
如果 (mode == ERROR_WARN)
strcat_printf(buf, 取大小(buf), "警告: ");
否则
strcat_printf(buf, 取大小(buf), "错误: ");
可变参数列表格式化后输出到字符数组(buf, 取大小(buf), fmt, ap);
如果 (!状态机1 || !状态机1->错误_函数) {
/* default 分支: stderr */
如果 (状态机1 && 状态机1->输出_类型 == ZHI_输出_预处理 && 状态机1->预处理输出文件 == stdout)
/* 在zhi -E期间打印换行符 */
printf("\n"), fflush(stdout);
fflush(stdout); /* flush -v output */
fprintf(stderr, "%s\n", buf);
fflush(stderr); /* print error/warning now (win32) */
} 否则 {
状态机1->错误_函数(状态机1->错误_不透明, buf);
}
如果 (状态机1) {
如果 (mode != ERROR_WARN)
状态机1->数量_错误++;
如果 (mode != ERROR_ERROR)
返回;
如果 (状态机1->错误_设置_jmp_启用)
longjmp(状态机1->错误_jmp_缓存, 1);
/*longjmp(envbuf,val);
longjmp函数中的参数envbuf是由setjmp函数所保存的堆栈环境,参数val设置setjmp函数的返回值。longjmp函数本身是没有返回值的,
它执行后跳转到保存envbuf参数的setjmp函数调用,并由setjmp函数调用返回,此时setjmp函数的返回值就是val。
setjmp和longjmp是C语言独有的,只有将它们结合起来使用,才能达到程序控制流有效转移的目的,按照程序员的预先设计的意图,
去实现对程序中可能出现的异常进行集中处理。
*/
}
exit(1);
}
HEXINKU接口 无类型 设置错误警告显示回调(知心状态机 *s, 无类型 *错误_不透明, ZHIErrorFunc 错误_函数)
{
s->错误_不透明 = 错误_不透明;
s->错误_函数 = 错误_函数;
}
HEXINKU接口 ZHIErrorFunc 返回错误警告回调(知心状态机 *s)
{
返回 s->错误_函数;
}
HEXINKU接口 无类型 *返回错误警告回调不透明指针(知心状态机 *s)
{
返回 s->错误_不透明;
}
/* 错误而没有中止当前编译 */
公共_函数 无类型 错误提示(常量 字符型 *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
错误1(ERROR_NOABORT, fmt, ap);
va_end(ap);
}
公共_函数 无类型 错误(常量 字符型 *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
循环 (;;) 错误1(ERROR_ERROR, fmt, ap);
}
公共_函数 无类型 _zhi_警告(常量 字符型 *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
错误1(ERROR_WARN, fmt, ap);
va_end(ap);
}
/********************************************************/
/* I/O层 */
静态_函数 无类型 打开缓存文件(知心状态机 *状态机1, 常量 字符型 *文件名, 整数型 initlen)
{
缓冲文件 *bf;
整数型 buflen = initlen ? initlen : 输入输出_缓冲_大小;
bf = 内存_初始化(取大小(缓冲文件) + buflen);
bf->buf_ptr = bf->buffer;
bf->buf_end = bf->buffer + initlen;
bf->buf_end[0] = CH_缓冲区结尾; /* put eob symbol */
p字符串复制(bf->文件名, 取大小(bf->文件名), 文件名);
#如果已定义 _WIN32
WIN32规范化斜杠(bf->文件名);
#结束如果
bf->true_filename = bf->文件名;
bf->line_num = 1;
bf->如果已宏定义_堆_ptr = 状态机1->如果已宏定义_堆_ptr;
bf->fd = -1;
bf->prev = file;
file = bf;
标识符_标记 = 符_标记_行开始前 | 符_标记_文件开始前;
}
静态_函数 无类型 关闭文件(无类型)
{
知心状态机 *状态机1 = zhi_状态;
缓冲文件 *bf = file;
如果 (bf->fd > 0) {
close(bf->fd);
总_行数 += bf->line_num;
}
如果 (bf->true_filename != bf->文件名)
内存_释放(bf->true_filename);
file = bf->prev;
内存_释放(bf);
}
静态 整数型 打开文件(知心状态机 *状态机1, 常量 字符型 *文件名)
{
整数型 fd;
如果 (strcmp(文件名, "-") == 0)
fd = 0, 文件名 = "<stdin>";
否则
fd = open(文件名, O_RDONLY | O_BINARY);
如果 ((状态机1->显示信息 == 2 && fd >= 0) || 状态机1->显示信息 == 3)
printf("%s %*s%s\n", fd < 0 ? "nf":"->",
(整数型)(状态机1->包含_堆_ptr - 状态机1->包含_堆), "", 文件名);
返回 fd;
}
静态_函数 整数型 打开一个新文件(知心状态机 *状态机1, 常量 字符型 *文件名)/*打开一个新文件()打开一个新文件并zhi_close()关闭它。*/
{
整数型 fd = 打开文件(状态机1, 文件名);
如果 (fd < 0)
返回 -1;
打开缓存文件(状态机1, 文件名, 0);
file->fd = fd;
返回 0;
}
/* 编译在“文件”中打开的文件。 错误返回非零. */
静态 整数型 编译_开始(知心状态机 *状态机1, 整数型 文件类型, 常量 字符型 *文件名称, 整数型 只读文件)
{
/* 从这里进入代码部分,开始使用全局变量进行解析和代码生成(词法分析.c,语法分析.c,<target> -gen.c),其他线程需要等待我们完成。
或者,我们可以对这些全局变量使用线程本地存储,这可能有优势也可能没有优势 */
进入状态机(状态机1);
如果 (setjmp(状态机1->错误_jmp_缓存) == 0)
{
/*整数型 setjmp(jmp_buf envbuf);
setjmp函数用缓冲区envbuf保存系统堆栈的内容,以便后续的longjmp函数使用。setjmp函数初次启用时返回0值。
* */
整数型 要_汇编;
状态机1->错误_设置_jmp_启用 = 1;
状态机1->数量_错误 = 0;
如果 (只读文件 == -1)
{
整数型 len = strlen(文件名称);
打开缓存文件(状态机1, "<string>", len);
memcpy(file->buffer, 文件名称, len);
} 否则 {
打开缓存文件(状态机1, 文件名称, 0);
file->fd = 只读文件;
}
/*两个!是为了把非0值转换成1,而0值还是0。
因为C语言中,所有非0值都表示真。
所以!非0值 = 0,而!0 = 1。
所以!!非0值 = 1,而!!0 = 0。
例如:i=123 !i=0 !!i=1
最后将123转换为1。
就是其他数据类型向bool值的转换*/
要_汇编 = !!(文件类型 & (文件格式_类型_汇编|文件格式_类型_ASMPP));
保存_段_数据状态(状态机1);
开始_预处理(状态机1, 要_汇编);
zhi语法_初始化(状态机1);
如果 (状态机1->输出_类型 == ZHI_输出_预处理)
{
预处理_源文件(状态机1);
} 否则 如果 (要_汇编)
{
#如果已定义 配置_ZHI_汇编
zhi_汇编(状态机1, !!(文件类型 & 文件格式_类型_ASMPP));
#否则
zhi_错误_不中止("不支持汇编");
#结束如果
} 否则 {
zhi语法_编译(状态机1);
}
}
状态机1->错误_设置_jmp_启用 = 0;
zhi语法_完成(状态机1);
结束_预处理(状态机1);
离开状态机();
结束_段_数据状态(状态机1);
返回 状态机1->数量_错误 != 0 ? -1 : 0;
}
HEXINKU接口 整数型 编译包含ZHI源代码的字符串(知心状态机 *s, 常量 字符型 *str)
{
返回 编译_开始(s, s->文件类型, str, -1);
}
/*定义预处理器符号。 还可以通过'='运算符提供一个值 */
HEXINKU接口 无类型 定义预处理程序符号(知心状态机 *状态机1, 常量 字符型 *sym, 常量 字符型 *value)
{
如果 (!value)
value = "1";
动态字符串_打印(&状态机1->命令行_定义, "#定义 %s %s\n", sym, value);
}
/* 取消定义预处理器符号 */
HEXINKU接口 无类型 未定义预处理符号(知心状态机 *状态机1, 常量 字符型 *sym)
{
动态字符串_打印(&状态机1->命令行_定义, "#取消定义 %s\n", sym);
}
HEXINKU接口 知心状态机 *初始化状态机(无类型)
{
知心状态机 *s;
s = 内存_初始化(取大小(知心状态机));
如果 (!s)
返回 NULL;
#如果已定义 内存_调试
++数量_states;/*自动变量:值不确定;静态变量:则为0;全局变量:则为0。*/
#结束如果
#取消定义 gnu_扩展
s->gnu_扩展 = 1;
s->zhi_扩展 = 1;
s->不使用通用符号 = 1;
s->允许_在标识符中使用美元符号 = 1; /*默认打开,如在gcc / clang中*/
s->ZHI版本 = 199901; /* 除非提供-std = c11,否则默认 */
s->警告_隐式函数声明 = 1;
s->允许_匿名联合和结构 = 1;
#如果已定义 字符串_是_无符号
s->字符串_无符号 = 1;
#结束如果
#如果已定义 ZHI_TARGET_I386
s->段_大小 = 32;
#结束如果
/* 如果要在Windows上使用带下划线的符号,请启用此功能: */
#如果 已定义 ZHI_TARGET_MACHO /* || 定义ZHI_TARGET_PE的下划线 */
s->前导_下划线 = 1;
#结束如果
s->预处理输出文件 = stdout;
/* 可能在preprocess_start()之前的error()中使用 */
s->包含_堆_ptr = s->包含_堆;
zhi_elf_新建(s);
#如果已定义 _WIN32
WIN32设置库路径(s);
#否则
设置库路径(s, 配置_ZHI目录);
#结束如果
{
字符型 buffer[32]; 整数型 a,b,c;
sscanf(ZHI_VERSION, "%d.%d.%d", &a, &b, &c);
sprintf(buffer, "%d", a*10000 + b*100 + c);
定义预处理程序符号(s, "__TINYC__", buffer);
}
/* 标准定义 */
定义预处理程序符号(s, "__STDC__", NULL);
定义预处理程序符号(s, "__STDC_VERSION__", "199901L");
定义预处理程序符号(s, "__STDC_HOSTED__", NULL);
/* 目标定义 */
#如果 已定义(ZHI_TARGET_I386)
定义预处理程序符号(s, "__i386__", NULL);
定义预处理程序符号(s, "__i386", NULL);
定义预处理程序符号(s, "i386", NULL);
#否则如果 已定义(ZHI_TARGET_X86_64)
定义预处理程序符号(s, "__x86_64__", NULL);
#否则如果 已定义(ZHI_TARGET_ARM)
定义预处理程序符号(s, "__ARM_ARCH_4__", NULL);
定义预处理程序符号(s, "__arm_elf__", NULL);
定义预处理程序符号(s, "__arm_elf", NULL);
定义预处理程序符号(s, "arm_elf", NULL);
定义预处理程序符号(s, "__arm__", NULL);
定义预处理程序符号(s, "__arm", NULL);
定义预处理程序符号(s, "arm", NULL);
定义预处理程序符号(s, "__APCS_32__", NULL);
定义预处理程序符号(s, "__ARMEL__", NULL);
#如果 已定义(ZHI_ARM_EABI)
定义预处理程序符号(s, "__ARM_EABI__", NULL);
#结束如果
#如果 已定义(ZHI_ARM_HARDFLOAT)
s->浮动_abi = ARM_HARD_FLOAT;
定义预处理程序符号(s, "__ARM_PCS_VFP", NULL);
#否则
s->浮动_abi = ARM_SOFTFP_FLOAT;
#结束如果
#否则如果 已定义(ZHI_TARGET_ARM64)
定义预处理程序符号(s, "__aarch64__", NULL);
#否则如果 已定义 ZHI_TARGET_C67
定义预处理程序符号(s, "__C67__", NULL);
#否则如果 已定义 ZHI_TARGET_RISCV64
定义预处理程序符号(s, "__riscv", NULL);
定义预处理程序符号(s, "__riscv_xlen", "64");
定义预处理程序符号(s, "__riscv_flen", "64");
定义预处理程序符号(s, "__riscv_div", NULL);
定义预处理程序符号(s, "__riscv_mul", NULL);
定义预处理程序符号(s, "__riscv_fdiv", NULL);
定义预处理程序符号(s, "__riscv_fsqrt", NULL);
定义预处理程序符号(s, "__riscv_float_abi_double", NULL);
#结束如果
#如果已定义 ZHI_TARGET_PE
定义预处理程序符号(s, "_WIN32", NULL);
定义预处理程序符号(s, "__declspec(x)", "__attribute__((x))");
定义预处理程序符号(s, "__cdecl", "");
# 如果已定义 ZHI_TARGET_X86_64
定义预处理程序符号(s, "_WIN64", NULL);
# 结束如果
#否则
定义预处理程序符号(s, "__unix__", NULL);
定义预处理程序符号(s, "__unix", NULL);
定义预处理程序符号(s, "unix", NULL);
# 如果 已定义(__linux__)
定义预处理程序符号(s, "__linux__", NULL);
定义预处理程序符号(s, "__linux", NULL);
# 结束如果
# 如果 已定义(__FreeBSD__)
定义预处理程序符号(s, "__FreeBSD__", "__FreeBSD__");
/* 带有zhi的FreeBSD上没有“本地线程存储”*/
定义预处理程序符号(s, "__NO_TLS", NULL);
# 结束如果
# 如果 已定义(__FreeBSD_kernel__)
定义预处理程序符号(s, "__FreeBSD_kernel__", NULL);
# 结束如果
# 如果 已定义(__NetBSD__)
定义预处理程序符号(s, "__NetBSD__", "__NetBSD__");
# 结束如果
# 如果 已定义(__OpenBSD__)
定义预处理程序符号(s, "__OpenBSD__", "__OpenBSD__");
# 结束如果
#结束如果
/* zhi&gcc定义 */
#如果 指针_大小 == 4
/* 32位系统. */
定义预处理程序符号(s, "__SIZE_TYPE__", "无符号 整数型");
定义预处理程序符号(s, "__PTRDIFF_TYPE__", "整数型");
定义预处理程序符号(s, "__ILP32__", NULL);
#否则如果 LONG_SIZE == 4
/* 64位 Windows. */
定义预处理程序符号(s, "__SIZE_TYPE__", "无符号 long long");
定义预处理程序符号(s, "__PTRDIFF_TYPE__", "long long");
定义预处理程序符号(s, "__LLP64__", NULL);
#否则
/* 其它64位系统. */
定义预处理程序符号(s, "__SIZE_TYPE__", "无符号 long");
定义预处理程序符号(s, "__PTRDIFF_TYPE__", "long");
定义预处理程序符号(s, "__LP64__", NULL);
#结束如果
定义预处理程序符号(s, "__SIZEOF_POINTER__", 指针_大小 == 4 ? "4" : "8");
#如果已定义 ZHI_TARGET_PE
定义预处理程序符号(s, "__WCHAR_TYPE__", "无符号 short");
定义预处理程序符号(s, "__WINT_TYPE__", "无符号 short");
#否则
定义预处理程序符号(s, "__WCHAR_TYPE__", "整数型");
/* 默认情况下,wint_t是unsigned 整数型,但在BSD上是(signed)整数型,在Windows上是unsigned short。 叹息,其他操作系统可能还有其他约定。 */
# 如果 已定义(__FreeBSD__) || 已定义 (__FreeBSD_kernel__) \
|| 已定义(__NetBSD__) || 已定义(__OpenBSD__)
定义预处理程序符号(s, "__WINT_TYPE__", "整数型");
# 如果已定义 __FreeBSD__
/* 定义__GNUC__以从sys / cdefs.h中获取一些有用的东西,这些东西在FreeBSDs其他系统头文件中无条件地使用 :/ */
定义预处理程序符号(s, "__GNUC__", "2");
定义预处理程序符号(s, "__GNUC_MINOR__", "7");
定义预处理程序符号(s, "__builtin_alloca", "alloca");
# 结束如果
# 否则
定义预处理程序符号(s, "__WINT_TYPE__", "无符号 整数型");
/* glibc定义 */
定义预处理程序符号(s, "__REDIRECT(name, proto, alias)",
"name proto __asm__ (#alias)");
定义预处理程序符号(s, "__REDIRECT_NTH(name, proto, alias)",
"name proto __asm__ (#alias) __THROW");
# 结束如果
/* 一些易于表达为宏的GCC内置函数. */
定义预处理程序符号(s, "__builtin_extract_return_addr(x)", "x");
#结束如果 /* ndef ZHI_TARGET_PE */
#如果已定义 ZHI_TARGET_MACHO
/* 模拟APPLE-GCC以编译libc头文件: */
定义预处理程序符号(s, "__APPLE__", "1");
定义预处理程序符号(s, "__GNUC__", "4"); /* darwin emits warning on GCC<4 */
定义预处理程序符号(s, "__APPLE_CC__", "1"); /* 循环 <TargetConditionals.h> */
定义预处理程序符号(s, "__builtin_alloca", "alloca"); /* as we claim GNUC */
/* 避免在libc-header文件中使用GCC / clang特定的内置函数: */
定义预处理程序符号(s, "__FINITE_MATH_ONLY__", "1");
定义预处理程序符号(s, "_FORTIFY_SOURCE", "0");
#结束如果 /* ndef ZHI_TARGET_MACHO */
返回 s;
}
HEXINKU接口 无类型 释放状态机(知心状态机 *状态机1)
{
/* free 段数 */
zhielf_删除(状态机1);
/* free library paths */
动态数组_重分配容量(&状态机1->库_路径, &状态机1->数量_库_路径);
动态数组_重分配容量(&状态机1->crt_路径, &状态机1->数量_crt_路径);
/* free 导入 paths */
动态数组_重分配容量(&状态机1->包含_路径, &状态机1->数量_包含_路径);
动态数组_重分配容量(&状态机1->系统包含_路径, &状态机1->数量_系统包含_路径);
内存_释放(状态机1->zhi_库_路径);
内存_释放(状态机1->基本名称);
内存_释放(状态机1->动态库路径);
内存_释放(状态机1->加载_符号);
内存_释放(状态机1->卸载_符号);
内存_释放(状态机1->输出文件);
内存_释放(状态机1->依赖_输出文件);
动态数组_重分配容量(&状态机1->文件数, &状态机1->数量_文件数);
动态数组_重分配容量(&状态机1->目标_依赖, &状态机1->数量_目标_依赖);
动态数组_重分配容量(&状态机1->语法_库数, &状态机1->数量_语法_库数);
动态数组_重分配容量(&状态机1->参数数组, &状态机1->参数数量);
动态字符串_释放(&状态机1->命令行_定义);
动态字符串_释放(&状态机1->命令行_包含);
#如果已定义 ZHI_是_本机
/* free runtime memory */
释放运行时内存(状态机1);
#结束如果
内存_释放(状态机1);
#如果已定义 内存_调试
如果 (0 == --数量_states)
zhi_内存检查();
#结束如果
}
HEXINKU接口 整数型 设置输出类型(知心状态机 *s, 整数型 输出_类型)
{
s->输出_类型 = 输出_类型;
/* 总是对象的可执行文件 */
如果 (输出_类型 == ZHI_输出_目标文件)
s->输出_格式 = ZHI_输出_格式_ELF;
如果 (s->字符串_无符号)
定义预处理程序符号(s, "__CHAR_UNSIGNED__", NULL);
如果 (s->ZHI版本 == 201112)
{
未定义预处理符号(s, "__STDC_VERSION__");
定义预处理程序符号(s, "__STDC_VERSION__", "201112L");
定义预处理程序符号(s, "__STDC_NO_ATOMICS__", NULL);
定义预处理程序符号(s, "__STDC_NO_COMPLEX__", NULL);
定义预处理程序符号(s, "__STDC_NO_THREADS__", NULL);
#如果未定义 ZHI_TARGET_PE
/* 在Linux上,这与glibc libs包含的/usr/导入/stdc-predef.h引入的定义冲突
定义预处理程序符号(s, "__STDC_ISO_10646__", "201605L"); */
定义预处理程序符号(s, "__STDC_UTF_16__", NULL);
定义预处理程序符号(s, "__STDC_UTF_32__", NULL);
#结束如果
}
如果 (s->编译优化 > 0)
定义预处理程序符号(s, "__OPTIMIZE__", NULL);
如果 (s->选项_线程)
定义预处理程序符号(s, "_REENTRANT", NULL);
如果 (!s->不添加标准头)
{
/* 默认包含路径 */
/* -isystem路径已被处理*/
添加到系统包含路径(s, 配置_ZHI_系统包含路径);
}
#如果已定义 配置_ZHI_边界检查
如果 (s->执行_边界_检查器)
{
/* 如果进行边界检查,则添加相应的部分 */
zhielf_bounds_new(s);
/* 定义符号 */
定义预处理程序符号(s, "__BOUNDS_CHECKING_ON", NULL);
}
#结束如果
如果 (s->执行_调试)
{
/* 添加调试部分 */
zhielf_stab_新建(s);
}
添加库路径(s, 配置_ZHI_库搜索路径);
#如果已定义 ZHI_TARGET_PE
# 如果已定义 _WIN32
如果 (!s->不添加标准库 && 输出_类型 != ZHI_输出_目标文件)
WIN32添加系统目录(s);
# 结束如果
#否则
/* crt对象的路径 */
拆分路径(s, &s->crt_路径, &s->数量_crt_路径, 配置_ZHI_CRT前缀);
/* 添加libc crt1 / crti对象 */
如果 ((输出_类型 == ZHI_输出_EXE || 输出_类型 == ZHI_输出_DLL) &&
!s->不添加标准库)
{
#如果未定义 ZHI_TARGET_MACHO
/* 具有LC_MAIN的Mach-O不需要任何crt启动代码. */
如果 (输出_类型 != ZHI_输出_DLL)
zhi_添加_crt(s, "crt1.o");
zhi_添加_crt(s, "crti.o");
#结束如果
}
#结束如果
返回 0;
}
HEXINKU接口 整数型 添加包含路径(知心状态机 *s, 常量 字符型 *pathname)
{
拆分路径(s, &s->包含_路径, &s->数量_包含_路径, pathname);
返回 0;
}
HEXINKU接口 整数型 添加到系统包含路径(知心状态机 *s, 常量 字符型 *pathname)
{
拆分路径(s, &s->系统包含_路径, &s->数量_系统包含_路径, pathname);
返回 0;
}
静态_函数 整数型 添加内部文件(知心状态机 *状态机1, 常量 字符型 *文件名, 整数型 文件类型位或错误打印)
{
整数型 只读文件, 返回值;
只读文件 = 打开文件(状态机1, 文件名);
如果 (只读文件 < 0)
{
如果 (文件类型位或错误打印 & AFF_打印_错误)
zhi_错误_不中止("没有找到文件 '%s' ", 文件名);
返回 -1;
}
状态机1->当前_文件名 = 文件名;
如果 (文件类型位或错误打印 & 文件格式_类型_BIN)
{
ElfW(ELF文件头) elf头文件;
整数型 目标文件_类型;
目标文件_类型 = zhi_目标文件_类型(只读文件, &elf头文件);
lseek(只读文件, 0, SEEK_SET);
#如果已定义 ZHI_TARGET_MACHO
如果 (0 == 目标文件_类型 && 0 == strcmp(取_文件扩展名(文件名), ".dylib"))
目标文件_类型 = AFF_二进制_DYN;
#结束如果
选择 (目标文件_类型)
{
分支 AFF_二进制_REL:
返回值 = zhi_加载_对象_文件(状态机1, 只读文件, 0);
跳出;
#如果未定义 ZHI_TARGET_PE
分支 AFF_二进制_DYN:
如果 (状态机1->输出_类型 == ZHI_输出_内存中运行)
{
返回值 = 0;
#如果已定义 ZHI_是_本机
如果 (NULL == dl打开(文件名, RTLD_全局 | RTLD_依赖))
返回值 = -1;
#结束如果
} 否则
{
#如果未定义 ZHI_TARGET_MACHO
返回值 = zhi_加载_dll(状态机1, fd, 文件名,(文件类型位或错误打印 & AFF_加载_引用的DLL) != 0);
#否则
返回值 = macho_加载_dll(状态机1, fd, 文件名,(文件类型位或错误打印 & AFF_加载_引用的DLL) != 0);
#结束如果
}
跳出;
#结束如果
分支 AFF_二进制_AR:
返回值 = zhi_加载_档案(状态机1, 只读文件, !(文件类型位或错误打印 & AFF_从存档加载_所有对象));
跳出;
#如果已定义 ZHI_TARGET_COFF
分支 AFF_二进制_C67:
返回值 = zhi_加载_coff(状态机1, fd);
跳出;
#结束如果
default:
#如果已定义 ZHI_TARGET_PE
返回值 = pe_加载_文件(状态机1, 文件名, 只读文件);
#否则如果 已定义(ZHI_TARGET_MACHO)
返回值 = -1;
#否则
/* 作为GNU ld,如果无法识别,则认为它是ld脚本 */
返回值 = zhi_加载_链接脚本(状态机1, fd);
#结束如果
如果 (返回值 < 0)
zhi_错误_不中止("%s: 无法识别的文件类型 %d", 文件名,目标文件_类型);
跳出;
}
close(只读文件);
} 否则 {
/* 更新目标部门 */
动态数组_追加元素(&状态机1->目标_依赖, &状态机1->数量_目标_依赖, 字符串_宽度加1(文件名));
返回值 = 编译_开始(状态机1, 文件类型位或错误打印, 文件名, 只读文件);//开始编译文件,编译文件入口
}
状态机1->当前_文件名 = NULL;
返回 返回值;
}
HEXINKU接口 整数型 添加文件(知心状态机 *s, 常量 字符型 *文件名)
{
整数型 文件类型 = s->文件类型;
如果 (0 == (文件类型 & 文件格式_类型_掩码))
{
常量 字符型 *扩展名 = 取_文件扩展名(文件名);
如果 (扩展名[0])
{
扩展名++;
如果 (!strcmp(扩展名, "S"))
文件类型 = 文件格式_类型_ASMPP;
否则 如果 (!strcmp(扩展名, "s"))
文件类型 = 文件格式_类型_汇编;
否则 如果 (!PATHCMP(扩展名, "z") || !PATHCMP(扩展名, "i")|| !PATHCMP(扩展名, "c"))/*设置源文件后缀名(扩展名)*/
文件类型 = 文件格式_类型_Z;
否则
文件类型 |= 文件格式_类型_BIN;
} 否则
{
文件类型 = 文件格式_类型_Z;
}
}
返回 添加内部文件(s, 文件名, 文件类型 | AFF_打印_错误);
}
HEXINKU接口 整数型 添加库路径(知心状态机 *s, 常量 字符型 *pathname)
{
拆分路径(s, &s->库_路径, &s->数量_库_路径, pathname);
返回 0;
}
静态 整数型 添加内部库(知心状态机 *s, 常量 字符型 *fmt,常量 字符型 *文件名, 整数型 flags, 字符型 **paths, 整数型 数量_paths)
{
字符型 buf[1024];
整数型 i;
循环(i = 0; i < 数量_paths; i++) {
snprintf(buf, 取大小(buf), fmt, paths[i], 文件名);
如果 (添加内部文件(s, buf, flags | 文件格式_类型_BIN) == 0)
返回 0;
}
返回 -1;
}
/* find and 加载 a dll. Return non zero 如果 not found */
/* XXX: add '-动态库路径' option support ? */
静态_函数 整数型 添加dll文件(知心状态机 *s, 常量 字符型 *文件名, 整数型 flags)
{
返回 添加内部库(s, "%s/%s", 文件名, flags,
s->库_路径, s->数量_库_路径);
}
#如果未定义 ZHI_TARGET_PE
静态_函数 整数型 zhi_添加_crt(知心状态机 *状态机1, 常量 字符型 *文件名)
{
如果 (-1 == 添加内部库(状态机1, "%s/%s",文件名, 0, 状态机1->crt_路径, 状态机1->数量_crt_路径))
zhi_错误_不中止("没有找到文件 '%s' ", 文件名);
返回 0;
}
#结束如果
/* the library name is the same as the argument of the '-l' option */
HEXINKU接口 整数型 使用库名称添加库(知心状态机 *s, 常量 字符型 *libraryname)
{
#如果 已定义 ZHI_TARGET_PE
常量 字符型 *libs[] = { "%s/%s.def", "%s/lib%s.def", "%s/%s.dll", "%s/lib%s.dll", "%s/lib%s.a", NULL };
常量 字符型 **pp = s->执行_静态链接 ? libs + 4 : libs;
#否则如果 已定义 ZHI_TARGET_MACHO
常量 字符型 *libs[] = { "%s/lib%s.dylib", "%s/lib%s.a", NULL };
常量 字符型 **pp = s->执行_静态链接 ? libs + 1 : libs;
#否则
常量 字符型 *libs[] = { "%s/lib%s.so", "%s/lib%s.a", NULL };
常量 字符型 **pp = s->执行_静态链接 ? libs + 1 : libs;
#结束如果
整数型 flags = s->文件类型 & AFF_从存档加载_所有对象;
判断 (*pp) {
如果 (0 == 添加内部库(s, *pp,
libraryname, flags, s->库_路径, s->数量_库_路径))
返回 0;
++pp;
}
返回 -1;
}
公共_函数 整数型 添加库错误(知心状态机 *状态机1, 常量 字符型 *libname)
{
整数型 返回值 = 使用库名称添加库(状态机1, libname);
如果 (返回值 < 0)
zhi_错误_不中止("没有找到库 '%s' ", libname);
返回 返回值;
}
/* handle #pragma comment(lib,) */
静态_函数 无类型 处理实用注释库(知心状态机 *状态机1)
{
整数型 i;
循环 (i = 0; i < 状态机1->数量_语法_库数; i++)
添加库错误(状态机1, 状态机1->语法_库数[i]);
}
HEXINKU接口 整数型 在已编译的程序中添加符号(知心状态机 *状态机1, 常量 字符型 *name, 常量 无类型 *val)
{
#如果已定义 ZHI_TARGET_PE
/* 在x86_64上,可能无法通过32位偏移量访问``val'',因此此处将其视为DLL中的内容进行处理。 */
pe_导入(状态机1, 0, name, (uintptr_t)val);
#否则
设置_elf_符号(单词表_部分, (uintptr_t)val, 0,
ELFW(ST_INFO)(STB_GLOBAL, STT_NOTYPE), 0,
SHN_ABS, name);
#结束如果
返回 0;
}
HEXINKU接口 无类型 设置库路径(知心状态机 *s, 常量 字符型 *path)
{
内存_释放(s->zhi_库_路径);
s->zhi_库_路径 = 字符串_宽度加1(path);
}
#定义 WD_ALL 0x0001 /* warning is activated when using -Wall */
#定义 FD_INVERT 0x0002 /* invert value before storing */
类型定义 结构体
{
uint16_t offset;
uint16_t flags;
常量 字符型 *name;
} 标记定义;
静态 整数型 没有标记(常量 字符型 **pp)
{
常量 字符型 *p = *pp;
如果 (*p != 'n' || *++p != 'o' || *++p != '-')
返回 0;
*pp = p + 1;
返回 1;
}
静态_函数 整数型 设置标记(知心状态机 *s, 常量 标记定义 *flags, 常量 字符型 *name)
{
整数型 value, 返回值;
常量 标记定义 *p;
常量 字符型 *r;
value = 1;
r = name;
如果 (没有标记(&r))
value = 0;
循环 (返回值 = -1, p = flags; p->name; ++p) {
如果 (返回值) {
如果 (strcmp(r, p->name))
继续;
} 否则 {
如果 (0 == (p->flags & WD_ALL))
继续;
}
如果 (p->offset) {
*((无符号 字符型 *)s + p->offset) =
p->flags & FD_INVERT ? !value : value;
如果 (返回值)
返回 0;
} 否则 {
返回值 = 0;
}
}
返回 返回值;
}
静态 整数型 strstart(常量 字符型 *val, 常量 字符型 **str)
{
常量 字符型 *str1, *val1;
str1 = *str;
val1 = val;
判断 (*val1)
{
如果 (*str1 != *val1)
返回 0;
str1++;
val1++;
}
*str = str1;
返回 1;
}
/*与strstart类似,但会自动考虑ld选项可以
*
*-以双破折号或单破折号开头(例如'--基本名称'或'-基本名称')
*-参数可以单独或在'='之后给出(例如'-Wl,-基本名称,x.so'
*或'-Wl,-基本名称 = x.so')
*
*您总是以“ option [=]”形式提供“ val”(无前导-)
*/
静态 整数型 链接_选项(常量 字符型 *str, 常量 字符型 *val, 常量 字符型 **ptr)
{
常量 字符型 *p, *q;
整数型 返回值;
/* 应该有1或2个破折号 */
如果 (*str++ != '-')
返回 0;
如果 (*str == '-')
str++;
/* then str & val should match (potentially up to '=') */
p = str;
q = val;
返回值 = 1;
如果 (q[0] == '?') {
++q;
如果 (没有标记(&p))
返回值 = -1;
}
判断 (*q != '\0' && *q != '=') {
如果 (*p != *q)
返回 0;
p++;
q++;
}
/* '=' near eos means ',' or '=' is ok */
如果 (*q == '=') {
如果 (*p == 0)
*ptr = p;
如果 (*p != ',' && *p != '=')
返回 0;
p++;
} 否则 如果 (*p) {
返回 0;
}
*ptr = p;
返回 返回值;
}
静态 常量 字符型 *跳过_链接器_参数(常量 字符型 **str)
{
常量 字符型 *状态机1 = *str;
常量 字符型 *s2 = strchr(状态机1, ',');
*str = s2 ? s2++ : (s2 = 状态机1 + strlen(状态机1));
返回 s2;
}
静态 无类型 复制_链接器_参数(字符型 **pp, 常量 字符型 *s, 整数型 sep)
{
常量 字符型 *q = s;
字符型 *p = *pp;
整数型 l = 0;
如果 (p && sep)
p[l = strlen(p)] = sep, ++l;
跳过_链接器_参数(&q);
复制_字符串(l + (*pp = 内存_重分配容量(p, q - s + l + 1)), s, q - s);
}
/* set linker options */
静态 整数型 设置链接器(知心状态机 *s, 常量 字符型 *option)
{
知心状态机 *状态机1 = s;
判断 (*option) {
常量 字符型 *p = NULL;
字符型 *end = NULL;
整数型 ignoring = 0;
整数型 返回值;
如果 (链接_选项(option, "Bsymbolic", &p)) {
s->先解析当前模块符号 = 1;
} 否则 如果 (链接_选项(option, "不添加标准库", &p)) {
s->不添加标准库 = 1;
} 否则 如果 (链接_选项(option, "fini=", &p)) {
复制_链接器_参数(&s->卸载_符号, p, 0);
ignoring = 1;
} 否则 如果 (链接_选项(option, "image-base=", &p)
|| 链接_选项(option, "Ttext=", &p)) {
s->代码段_地址 = strtoull(p, &end, 16);
s->已有_代码段_地址 = 1;
} 否则 如果 (链接_选项(option, "init=", &p)) {
复制_链接器_参数(&s->加载_符号, p, 0);
ignoring = 1;
} 否则 如果 (链接_选项(option, "oformat=", &p)) {
#如果 已定义(ZHI_TARGET_PE)
如果 (strstart("pe-", &p)) {
#否则如果 指针_大小 == 8
如果 (strstart("elf64-", &p)) {
#否则
如果 (strstart("elf32-", &p)) {
#结束如果
s->输出_格式 = ZHI_输出_格式_ELF;
} 否则 如果 (!strcmp(p, "binary")) {
s->输出_格式 = ZHI_输出_格式_二进制;
#如果已定义 ZHI_TARGET_COFF
} 否则 如果 (!strcmp(p, "coff")) {
s->输出_格式 = ZHI_输出_格式_COFF;
#结束如果
} 否则
去向 err;
} 否则 如果 (链接_选项(option, "as-needed", &p)) {
ignoring = 1;
} 否则 如果 (链接_选项(option, "O", &p)) {
ignoring = 1;
} 否则 如果 (链接_选项(option, "export-all-symbols", &p)) {
s->导出所有符号 = 1;
} 否则 如果 (链接_选项(option, "export-dynamic", &p)) {
s->导出所有符号 = 1;
} 否则 如果 (链接_选项(option, "动态库路径=", &p)) {
复制_链接器_参数(&s->动态库路径, p, ':');
} 否则 如果 (链接_选项(option, "enable-new-dtags", &p)) {
s->启用新的dtags = 1;
} 否则 如果 (链接_选项(option, "section-alignment=", &p)) {
s->分段_对齐 = strtoul(p, &end, 16);
} 否则 如果 (链接_选项(option, "基本名称=", &p)) {
复制_链接器_参数(&s->基本名称, p, 0);
#如果已定义 ZHI_TARGET_PE
} 否则 如果 (链接_选项(option, "large-address-aware", &p)) {
s->pe_特征 |= 0x20;
} 否则 如果 (链接_选项(option, "file-alignment=", &p)) {
s->pe_文件_对齐 = strtoul(p, &end, 16);
} 否则 如果 (链接_选项(option, "stack=", &p)) {
s->pe_堆栈_大小 = strtoul(p, &end, 10);
} 否则 如果 (链接_选项(option, "subsystem=", &p)) {
#如果 已定义(ZHI_TARGET_I386) || 已定义(ZHI_TARGET_X86_64)
如果 (!strcmp(p, "native")) {
s->pe_子系统 = 1;
} 否则 如果 (!strcmp(p, "console")) {
s->pe_子系统 = 3;
} 否则 如果 (!strcmp(p, "gui") || !strcmp(p, "windows")) {
s->pe_子系统 = 2;
} 否则 如果 (!strcmp(p, "posix")) {
s->pe_子系统 = 7;
} 否则 如果 (!strcmp(p, "efiapp")) {
s->pe_子系统 = 10;
} 否则 如果 (!strcmp(p, "efiboot")) {
s->pe_子系统 = 11;
} 否则 如果 (!strcmp(p, "efiruntime")) {
s->pe_子系统 = 12;
} 否则 如果 (!strcmp(p, "efirom")) {
s->pe_子系统 = 13;
#否则如果 已定义(ZHI_TARGET_ARM)
如果 (!strcmp(p, "wince")) {
s->pe_子系统 = 9;
#结束如果
} 否则
去向 err;
#结束如果
} 否则 如果 (返回值 = 链接_选项(option, "?whole-archive", &p), 返回值) {
如果 (返回值 > 0)
s->文件类型 |= AFF_从存档加载_所有对象;
否则
s->文件类型 &= ~AFF_从存档加载_所有对象;
} 否则 如果 (p) {
返回 0;
} 否则 {
err:
错误_打印("不支持的链接器选项 '%s'", option);
}
如果 (ignoring && s->警告_不支持)
zhi_警告("不支持的链接器选项 '%s'", option);
option = 跳过_链接器_参数(&p);
}
返回 1;
}
类型定义 结构体
{
常量 字符型 *name;
uint16_t index;
uint16_t flags;
} 知心指令;
枚举 {
知心编译_指令_帮助,
知心编译_指令_关于,
知心编译_指令_版本,
知心编译_指令_添加头文件路径,
知心编译_指令_用val定义sym,
知心编译_指令_未定义的sym,
知心编译_指令_P,
知心编译_指令_添加库路径,
知心编译_指令_设置zhi实用程序路径,
知心编译_指令_l,
知心编译_指令_显示编译统计,
知心编译_指令_与backtrace链接,
知心编译_指令_使用内置内存和边界检查器进行编译,
知心编译_指令_ba,
知心编译_指令_生成运行时调试信息,
知心编译_指令_仅编译不链接,
知心编译_指令_打印版本信息,
知心编译_指令_使用E输出宏定义指令,
知心编译_指令_链接到静态库,
知心编译_指令_设置知心编译器标准,
知心编译_指令_生成共享库,
知心编译_指令_设置运行时使用的共享库名称,
知心编译_指令_设置输出文件名,
知心编译_指令_生成可重定位目标文件,
知心编译_指令_s,
知心编译_指令_traditional,
知心编译_指令_设置链接器,
知心编译_指令_Wp,
知心编译_指令_设置和重置警告,
知心编译_指令_仅用于定义OPTIMIZE,
知心编译_指令_mfloat_abi,
知心编译_指令_m,
知心编译_指令_设置或重置flag,
知心编译_指令_添加到系统包含路径,
知心编译_指令_iwithprefix,
知心编译_指令_在文件上方导入文件,
知心编译_指令_不使用标准系统包含路径,
知心编译_指令_不与标准crt和库链接,
知心编译_指令_打印搜索路径,
知心编译_指令_所有全局符号导出到动态链接器,
知心编译_指令_param,
知心编译_指令_pedantic,
知心编译_指令_连接线程,
知心编译_指令_编译源文件,
知心编译_指令_禁止所有警告,
知心编译_指令_pipe,
知心编译_指令_生成预处理文件,
知心编译_指令_生成make的依赖文件,
知心编译_指令_指定依赖文件名,
知心编译_指令_指定文件后缀类型,
知心编译_指令_创建库,
知心编译_指令_创建定义文件
};
#定义 知心编译_指令_有_参数 0x0001
#定义 知心编译_指令_NOSEP 0x0002 /* option和arg之前不能有空间 */
静态 常量 知心指令 zhi_选项[] = {
{ "帮助", 知心编译_指令_帮助, 0 },
{ "h", 知心编译_指令_帮助, 0 },
{ "help", 知心编译_指令_帮助, 0 },
{ "?", 知心编译_指令_帮助, 0 },
{ "关于", 知心编译_指令_关于, 0 },
{ "about", 知心编译_指令_关于, 0 },
{ "版本", 知心编译_指令_版本, 知心编译_指令_有_参数 | 知心编译_指令_NOSEP },
{ "v", 知心编译_指令_版本, 知心编译_指令_有_参数 | 知心编译_指令_NOSEP },
{ "version", 知心编译_指令_版本, 0 },
{ "I", 知心编译_指令_添加头文件路径, 知心编译_指令_有_参数 },
{ "D", 知心编译_指令_用val定义sym, 知心编译_指令_有_参数 },
{ "U", 知心编译_指令_未定义的sym, 知心编译_指令_有_参数 },
{ "P", 知心编译_指令_P, 知心编译_指令_有_参数 | 知心编译_指令_NOSEP },
{ "L", 知心编译_指令_添加库路径, 知心编译_指令_有_参数 },
{ "B", 知心编译_指令_设置zhi实用程序路径, 知心编译_指令_有_参数 },
{ "l", 知心编译_指令_l, 知心编译_指令_有_参数 },
{ "bench", 知心编译_指令_显示编译统计, 0 },
#如果已定义 ZHI_配置_记录回滚
{ "bt", 知心编译_指令_与backtrace链接, 知心编译_指令_有_参数 | 知心编译_指令_NOSEP },
#结束如果
#如果已定义 配置_ZHI_边界检查
{ "b", 知心编译_指令_使用内置内存和边界检查器进行编译, 0 },
#结束如果
{ "g", 知心编译_指令_生成运行时调试信息, 知心编译_指令_有_参数 | 知心编译_指令_NOSEP },
{ "c", 知心编译_指令_仅编译不链接, 0 },
{ "dumpversion", 知心编译_指令_打印版本信息, 0},
{ "d", 知心编译_指令_使用E输出宏定义指令, 知心编译_指令_有_参数 | 知心编译_指令_NOSEP },
{ "静态", 知心编译_指令_链接到静态库, 0 },
{ "std", 知心编译_指令_设置知心编译器标准, 知心编译_指令_有_参数 | 知心编译_指令_NOSEP },
{ "shared", 知心编译_指令_生成共享库, 0 },
{ "基本名称", 知心编译_指令_设置运行时使用的共享库名称, 知心编译_指令_有_参数 },
{ "o", 知心编译_指令_设置输出文件名, 知心编译_指令_有_参数 },
{ "-param", 知心编译_指令_param, 知心编译_指令_有_参数 },
{ "pedantic", 知心编译_指令_pedantic, 0},
{ "pthread", 知心编译_指令_连接线程, 0},
{ "运行", 知心编译_指令_编译源文件, 知心编译_指令_有_参数 | 知心编译_指令_NOSEP },
{ "run", 知心编译_指令_编译源文件, 知心编译_指令_有_参数 | 知心编译_指令_NOSEP },
{ "导出所有符号", 知心编译_指令_所有全局符号导出到动态链接器, 0 },
{ "r", 知心编译_指令_生成可重定位目标文件, 0 },
{ "s", 知心编译_指令_s, 0 },
{ "traditional", 知心编译_指令_traditional, 0 },
{ "Wl,", 知心编译_指令_设置链接器, 知心编译_指令_有_参数 | 知心编译_指令_NOSEP },
{ "Wp,", 知心编译_指令_Wp, 知心编译_指令_有_参数 | 知心编译_指令_NOSEP },
{ "W", 知心编译_指令_设置和重置警告, 知心编译_指令_有_参数 | 知心编译_指令_NOSEP },
{ "O", 知心编译_指令_仅用于定义OPTIMIZE, 知心编译_指令_有_参数 | 知心编译_指令_NOSEP },
#如果已定义 ZHI_TARGET_ARM
{ "mfloat-abi", 知心编译_指令_mfloat_abi, 知心编译_指令_有_参数 },
#结束如果
{ "m", 知心编译_指令_m, 知心编译_指令_有_参数 | 知心编译_指令_NOSEP },
{ "f", 知心编译_指令_设置或重置flag, 知心编译_指令_有_参数 | 知心编译_指令_NOSEP },
{ "isystem", 知心编译_指令_添加到系统包含路径, 知心编译_指令_有_参数 },
{ "include", 知心编译_指令_在文件上方导入文件, 知心编译_指令_有_参数 },
{ "不添加标准头", 知心编译_指令_不使用标准系统包含路径, 0 },
{ "不添加标准库", 知心编译_指令_不与标准crt和库链接, 0 },
{ "print-search-dirs", 知心编译_指令_打印搜索路径, 0 },
{ "w", 知心编译_指令_禁止所有警告, 0 },
{ "pipe", 知心编译_指令_pipe, 0},
{ "E", 知心编译_指令_生成预处理文件, 0},
{ "MD", 知心编译_指令_生成make的依赖文件, 0},
{ "MF", 知心编译_指令_指定依赖文件名, 知心编译_指令_有_参数 },
{ "x", 知心编译_指令_指定文件后缀类型, 知心编译_指令_有_参数 },
{ "ar", 知心编译_指令_创建库, 0},
#如果已定义 ZHI_TARGET_PE
{ "impdef", 知心编译_指令_创建定义文件, 0},
#结束如果
{ NULL, 0, 0 },
};
静态 常量 标记定义 选项_W[] = {
{ 0, 0, "all" },
{ offsetof(知心状态机, 警告_不支持), 0, "unsupported" },
{ offsetof(知心状态机, 警告_写字符串), 0, "write-strings" },
{ offsetof(知心状态机, 警告_错误), 0, "error" },
{ offsetof(知心状态机, 警告_gcc兼容), 0, "gcc-compat" },
{ offsetof(知心状态机, 警告_隐式函数声明), WD_ALL,
"implicit-function-declaration" },
{ 0, 0, NULL }
};
静态 常量 标记定义 选项_f[] = {
{ offsetof(知心状态机, 字符串_无符号), 0, "无符号-字符型" },
{ offsetof(知心状态机, 字符串_无符号), FD_INVERT, "signed-字符型" },
{ offsetof(知心状态机, 不使用通用符号), FD_INVERT, "common" },
{ offsetof(知心状态机, 前导_下划线), 0, "leading-underscore" },
{ offsetof(知心状态机, 允许_匿名联合和结构), 0, "ms-extensions" },
{ offsetof(知心状态机, 允许_在标识符中使用美元符号), 0, "dollars-in-identifiers" },
{ 0, 0, NULL }
};
静态 常量 标记定义 选项_m[] = {
{ offsetof(知心状态机, 模拟_对齐位域MS算法), 0, "ms-bitfields" },
#如果已定义 ZHI_TARGET_X86_64
{ offsetof(知心状态机, 支持mno和sse), FD_INVERT, "sse" },
#结束如果
{ 0, 0, NULL }
};
静态 无类型 解析_选项_D(知心状态机 *状态机1, 常量 字符型 *编译指令)
{
字符型 *sym = 字符串_宽度加1(编译指令);
字符型 *value = strchr(sym, '=');
如果 (value)
*value++ = '\0';
定义预处理程序符号(状态机1, sym, value);
内存_释放(sym);
}
静态 无类型 参数_解析_增加_文件(知心状态机 *s, 常量 字符型* 文件名, 整数型 文件类型)
{
文件名称类型结构 *文件 = 内存_申请(取大小 *文件 + strlen(文件名));
文件->类型 = 文件类型;
strcpy(文件->名称, 文件名);
动态数组_追加元素(&s->文件数, &s->数量_文件数, 文件);
}
静态 整数型 参数数量_解析_make_参数数组(常量 字符型 *文件缓存区, 整数型 *命令行参数数量, 字符型 ***命令行参数数组)
{
整数型 返回值 = 0, q, c;
动态字符串 str;
循环(;;)/*永久循环*/
{
判断 (c = (无符号 字符型)*文件缓存区, c && c <= ' ')
++文件缓存区;
如果 (c == 0)
跳出;
q = 0;
动态字符串_初始化(&str);
判断 (c = (无符号 字符型)*文件缓存区, c)
{
++文件缓存区;
如果 (c == '\\' && (*文件缓存区 == '"' || *文件缓存区 == '\\'))
{
c = *文件缓存区++;
} 否则 如果 (c == '"') {
q = !q;
继续;
} 否则 如果 (q == 0 && c <= ' ')
{
跳出;
}
动态字符串_追加单个字符(&str, c);
}
动态字符串_追加单个字符(&str, 0);
动态数组_追加元素(命令行参数数组, 命令行参数数量, 字符串_宽度加1(str.指向字符串的指针));
动态字符串_释放(&str);
++返回值;
}
返回 返回值;
}
/* 读取文件列表 */
静态 无类型 从参数数组获取列表文件(知心状态机 *状态机,常量 字符型 *文件名, 整数型 optind, 整数型 *pargc, 字符型 ***pargv)
{
知心状态机 *状态机1 = 状态机;
整数型 文件描述词, i;
size_t 文件字节数;
字符型 *文件的缓存区;
整数型 参数数量 = 0;
字符型 **命令行参数数组 = NULL;
/*open(文件名, O_RDONLY | O_BINARY)参数 文件名 指向欲打开的文件路径字符串. 下列是参数flags 所能使用的旗标:O_RDONLY 以只读方式打开文件.
* 返回值:若所有欲核查的权限都通过了检查则返回0 值, 表示成功, 只要有一个权限被禁止则返回-1.*/
文件描述词 = open(文件名, O_RDONLY | O_BINARY);
如果 (文件描述词 < 0)
错误_打印("找不到列表文件 '%s' ", 文件名);
文件字节数 = lseek(文件描述词, 0, SEEK_END);/*移动文件的读写位置到文件尾位置*/
文件的缓存区 = 内存_申请(文件字节数 + 1);
文件的缓存区[文件字节数] = 0;
lseek(文件描述词, 0, SEEK_SET);/*移动文件的读写位置到文件开始位置*/
read(文件描述词, 文件的缓存区, 文件字节数);/*read(整数型 fd,无类型 *buf,整数型 count);从文件说明符fd相关联的文件中读取count个字符,并把这些字符存储到buf所指的缓冲区中。*/
close(文件描述词);
循环 (i = 0; i < *pargc; ++i)
如果 (i == optind)
参数数量_解析_make_参数数组(文件的缓存区, &参数数量, &命令行参数数组);
否则
动态数组_追加元素(&命令行参数数组, &参数数量, 字符串_宽度加1((*pargv)[i]));
内存_释放(文件的缓存区);
动态数组_重分配容量(&状态机->参数数组, &状态机->参数数量);
*pargc = 状态机->参数数量 = 参数数量, *pargv = 状态机->参数数组 = 命令行参数数组;
}
/*开始解析main导入的参数文件*/
公共_函数 整数型 解析命令行参数(知心状态机 *状态机, 整数型 *pargc, 字符型 ***pargv, 整数型 optind)/*optind(选择)*/
{
知心状态机 *状态机1 = 状态机;
常量 知心指令 *临时指令;
常量 字符型 *编译指令, *临时参数数组;
常量 字符型 *run = NULL;
整数型 x;
动态字符串 连接器变量; /* 查找 -Wl 选项 */
整数型 tool = 0, arg_start = 0, noaction = optind;
字符型 **命令行参数数组 = *pargv;
整数型 命令行参数数量 = *pargc;
动态字符串_初始化(&连接器变量);
/***************************判断()--开始***************************/
判断 (optind < 命令行参数数量)
{
临时参数数组 = 命令行参数数组[optind];
如果 (临时参数数组[0] == '@' && 临时参数数组[1] != '\0')
{
从参数数组获取列表文件(状态机, 临时参数数组 + 1, optind, &命令行参数数量, &命令行参数数组);
继续;
}
optind++;
如果 (tool)
{
如果 (临时参数数组[0] == '-' && 临时参数数组[1] == 'v' && 临时参数数组[2] == 0)
++状态机->显示信息;
继续;
}
reparse:
如果 (临时参数数组[0] != '-' || 临时参数数组[1] == '\0')
{
如果 (临时参数数组[0] != '@') /* 允许“ zhi file(s) -run @ args ...” */
参数_解析_增加_文件(状态机, 临时参数数组, 状态机->文件类型);
如果 (run)
{
设置编译选项(状态机, run);
arg_start = optind - 1;
跳出;
}
继续;
}
/* 在表中查找选项 */
循环(临时指令 = zhi_选项; ; ++临时指令)
{
常量 字符型 *指令名称1 = 临时指令->name;
常量 字符型 *指令1 = 临时参数数组 + 1;
如果 (指令名称1 == NULL)
错误_打印("无效的指令 -- '%s'", 临时参数数组);
如果 (!strstart(指令名称1, &指令1))
继续;
编译指令 = 指令1;
如果 (临时指令->flags & 知心编译_指令_有_参数)
{
如果 (*指令1 == '\0' && !(临时指令->flags & 知心编译_指令_NOSEP))
{
如果 (optind >= 命令行参数数量)
{参数_错误:
错误_打印(" '%s' 的参数丢失", 临时参数数组);
}
编译指令 = 命令行参数数组[optind++];
}
} 否则 如果 (*指令1 != '\0')
继续;
跳出;
}
选择(临时指令->index)
{
分支 知心编译_指令_帮助:
x = 指令_HELP;
去向 extra_action;
分支 知心编译_指令_关于:
x = 指令_ABOUT;
去向 extra_action;
分支 知心编译_指令_添加头文件路径:
添加包含路径(状态机, 编译指令);
跳出;
分支 知心编译_指令_用val定义sym:
解析_选项_D(状态机, 编译指令);
跳出;
分支 知心编译_指令_未定义的sym:
未定义预处理符号(状态机, 编译指令);
跳出;
分支 知心编译_指令_添加库路径:
添加库路径(状态机, 编译指令);
跳出;
分支 知心编译_指令_设置zhi实用程序路径:
/* 设置zhi实用程序路径(主要用于zhi开发) */
设置库路径(状态机, 编译指令);
跳出;
分支 知心编译_指令_l:
参数_解析_增加_文件(状态机, 编译指令, 文件格式_类型_库 | (状态机->文件类型 & ~文件格式_类型_掩码));
状态机->数量_库数++;
跳出;
分支 知心编译_指令_连接线程:
状态机->选项_线程 = 1;
跳出;
分支 知心编译_指令_显示编译统计:
状态机->显示_编译统计 = 1;
跳出;
#如果已定义 ZHI_配置_记录回滚
分支 知心编译_指令_与backtrace链接:
状态机->运行时_num_callers = atoi(编译指令);
状态机->执行_跟踪 = 1;
状态机->执行_调试 = 1;
跳出;
#结束如果
#如果已定义 配置_ZHI_边界检查
分支 知心编译_指令_使用内置内存和边界检查器进行编译:
状态机->执行_边界_检查器 = 1;
状态机->执行_跟踪 = 1;
状态机->执行_调试 = 1;
跳出;
#结束如果
分支 知心编译_指令_生成运行时调试信息:
状态机->执行_调试 = 1;
跳出;
分支 知心编译_指令_仅编译不链接:
x = ZHI_输出_目标文件;
set_output_type:
如果 (状态机->输出_类型)
zhi_警告("-%s: 覆盖已指定的编译器操作", 临时指令->name);
状态机->输出_类型 = x;
跳出;
分支 知心编译_指令_使用E输出宏定义指令:
如果 (*编译指令 == 'D')
状态机->DX标号 = 3;
否则 如果 (*编译指令 == 'M')
状态机->DX标号 = 7;
否则 如果 (*编译指令 == 't')
状态机->DX标号 = 16;
否则 如果 (是数字(*编译指令))
状态机->g_调试 |= atoi(编译指令);
否则
去向 不支持的_选项;
跳出;
分支 知心编译_指令_链接到静态库:
状态机->执行_静态链接 = 1;
跳出;
分支 知心编译_指令_设置知心编译器标准:
如果 (strcmp(编译指令, "=c11") == 0)
状态机->ZHI版本 = 201112;
跳出;
分支 知心编译_指令_生成共享库:
x = ZHI_输出_DLL;
去向 set_output_type;
分支 知心编译_指令_设置运行时使用的共享库名称:
状态机->基本名称 = 字符串_宽度加1(编译指令);
跳出;
分支 知心编译_指令_设置输出文件名:
如果 (状态机->输出文件)
{
zhi_警告("多个 -o 选项");
内存_释放(状态机->输出文件);
}
状态机->输出文件 = 字符串_宽度加1(编译指令);
跳出;
分支 知心编译_指令_生成可重定位目标文件:
/* 生成.o 合并多个输出文件 */
状态机->选项_可重定位目标文件 = 1;
x = ZHI_输出_目标文件;
去向 set_output_type;
分支 知心编译_指令_添加到系统包含路径:
添加到系统包含路径(状态机, 编译指令);
跳出;
分支 知心编译_指令_在文件上方导入文件:
动态字符串_打印(&状态机->命令行_包含, "#导入 \"%s\"\n", 编译指令);
跳出;
分支 知心编译_指令_不使用标准系统包含路径:
状态机->不添加标准头 = 1;
跳出;
分支 知心编译_指令_不与标准crt和库链接:
状态机->不添加标准库 = 1;
跳出;
分支 知心编译_指令_编译源文件:
#如果未定义 ZHI_是_本机
错误_打印("-run 在交叉编译器中不可用");
#结束如果
run = 编译指令;
x = ZHI_输出_内存中运行;
去向 set_output_type;
分支 知心编译_指令_版本:
执行 ++状态机->显示信息; 判断 (*编译指令++ == 'v');
++noaction;
跳出;
分支 知心编译_指令_设置或重置flag:
如果 (设置标记(状态机, 选项_f, 编译指令) < 0)
去向 不支持的_选项;
跳出;
#如果已定义 ZHI_TARGET_ARM
分支 知心编译_指令_mfloat_abi:
/* zhi还不支持软浮动 */
如果 (!strcmp(编译指令, "softfp"))
{
s->浮动_abi = ARM_SOFTFP_FLOAT;
未定义预处理符号(s, "__ARM_PCS_VFP");
} 否则 如果 (!strcmp(编译指令, "hard"))
s->浮动_abi = ARM_HARD_FLOAT;
否则
错误_打印("不支持的浮动abi '%s'", 编译指令);
跳出;
#结束如果
分支 知心编译_指令_m:
如果 (设置标记(状态机, 选项_m, 编译指令) < 0)
{
如果 (x = atoi(编译指令), x != 32 && x != 64)/*整数型 atoi(常量 字符型 *str) 把参数 str 所指向的字符串转换为一个整数(类型为 整数型 型)。*/
去向 不支持的_选项;
如果 (指针_大小 != x/8)
返回 x;
++noaction;
}
跳出;
分支 知心编译_指令_设置和重置警告:
状态机->警告_none = 0;
如果 (编译指令[0] && 设置标记(状态机, 选项_W, 编译指令) < 0)
去向 不支持的_选项;
跳出;
分支 知心编译_指令_禁止所有警告:
状态机->警告_none = 1;
跳出;
分支 知心编译_指令_所有全局符号导出到动态链接器:
状态机->导出所有符号 = 1;
跳出;
分支 知心编译_指令_设置链接器:
如果 (连接器变量.字符串长度)
--连接器变量.字符串长度, 动态字符串_追加单个字符(&连接器变量, ',');
动态字符串_cat(&连接器变量, 编译指令, 0);
如果 (设置链接器(状态机, 连接器变量.指向字符串的指针))
动态字符串_释放(&连接器变量);
跳出;
分支 知心编译_指令_Wp:
临时参数数组 = 编译指令;
去向 reparse;
分支 知心编译_指令_生成预处理文件:
x = ZHI_输出_预处理;
去向 set_output_type;
分支 知心编译_指令_P:
状态机->P标号 = atoi(编译指令) + 1;
跳出;
分支 知心编译_指令_生成make的依赖文件:
状态机->生成_依赖 = 1;
跳出;
分支 知心编译_指令_指定依赖文件名:
状态机->依赖_输出文件 = 字符串_宽度加1(编译指令);
跳出;
分支 知心编译_指令_打印版本信息:
printf ("%s\n", ZHI_VERSION);
exit(0);
跳出;
分支 知心编译_指令_指定文件后缀类型:
x = 0;
如果 (*编译指令 == 'c')
x = 文件格式_类型_Z;
否则 如果 (*编译指令 == 'a')
x = 文件格式_类型_ASMPP;
否则 如果 (*编译指令 == 'b')
x = 文件格式_类型_BIN;
否则 如果 (*编译指令 == 'n')
x = 文件格式_类型_NONE;
否则
zhi_警告("不支持的语言 '%s'", 编译指令);
状态机->文件类型 = x | (状态机->文件类型 & ~文件格式_类型_掩码);
跳出;
分支 知心编译_指令_仅用于定义OPTIMIZE:
状态机->编译优化 = atoi(编译指令);
跳出;
分支 知心编译_指令_打印搜索路径:
x = 指令_打印_目录;
去向 extra_action;
分支 知心编译_指令_创建定义文件:
x = 指令_IMPDEF;
去向 extra_action;
分支 知心编译_指令_创建库:
x = 指令_AR;
extra_action:
arg_start = optind - 1;
如果 (arg_start != noaction)
错误_打印("无法在这里解析 %s ", 临时参数数组);
tool = x;
跳出;
分支 知心编译_指令_traditional:
分支 知心编译_指令_pedantic:
分支 知心编译_指令_pipe:
分支 知心编译_指令_s:
/* 被忽略 */
跳出;
default:
不支持的_选项:
如果 (状态机->警告_不支持)
zhi_警告("不支持的选项 '%s'", 临时参数数组);
跳出;
}
}
/***************************判断()--结束***************************/
如果 (连接器变量.字符串长度)
{
临时参数数组 = 连接器变量.指向字符串的指针;
去向 参数_错误;
}
*pargc = 命令行参数数量 - arg_start;
*pargv = 命令行参数数组 + arg_start;
如果 (tool)
返回 tool;
如果 (optind != noaction)
返回 0;
如果 (状态机->显示信息 == 2)
返回 指令_打印_目录;
如果 (状态机->显示信息)
返回 指令_V;
返回 指令_HELP;
}
HEXINKU接口 无类型 设置编译选项(知心状态机 *s, 常量 字符型 *r)
{
字符型 **命令行参数数组 = NULL;
整数型 参数数量 = 0;
参数数量_解析_make_参数数组(r, &参数数量, &命令行参数数组);
解析命令行参数(s, &参数数量, &命令行参数数组, 0);
动态数组_重分配容量(&命令行参数数组, &参数数量);
}
公共_函数 无类型 显示编译统计信息(知心状态机 *状态机1, 无符号 total_time)
{
如果 (total_time < 1)
total_time = 1;
如果 (总_字节数 < 1)
总_字节数 = 1;
fprintf(stderr, "* %d 个标识符, %d 行, %d 个字节\n"
"* %0.3f 秒, %u 行/秒, %0.1f 兆字节(MB)/秒\n",
总_idents, 总_行数, 总_字节数,
(double)total_time/1000,
(无符号)总_行数*1000/total_time,
(double)总_字节数/1000/total_time);
#如果已定义 内存_调试
fprintf(stderr, "* 已使用 %d 个字节的内存\n", 内存_最大_大小);
#结束如果
}
上一篇: 李广战功赫赫,为什么结局却很凄惨呢?
下一篇: 复杂业务逻辑下的合理遍历
推荐阅读
-
TCC(TinyC)编译器汉化(中文编译器、汉语编程)之四:语法分析上
-
TCC(TinyC)编译器汉化(中文编译器、汉语编程)之三:词法分析
-
TCC(TinyC)编译器汉化(中文编译器、汉语编程)之二:字符(token)汉化
-
TCC(TinyC)编译器汉化(中文编译器、汉语编程)之九:核心库源码
-
TCC(TinyC)编译器汉化(中文编译器、汉语编程)之七:中间语言生成器
-
TCC(TinyC)编译器汉化(中文编译器、汉语编程)之六:中间操作码
-
TCC(TinyC)编译器汉化(中文编译器、汉语编程)之八:汇编处理
-
TCC(TinyC)编译器汉化(中文编译器、汉语编程)之一:主文件汉化
-
TCC(TinyC)编译器汉化(中文编译器、汉语编程)之五:语法分析下