欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

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