TCC(TinyC)编译器汉化(中文编译器、汉语编程)之九:核心库源码

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", 内存_最大_大小);
#结束如果
}

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

知语言

您的鼓励是我从事编译器汉化动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值