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

TCC(TinyC)编译器汉化(中文编译器、汉语编程)之三:词法分析

程序员文章站 2022-03-30 20:41:08
...

词法分析.h 源码如下:

/*
 *  功能:预处理,词法分析
 *  只在hexinku.c第7行一个地方引用
 */
#定义 全局_使用
#导入 "zhi.h"

/********************************************************/
/* 全局变量 */

静态_外部 整数型 标识符_标记;
静态_外部 整数型 解析_标记;

静态_外部 结构体 缓冲文件 *file;
静态_外部 整数型 当前取到的源码字符, 单词编码;
静态_外部 恒定值 单词值;
静态_外部 常量 整数型 *宏_ptr;
静态_外部 动态字符串 当前单词字符串;

/* 显示基准信息 */
静态_外部 整数型 单词_识别号;
静态_外部 单词存储结构 **单词表;

/* ------------------------------------------------------------------------- */

静态 单词存储结构 *单词_哈希表[哈希表容量];
静态 字符型 标识符_缓冲[字符串_最大_长度 + 1];
静态 动态字符串 动态字符串_缓冲;
静态 动态字符串 宏_等于_缓冲区;
静态 单词字符串 单词字符串_缓冲;
静态 无符号 字符型 等值_表[256 - CH_文件结尾];
静态 整数型 词法分析_调试_标识符, 词法分析_调试_字符值;
静态 整数型 词法分析_第一次;
静态 整数型 词法分析_表达式;
静态 整数型 词法分析_计数器;
静态 无类型 标识符_打印(常量 字符型 *msg, 常量 整数型 *str);

静态 结构体 微内存分配 *单词字符_分配内存;
静态 结构体 微内存分配 *单词字符串_分配内存;

静态 单词字符串 *宏_堆栈;

静态 常量 字符型 编译_关键词[] = 
#定义 字符(id, str) str "\0"
#导入 "字符.h"
;

/* 双字符符号编号 */
静态 常量 无符号 字符型 双字符符号[] =
{
    '<','=', 双符号_小于等于,
    '>','=', 双符号_大于等于,
    '!','=', 双符号_不等于,
    '&','&', 双符号_逻辑与,
    '|','|', 双符号_逻辑或,
    '+','+', 双符号_自加1,
    '-','-', 双符号_自减1,
    '=','=', 双符号_等于,
    '<','<', 双符号_左位移,
    '>','>', 双符号_右位移,
    '+','=', 双符号_先求和后赋值,
    '-','=', 双符号_先求差后赋值,
    '*','=', 双符号_先求积后赋值,
    '/','=', 双符号_先求商后赋值,
    '%','=', 双符号_先取模后赋值,
    '&','=', 双符号_先求位与后赋值,
    '^','=', 双符号_先求异或后赋值,
    '|','=', 双符号_先求位或后赋值,
    '-','>', 双符号_结构体指针运算符,
    '.','.', 双符号_2个圆点号,
    '#','#', 双符号_2个井号,
    0
};

静态 无类型 取_下个符号_不宏扩展(无类型);
/*跳到下一个标识符*/
静态_函数 无类型 跳过(整数型 c)
{
    如果 (单词编码 != c)
        错误_打印("'%c'(程序中的 \"%s\")应为:''", c, 取_单词字符串(单词编码, &单词值));
    带有宏替换的下个标记();
}

静态_函数 无类型 应为(常量 字符型 *msg)
{
    错误_打印("%s 应为", msg);
}

/* ------------------------------------------------------------------------- */
/* 自定义分配器,用于微小对象 */

#定义 小对象_分配器

#如果未定义 小对象_分配器
#定义 小分配器_释放(al, p) 内存_释放(p)
#定义 小分配器_重新分配(al, p, size) 内存_重分配容量(p, size)
#定义 小分配器_新建(a,b,c)
#定义 小分配器_删除(a)
#否则
#如果 !已定义(内存_调试)
#定义 小分配器_释放(al, p) 小分配器_释放_impl(al, p)
#定义 小分配器_重新分配(al, p, size) 小分配器_重分配_impl(&al, p, size)
#定义 小分配器_调试_参数
#否则
#定义 小分配器_调试 1
#定义 小分配器_释放(al, p) 小分配器_释放_impl(al, p, __FILE__, __LINE__)
#定义 小分配器_重新分配(al, p, size) 小分配器_重分配_impl(&al, p, size, __FILE__, __LINE__)
#定义 小分配器_调试_参数 , 常量 字符型 *file, 整数型 line
#定义 小分配器_调试_文件_长度 40
#结束如果

#定义 单词字符_小分配器_大小     (768 * 1024) /* 表_识别中微小TokenSym的分配器 */
#定义 单词字符串_小分配器_大小     (768 * 1024) /* 微小TokenString实例的分配器 */
#定义 动态字符串_小分配器_大小       (256 * 1024) /* 小型CString实例的分配器。没有使用 */
#定义 单词字符_小分配器_限制    256 /* 倾向于使用唯一的限制来区分分配器调试消息 */
#定义 单词字符串_小分配器_限制    128 /* 32 * 取大小(整数型) */
#定义 动态字符串_小分配器_限制      1024
类型定义 结构体 微内存分配 {
    无符号  limit;
    无符号  size;
    uint8_t *buffer;
    uint8_t *p;
    无符号  数量_allocs;
    结构体 微内存分配 *next, *top;
#如果已定义 小分配器_信息
    无符号  数量_peak;
    无符号  数量_total;
    无符号  数量_missed;
    uint8_t *peak_p;
#结束如果
} 微内存分配;

类型定义 结构体 小分配器_header_t {
    无符号  size;
#如果已定义 小分配器_调试
    整数型     line_num; /* 拒绝line_num用于双重释放检查 */
    字符型    file_name[小分配器_调试_文件_长度 + 1];
#结束如果
} 小分配器_header_t;

/* ------------------------------------------------------------------------- */

静态 微内存分配 *小分配器_新建(微内存分配 **pal, 无符号 limit, 无符号 size)
{
    微内存分配 *al = 内存_初始化(取大小(微内存分配));
    al->p = al->buffer = 内存_申请(size);
    al->limit = limit;
    al->size = size;
    如果 (pal) *pal = al;
    返回 al;
}

静态 无类型 小分配器_删除(微内存分配 *al)
{
    微内存分配 *next;

tail_call:
    如果 (!al)
        返回;
#如果已定义 小分配器_信息
    fprintf(stderr, "limit=%5d, size=%5g MB, 数量_peak=%6d, 数量_total=%8d, 数量_missed=%6d, usage=%5.1f%%\n",
            al->limit, al->size / 1024.0 / 1024.0, al->数量_peak, al->数量_total, al->数量_missed,
            (al->peak_p - al->buffer) * 100.0 / al->size);
#结束如果
#如果已定义 小分配器_调试
    如果 (al->数量_allocs > 0) {
        uint8_t *p;
        fprintf(stderr, "小分配器_调试: 内存泄漏 %d 个数据块 (限制= %d)\n",
                al->数量_allocs, al->limit);
        p = al->buffer;
        判断 (p < al->p) {
            小分配器_header_t *header = (小分配器_header_t *)p;
            如果 (header->line_num > 0) {
                fprintf(stderr, "%s:%d:  %d 个字节的块泄漏\n",
                        header->file_name, header->line_num, header->size);
            }
            p += header->size + 取大小(小分配器_header_t);
        }
#如果 内存_调试-0 == 2
        exit(2);
#结束如果
    }
#结束如果
    next = al->next;
    内存_释放(al->buffer);
    内存_释放(al);
    al = next;
    去向 tail_call;
}

静态 无类型 小分配器_释放_impl(微内存分配 *al, 无类型 *p 小分配器_调试_参数)
{
    如果 (!p)
        返回;
tail_call:
    如果 (al->buffer <= (uint8_t *)p && (uint8_t *)p < al->buffer + al->size) {
#如果已定义 小分配器_调试
        小分配器_header_t *header = (((小分配器_header_t *)p) - 1);
        如果 (header->line_num < 0) {
            fprintf(stderr, "%s:%d: 小分配器_调试: 双重释放块\n",
                    file, line);
            fprintf(stderr, "%s:%d: %d 个字节\n",
                    header->file_name, (整数型)-header->line_num, (整数型)header->size);
        } 否则
            header->line_num = -header->line_num;
#结束如果
        al->数量_allocs--;
        如果 (!al->数量_allocs)
            al->p = al->buffer;
    } 否则 如果 (al->next) {
        al = al->next;
        去向 tail_call;
    }
    否则
        内存_释放(p);
}

静态 无类型 *小分配器_重分配_impl(微内存分配 **pal, 无类型 *p, 无符号 size 小分配器_调试_参数)
{
    小分配器_header_t *header;
    无类型 *ret;
    整数型 is_own;
    无符号 adj_size = (size + 3) & -4;
    微内存分配 *al = *pal;

tail_call:
    is_own = (al->buffer <= (uint8_t *)p && (uint8_t *)p < al->buffer + al->size);
    如果 ((!p || is_own) && size <= al->limit) {
        如果 (al->p - al->buffer + adj_size + 取大小(小分配器_header_t) < al->size) {
            header = (小分配器_header_t *)al->p;
            header->size = adj_size;
#如果已定义 小分配器_调试
            { 整数型 ofs = strlen(file) - 小分配器_调试_文件_长度;
            strncpy(header->file_name, file + (ofs > 0 ? ofs : 0), 小分配器_调试_文件_长度);
            header->file_name[小分配器_调试_文件_长度] = 0;
            header->line_num = line; }
#结束如果
            ret = al->p + 取大小(小分配器_header_t);
            al->p += adj_size + 取大小(小分配器_header_t);
            如果 (is_own) {
                header = (((小分配器_header_t *)p) - 1);
                如果 (p) memcpy(ret, p, header->size);
#如果已定义 小分配器_调试
                header->line_num = -header->line_num;
#结束如果
            } 否则 {
                al->数量_allocs++;
            }
#如果已定义 小分配器_信息
            如果 (al->数量_peak < al->数量_allocs)
                al->数量_peak = al->数量_allocs;
            如果 (al->peak_p < al->p)
                al->peak_p = al->p;
            al->数量_total++;
#结束如果
            返回 ret;
        } 否则 如果 (is_own) {
            al->数量_allocs--;
            ret = 小分配器_重新分配(*pal, 0, size);
            header = (((小分配器_header_t *)p) - 1);
            如果 (p) memcpy(ret, p, header->size);
#如果已定义 小分配器_调试
            header->line_num = -header->line_num;
#结束如果
            返回 ret;
        }
        如果 (al->next) {
            al = al->next;
        } 否则 {
            微内存分配 *bottom = al, *next = al->top ? al->top : al;

            al = 小分配器_新建(pal, next->limit, next->size * 2);
            al->next = next;
            bottom->top = al;
        }
        去向 tail_call;
    }
    如果 (is_own) {
        al->数量_allocs--;
        ret = 内存_申请(size);
        header = (((小分配器_header_t *)p) - 1);
        如果 (p) memcpy(ret, p, header->size);
#如果已定义 小分配器_调试
        header->line_num = -header->line_num;
#结束如果
    } 否则 如果 (al->next) {
        al = al->next;
        去向 tail_call;
    } 否则
        ret = 内存_重分配容量(p, size);
#如果已定义 小分配器_信息
    al->数量_missed++;
#结束如果
    返回 ret;
}

#结束如果 /* 小对象_分配器 */

/* ------------------------------------------------------------------------- */
静态 无类型 动态字符串_重分配内存(动态字符串 *cstr, 整数型 字符串新长度)
{
    整数型 size;

    size = cstr->缓冲区长度;
    如果 (size < 8)
        size = 8;
    判断 (size < 字符串新长度)
        size = size * 2;
    cstr->指向字符串的指针 = 内存_重分配容量(cstr->指向字符串的指针, size);
    cstr->缓冲区长度 = size;
}

静态_内联 无类型 动态字符串_追加单个字符(动态字符串 *cstr, 整数型 当前取到的源码字符)
{
    整数型 size;
    size = cstr->字符串长度 + 1;
    如果 (size > cstr->缓冲区长度)
        动态字符串_重分配内存(cstr, size);
    ((无符号 字符型 *)cstr->指向字符串的指针)[size - 1] = 当前取到的源码字符;
    cstr->字符串长度 = size;
}

静态_函数 无类型 动态字符串_cat(动态字符串 *cstr, 常量 字符型 *str, 整数型 len)
{
    整数型 size;
    如果 (len <= 0)
        len = strlen(str) + 1 + len;
    size = cstr->字符串长度 + len;
    如果 (size > cstr->缓冲区长度)
        动态字符串_重分配内存(cstr, size);
    memmove(((无符号 字符型 *)cstr->指向字符串的指针) + cstr->字符串长度, str, len);
    cstr->字符串长度 = size;
}

/* 增加一个宽字符 */
静态_函数 无类型 动态字符串_追加一个宽字符(动态字符串 *cstr, 整数型 当前取到的源码字符)
{
    整数型 size;
    size = cstr->字符串长度 + 取大小(nwchar_t);
    如果 (size > cstr->缓冲区长度)
        动态字符串_重分配内存(cstr, size);
    *(nwchar_t *)(((无符号 字符型 *)cstr->指向字符串的指针) + size - 取大小(nwchar_t)) = 当前取到的源码字符;
    cstr->字符串长度 = size;
}
静态_函数 无类型 动态字符串_初始化(动态字符串 *cstr)
{
	/*memset(无类型 *s, 整数型 c, 无符号 long n);函数的功能是:将指针变量 s 所指向的前 n 字节的内存单元用一个“整数” c 替换,注意 c 是 整数型 型。s 是 无类型* 型的指针变量,所以它可以为任何类型的数据进行初始化。*/
    memset(cstr, 0, 取大小(动态字符串));
}

静态_函数 无类型 动态字符串_释放(动态字符串 *cstr)
{
    内存_释放(cstr->指向字符串的指针);
    动态字符串_初始化(cstr);
}

/* 将字符串重置为空 */
静态_函数 无类型 动态字符串_重置(动态字符串 *cstr)
{
    cstr->字符串长度 = 0;
}

静态_函数 整数型 动态字符串_打印(动态字符串 *cstr, 常量 字符型 *fmt, ...)
{
    va_list v;
    整数型 len, size;
/*在运行VA_START(va_list ap, last_arg)以后,ap指向第一个可变参数在堆栈的地址。
 * last_arg 是最后一个传递给函数的已知的固定参数,即省略号之前的参数。
 */
    va_start(v, fmt);
    len = vsnprintf(NULL, 0, fmt, v);
    va_end(v);
    size = cstr->字符串长度 + len + 1;
    如果 (size > cstr->缓冲区长度)
        动态字符串_重分配内存(cstr, size);
    va_start(v, fmt);
    vsnprintf((字符型*)cstr->指向字符串的指针 + cstr->字符串长度, size, fmt, v);
    va_end(v);
    cstr->字符串长度 += len;
    返回 len;
}

/* XXX: 统一码 ? */
静态 无类型 添加_字符(动态字符串 *cstr, 整数型 c)
{
    如果 (c == '\'' || c == '\"' || c == '\\') {
        /* XXX: 如果使用char或string可能更精确 */
        动态字符串_追加单个字符(cstr, '\\');
    }
    如果 (c >= 32 && c <= 126) {
        动态字符串_追加单个字符(cstr, c);
    } 否则 {
        动态字符串_追加单个字符(cstr, '\\');
        如果 (c == '\n') {
            动态字符串_追加单个字符(cstr, 'n');
        } 否则 {
            动态字符串_追加单个字符(cstr, '0' + ((c >> 6) & 7));
            动态字符串_追加单个字符(cstr, '0' + ((c >> 3) & 7));
            动态字符串_追加单个字符(cstr, '0' + (c & 7));
        }
    }
}

/* ------------------------------------------------------------------------- */
/* 分配新标识*/
静态 单词存储结构 *标识符_分配新内存(单词存储结构 **pts, 常量 字符型 *str, 整数型 len)
{
    单词存储结构 *ts, **ptable;
    整数型 i;

    如果 (单词_识别号 >= 符号_第一个_匿名) 
        错误_打印("内存已满(符号)");

    /* 必要的时候可以扩展标识符表 */
    i = 单词_识别号 - 符_识别;
    如果 ((i % 符_分配_INCR) == 0) {
        ptable = 内存_重分配容量(单词表, (i + 符_分配_INCR) * 取大小(单词存储结构 *));
        单词表 = ptable;
    }

    ts = 小分配器_重新分配(单词字符_分配内存, 0, 取大小(单词存储结构) + len);
    单词表[i] = ts;
    ts->单词编码 = 单词_识别号++;
    ts->sym_define = NULL;
    ts->sym_label = NULL;
    ts->sym_struct = NULL;
    ts->sym_identifier = NULL;
    ts->len = len;
    ts->hash_next = NULL;
    memcpy(ts->str, str, len);
    ts->str[len] = '\0';
    *pts = ts;
    返回 ts;
}

#定义 符_哈希_初始化 1
#定义 符_哈希_函数(h, c) ((h) + ((h) << 5) + ((h) >> 27) + (c))
/*单词表中查找单词_如不存在就添加它*/
静态_函数 单词存储结构 *单词表_查找(常量 字符型 *str, 整数型 len)
{
    单词存储结构 *单词存储结构, **pts;
    整数型 i;
    无符号 整数型 h;
    
    h = 符_哈希_初始化;
    循环(i=0;i<len;i++)
        h = 符_哈希_函数(h, ((无符号 字符型 *)str)[i]);
    h &= (哈希表容量 - 1);

    pts = &单词_哈希表[h];
    循环(;;) {
    	单词存储结构 = *pts;
        如果 (!单词存储结构)
            跳出;
        如果 (单词存储结构->len == len && !memcmp(单词存储结构->str, str, len))
            返回 单词存储结构;
        pts = &(单词存储结构->hash_next);
    }
    返回 标识符_分配新内存(pts, str, len);
}
静态_函数 常量 字符型 *取_单词字符串(整数型 v, 恒定值 *cv)
{
    字符型 *p;
    整数型 i, len;

    动态字符串_重置(&动态字符串_缓冲);
    p = 动态字符串_缓冲.指向字符串的指针;

    选择(v) {
    分支 常量_整数:
    分支 常量_无符整数:
    分支 常量_长整数:
    分支 常量_无符长整数:
    分支 常量_长长整数:
    分支 常量_无符长长整数:
        /* XXX: 不太精确,但仅对测试有用  */
#如果已定义 _WIN32
        sprintf(p, "%u", (无符号)cv->i);
#否则
        sprintf(p, "%llu", (无符号 long long)cv->i);
#结束如果
        跳出;
    分支 常量_长字符型:
        动态字符串_追加单个字符(&动态字符串_缓冲, 'L');
    分支 常量_字符型:
        动态字符串_追加单个字符(&动态字符串_缓冲, '\'');
        添加_字符(&动态字符串_缓冲, cv->i);
        动态字符串_追加单个字符(&动态字符串_缓冲, '\'');
        动态字符串_追加单个字符(&动态字符串_缓冲, '\0');
        跳出;
    分支 常量_预处理编号:
    分支 常量_预处理字符串:
        返回 (字符型*)cv->str.data;
    分支 常量_长字符串:
        动态字符串_追加单个字符(&动态字符串_缓冲, 'L');
    分支 常量_字符串:
        动态字符串_追加单个字符(&动态字符串_缓冲, '\"');
        如果 (v == 常量_字符串) {
            len = cv->str.size - 1;
            循环(i=0;i<len;i++)
                添加_字符(&动态字符串_缓冲, ((无符号 字符型 *)cv->str.data)[i]);
        } 否则 {
            len = (cv->str.size / 取大小(nwchar_t)) - 1;
            循环(i=0;i<len;i++)
                添加_字符(&动态字符串_缓冲, ((nwchar_t *)cv->str.data)[i]);
        }
        动态字符串_追加单个字符(&动态字符串_缓冲, '\"');
        动态字符串_追加单个字符(&动态字符串_缓冲, '\0');
        跳出;

    分支 常量_浮点型:
        动态字符串_cat(&动态字符串_缓冲, "<float>", 0);
        跳出;
    分支 常量_双精度:
	动态字符串_cat(&动态字符串_缓冲, "<double>", 0);
	跳出;
    分支 常量_长双精度:
	动态字符串_cat(&动态字符串_缓冲, "<long double>", 0);
	跳出;
    分支 常量_行号:
	动态字符串_cat(&动态字符串_缓冲, "<linenumber>", 0);
	跳出;

    /* 上面的标识符具有价值,下面的标识符没有价值 */
    分支 符_LT:
        v = '<';
        去向 addv;
    分支 符_GT:
        v = '>';
        去向 addv;
    分支 符_三个圆点:
        返回 strcpy(p, "...");
    分支 符_A_SHL:
        返回 strcpy(p, "<<=");
    分支 符_A_SAR:
        返回 strcpy(p, ">>=");
    分支 符_文件结尾:
        返回 strcpy(p, "<eof>");
    default:
        如果 (v < 符_识别) {
            /* search in two bytes table */
            常量 无符号 字符型 *q = 双字符符号;
            判断 (*q) {
                如果 (q[2] == v) {
                    *p++ = q[0];
                    *p++ = q[1];
                    *p = '\0';
                    返回 动态字符串_缓冲.指向字符串的指针;
                }
                q += 3;
            }
        如果 (v >= 127) {
            sprintf(动态字符串_缓冲.指向字符串的指针, "<%02x>", v);
            返回 动态字符串_缓冲.指向字符串的指针;
        }
        addv:
            *p++ = v;
            *p = '\0';
        } 否则 如果 (v < 单词_识别号) {
            返回 单词表[v - 符_识别]->str;
        } 否则 如果 (v >= 符号_第一个_匿名) {
            /* 匿名符号的特殊名称 */
            sprintf(p, "L.%u", v - 符号_第一个_匿名);
        } 否则 {
            /* 不应该发生 */
            返回 NULL;
        }
        跳出;
    }
    返回 动态字符串_缓冲.指向字符串的指针;
}

/* 返回当前字符,必要时处理块的结尾 */
静态 整数型 处理_块的结尾(无类型)
{
    缓冲文件 *bf = file;
    整数型 len;

    /* 仅在缓冲区真正结束时尝试读取 */
    如果 (bf->buf_ptr >= bf->buf_end) {
        如果 (bf->fd >= 0) {
#如果 已定义(PARSE_DEBUG)
            len = 1;
#否则
            len = 输入输出_缓冲_大小;
#结束如果
            len = read(bf->fd, bf->buffer, len);
            如果 (len < 0)
                len = 0;
        } 否则 {
            len = 0;
        }
        总_字节数 += len;
        bf->buf_ptr = bf->buffer;
        bf->buf_end = bf->buffer + len;
        *bf->buf_end = CH_缓冲区结尾;
    }
    如果 (bf->buf_ptr < bf->buf_end) {
        返回 bf->buf_ptr[0];
    } 否则 {
        bf->buf_ptr = bf->buf_end;
        返回 CH_文件结尾;
    }
}

静态 内联 无类型 读下个符号处理缓冲区结尾(无类型)
{
    当前取到的源码字符 = *(++(file->buf_ptr));
    /* 缓冲区/文件处理结束 */
    如果 (当前取到的源码字符 == CH_缓冲区结尾)
        当前取到的源码字符 = 处理_块的结尾();
}

/* 处理 '\[\r]\n' */
静态 整数型 处理_转义_无错误(无类型)
{
    判断 (当前取到的源码字符 == '\\') {
        读下个符号处理缓冲区结尾();
        如果 (当前取到的源码字符 == '\n') {
            file->line_num++;
            读下个符号处理缓冲区结尾();
        } 否则 如果 (当前取到的源码字符 == '\r') {
            读下个符号处理缓冲区结尾();
            如果 (当前取到的源码字符 != '\n')
                去向 fail;
            file->line_num++;
            读下个符号处理缓冲区结尾();
        } 否则 {
        fail:
            返回 1;
        }
    }
    返回 0;
}
/**/
静态 无类型 处理_转义(无类型)
{
    如果 (处理_转义_无错误())
        错误_打印("程序中转义 '\\' ");
}

/* 跳过转义符,处理\\ n。 如果输出错误
    转义后不正确的字符 */
静态 整数型 处理_转义1(uint8_t *p)
{
    整数型 c;

    file->buf_ptr = p;
    如果 (p >= file->buf_end) {
        c = 处理_块的结尾();
        如果 (c != '\\')
            返回 c;
        p = file->buf_ptr;
    }
    当前取到的源码字符 = *p;
    如果 (处理_转义_无错误()) {
        如果 (!(解析_标记 & 解析_标记_接受_转义))
            错误_打印("程序中转义 '\\' ");
        *--file->buf_ptr = '\\';
    }
    p = file->buf_ptr;
    c = *p;
    返回 c;
}

/* 仅处理EOB情况,但不能处理转义 */
#定义 仅处理模块结尾_不处理转义(c, p)\
{\
    p++;\
    c = *p;\
    如果 (c == '\\') {\
        file->buf_ptr = p;\
        c = 处理_块的结尾();\
        p = file->buf_ptr;\
    }\
}

/* 处理复杂的转义情况*/
#定义 复杂转义(c, p)\
{\
    p++;\
    c = *p;\
    如果 (c == '\\') {\
        c = 处理_转义1(p);\
        p = file->buf_ptr;\
    }\
}

/* 输入以'\ [\ r] \ n'处理。 请注意,此函数无法处理'\'之后的其他字符,因此您不能在字符串或注释中调用它 */
静态 无类型 仅处理第一个斜杠(无类型)
{
    读下个符号处理缓冲区结尾();
    如果 (当前取到的源码字符 == '\\') 
        处理_转义();
}

/* 单行C ++注释 */
静态 uint8_t *解析_单行_注释(uint8_t *p)
{
    整数型 c;

    p++;
    循环(;;) {
        c = *p;
    redo:
        如果 (c == '\n' || c == CH_文件结尾) {
            跳出;
        } 否则 如果 (c == '\\') {
            file->buf_ptr = p;
            c = 处理_块的结尾();
            p = file->buf_ptr;
            如果 (c == '\\') {
                仅处理模块结尾_不处理转义(c, p);
                如果 (c == '\n') {
                    file->line_num++;
                    仅处理模块结尾_不处理转义(c, p);
                } 否则 如果 (c == '\r') {
                    仅处理模块结尾_不处理转义(c, p);
                    如果 (c == '\n') {
                        file->line_num++;
                        仅处理模块结尾_不处理转义(c, p);
                    }
                }
            } 否则 {
                去向 redo;
            }
        } 否则 {
            p++;
        }
    }
    返回 p;
}

/* C 注释(解释,注释) */
静态 uint8_t *解析_注释(uint8_t *p)
{
    整数型 c;

    p++;
    循环(;;) {
        /* 快速跳过循环 */
        循环(;;) {
            c = *p;
            如果 (c == '\n' || c == '*' || c == '\\')
                跳出;
            p++;
            c = *p;
            如果 (c == '\n' || c == '*' || c == '\\')
                跳出;
            p++;
        }
        /* 现在我们可以处理所有情况 */
        如果 (c == '\n') {
            file->line_num++;
            p++;
        } 否则 如果 (c == '*') {
            p++;
            循环(;;) {
                c = *p;
                如果 (c == '*') {
                    p++;
                } 否则 如果 (c == '/') {
                    去向 end_of_comment;
                } 否则 如果 (c == '\\') {
                    file->buf_ptr = p;
                    c = 处理_块的结尾();
                    p = file->buf_ptr;
                    如果 (c == CH_文件结尾)
                        错误_打印("注释中的文件意外结束");
                    如果 (c == '\\') {
                        /* 跳过 '\[\r]\n', otherwise just 跳过 the stray */
                        判断 (c == '\\') {
                            仅处理模块结尾_不处理转义(c, p);
                            如果 (c == '\n') {
                                file->line_num++;
                                仅处理模块结尾_不处理转义(c, p);
                            } 否则 如果 (c == '\r') {
                                仅处理模块结尾_不处理转义(c, p);
                                如果 (c == '\n') {
                                    file->line_num++;
                                    仅处理模块结尾_不处理转义(c, p);
                                }
                            } 否则 {
                                去向 after_star;
                            }
                        }
                    }
                } 否则 {
                    跳出;
                }
            }
        after_star: ;
        } 否则 {
            /* stray, eob or eof */
            file->buf_ptr = p;
            c = 处理_块的结尾();
            p = file->buf_ptr;
            如果 (c == CH_文件结尾) {
                错误_打印("注释中的文件意外结束");
            } 否则 如果 (c == '\\') {
                p++;
            }
        }
    }
 end_of_comment:
    p++;
    返回 p;
}

静态_函数 整数型 设置_等值数(整数型 c, 整数型 val)
{
    整数型 prev = 等值_表[c - CH_文件结尾];
    等值_表[c - CH_文件结尾] = val;
    返回 prev;
}

#定义 cinp 仅处理第一个斜杠

静态 内联 无类型 跳过_空格(无类型)
{
    判断 (等值_表[当前取到的源码字符 - CH_文件结尾] & IS_SPC)
        cinp();
}

静态 内联 整数型 检查_空格(整数型 t, 整数型 *spc)
{
    如果 (t < 256 && (等值_表[t - CH_文件结尾] & IS_SPC)) {
        如果 (*spc) 
            返回 1;
        *spc = 1;
    } 否则 
        *spc = 0;
    返回 0;
}

静态 uint8_t *解析字符串_不解析转义(uint8_t *p,整数型 sep, 动态字符串 *str)
{
    整数型 c;
    p++;
    循环(;;) {
        c = *p;
        如果 (c == sep) {
            跳出;
        } 否则 如果 (c == '\\') {
            file->buf_ptr = p;
            c = 处理_块的结尾();
            p = file->buf_ptr;
            如果 (c == CH_文件结尾) {
            unterminated_string:
                /* XXX: 指示字符串开头的行号 */
                错误_打印("缺少终止符 %c ", sep);
            } 否则 如果 (c == '\\') {
                /* escape : just 跳过 \[\r]\n */
                仅处理模块结尾_不处理转义(c, p);
                如果 (c == '\n') {
                    file->line_num++;
                    p++;
                } 否则 如果 (c == '\r') {
                    仅处理模块结尾_不处理转义(c, p);
                    如果 (c != '\n')
                        应为("'\n' after '\r'");
                    file->line_num++;
                    p++;
                } 否则 如果 (c == CH_文件结尾) {
                    去向 unterminated_string;
                } 否则 {
                    如果 (str) {
                        动态字符串_追加单个字符(str, '\\');
                        动态字符串_追加单个字符(str, c);
                    }
                    p++;
                }
            }
        } 否则 如果 (c == '\n') {
            file->line_num++;
            去向 添加_字符;
        } 否则 如果 (c == '\r') {
            仅处理模块结尾_不处理转义(c, p);
            如果 (c != '\n') {
                如果 (str)
                    动态字符串_追加单个字符(str, '\r');
            } 否则 {
                file->line_num++;
                去向 添加_字符;
            }
        } 否则 {
        添加_字符:
            如果 (str)
                动态字符串_追加单个字符(str, c);
            p++;
        }
    }
    p++;
    返回 p;
}

/* 跳过预处理。_预处理(预处理)。跳过#否则,#elif或#结束如果。 也跳过
    #如果 /#结束如果 */
静态 无类型 跳过_预处理(无类型)
{
    整数型 a, start_of_line, c, in_warn_or_error;
    uint8_t *p;

    p = file->buf_ptr;
    a = 0;
redo_start:
    start_of_line = 1;
    in_warn_or_error = 0;
    循环(;;) {
    redo_no_start:
        c = *p;
        选择(c) {
        分支 ' ':
        分支 '\t':
        分支 '\f':
        分支 '\v':
        分支 '\r':
            p++;
            去向 redo_no_start;
        分支 '\n':
            file->line_num++;
            p++;
            去向 redo_start;
        分支 '\\':
            file->buf_ptr = p;
            c = 处理_块的结尾();
            如果 (c == CH_文件结尾) {
                应为("#结束如果");
            } 否则 如果 (c == '\\') {
                当前取到的源码字符 = file->buf_ptr[0];
                处理_转义_无错误();
            }
            p = file->buf_ptr;
            去向 redo_no_start;
        /* 跳过字符串 */
        分支 '\"':
        分支 '\'':
            如果 (in_warn_or_error)
                去向 _default;
            p = 解析字符串_不解析转义(p, c, NULL);
            跳出;
        /* 跳过注释 */
        分支 '/':
            如果 (in_warn_or_error)
                去向 _default;
            file->buf_ptr = p;
            当前取到的源码字符 = *p;
            仅处理第一个斜杠();
            p = file->buf_ptr;
            如果 (当前取到的源码字符 == '*') {
                p = 解析_注释(p);
            } 否则 如果 (当前取到的源码字符 == '/') {
                p = 解析_单行_注释(p);
            }
            跳出;
        分支 '#':
            p++;
            如果 (start_of_line) {
                file->buf_ptr = p;
                取_下个符号_不宏扩展();
                p = file->buf_ptr;
                如果 (a == 0 && (单词编码 == 关键字_ELSE || 单词编码 == 关键字_否则 || 单词编码 == 关键字_ELIF || 单词编码 == 关键字_否则如果 || 单词编码 == 关键字_ENDIF || 单词编码 == 关键字_结束如果))
                    去向 the_end;
                如果 (单词编码 == 关键字_IF || 单词编码 == 关键字_如果 || 单词编码 == 关键字_IFDEF || 单词编码 == 关键字_如果已定义 || 单词编码 == 关键字_IFNDEF || 单词编码 == 关键字_如果未定义)
                    a++;
                否则 如果 (单词编码 == 关键字_ENDIF || 单词编码 == 关键字_结束如果)
                    a--;
                否则 如果( 单词编码 == 关键字_ERROR || 单词编码 == 关键字_错误  || 单词编码 == 关键字_WARNING || 单词编码 == 关键字_警告)
                    in_warn_or_error = 1;
                否则 如果 (单词编码 == 符_换行)
                    去向 redo_start;
                否则 如果 (解析_标记 & 解析_标记_汇编_文件)
                    p = 解析_单行_注释(p - 1);
            } 否则 如果 (解析_标记 & 解析_标记_汇编_文件)
                p = 解析_单行_注释(p - 1);
            跳出;
_default:
        default:
            p++;
            跳出;
        }
        start_of_line = 0;
    }
 the_end: ;
    file->buf_ptr = p;
}

#如果 0
/* 返回存储标识符所需的其他“ 整数型”数 。次函数没有被使用*/
静态 内联 整数型 标识符_大小(常量 整数型 *p)
{
    选择(*p) {
        /* 4 字节 */
    分支 常量_整数:
    分支 常量_无符整数:
    分支 常量_字符型:
    分支 常量_长字符型:
    分支 常量_浮点型:
    分支 常量_行号:
        返回 1 + 1;
    分支 常量_字符串:
    分支 常量_长字符串:
    分支 常量_预处理编号:
    分支 常量_预处理字符串:
        返回 1 + ((取大小(动态字符串) + ((动态字符串 *)(p+1))->size + 3) >> 2);
    分支 常量_长整数:
    分支 常量_无符长整数:
	返回 1 + LONG_SIZE / 4;
    分支 常量_双精度:
    分支 常量_长长整数:
    分支 常量_无符长长整数:
        返回 1 + 2;
    分支 常量_长双精度:
        返回 1 + 长双精度_大小 / 4;
    default:
        返回 1 + 0;
    }
}
#结束如果
静态_内联 无类型 单词字符串_处理(单词字符串 *s)
{
    s->str = NULL;
    s->len = s->lastlen = 0;
    s->allocated_len = 0;
    s->最后_行_号 = -1;
}

静态_函数 单词字符串 *单词字符串_分配(无类型)
{
    单词字符串 *str = 小分配器_重新分配(单词字符串_分配内存, 0, 取大小 *str);
    单词字符串_处理(str);
    返回 str;
}

静态_函数 整数型 *单词字符串_复制到新内存地址(单词字符串 *s)
{
    整数型 *str;

    str = 小分配器_重新分配(单词字符串_分配内存, 0, s->len * 取大小(整数型));
    memcpy(str, s->str, s->len * 取大小(整数型));
    返回 str;
}

静态_函数 无类型 单词字符串_释放_字符串(整数型 *str)
{
    小分配器_释放(单词字符串_分配内存, str);
}

静态_函数 无类型 单词字符串_释放(单词字符串 *str)
{
    单词字符串_释放_字符串(str->str);
    小分配器_释放(单词字符串_分配内存, str);
}

静态_函数 整数型 *单词字符串_重分配(单词字符串 *s, 整数型 new_size)
{
    整数型 *str, size;

    size = s->allocated_len;
    如果 (size < 16)
        size = 16;
    判断 (size < new_size)
        size = size * 2;
    如果 (size > s->allocated_len) {
        str = 小分配器_重新分配(单词字符串_分配内存, s->str, size * 取大小(整数型));
        s->allocated_len = size;
        s->str = str;
    }
    返回 s->str;
}

静态_函数 无类型 单词字符串_增加大小(单词字符串 *s, 整数型 t)
{
    整数型 len, *str;

    len = s->len;
    str = s->str;
    如果 (len >= s->allocated_len)
        str = 单词字符串_重分配(s, len + 1);
    str[len++] = t;
    s->len = len;
}

静态_函数 无类型 开始_宏(单词字符串 *str, 整数型 alloc)
{
    str->alloc = alloc;
    str->prev = 宏_堆栈;
    str->prev_ptr = 宏_ptr;
    str->save_line_num = file->line_num;
    宏_ptr = str->str;
    宏_堆栈 = str;
}

静态_函数 无类型 结束_宏(无类型)
{
    单词字符串 *str = 宏_堆栈;
    宏_堆栈 = str->prev;
    宏_ptr = str->prev_ptr;
    file->line_num = str->save_line_num;
    如果 (str->alloc != 0) {
        如果 (str->alloc == 2)
            str->str = NULL; /* 不释放 */
        单词字符串_释放(str);
    }
}

静态 无类型 单词字符串_增加大小2(单词字符串 *s, 整数型 t, 恒定值 *cv)
{
    整数型 len, *str;

    len = s->lastlen = s->len;
    str = s->str;

    /* allocate space 循环 worst 分支 */
    如果 (len + 符_最大_大小 >= s->allocated_len)
        str = 单词字符串_重分配(s, len + 符_最大_大小 + 1);
    str[len++] = t;
    选择(t) {
    分支 常量_整数:
    分支 常量_无符整数:
    分支 常量_字符型:
    分支 常量_长字符型:
    分支 常量_浮点型:
    分支 常量_行号:
#如果 LONG_SIZE == 4
    分支 常量_长整数:
    分支 常量_无符长整数:
#结束如果
        str[len++] = cv->tab[0];
        跳出;
    分支 常量_预处理编号:
    分支 常量_预处理字符串:
    分支 常量_字符串:
    分支 常量_长字符串:
        {
            /* 将字符串插入int数组. */
            size_t 数量_words =
                1 + (cv->str.size + 取大小(整数型) - 1) / 取大小(整数型);
            如果 (len + 数量_words >= s->allocated_len)
                str = 单词字符串_重分配(s, len + 数量_words + 1);
            str[len] = cv->str.size;
            memcpy(&str[len + 1], cv->str.data, cv->str.size);
            len += 数量_words;
        }
        跳出;
    分支 常量_双精度:
    分支 常量_长长整数:
    分支 常量_无符长长整数:
#如果 LONG_SIZE == 8
    分支 常量_长整数:
    分支 常量_无符长整数:
#结束如果
#如果 长双精度_大小 == 8
    分支 常量_长双精度:
#结束如果
        str[len++] = cv->tab[0];
        str[len++] = cv->tab[1];
        跳出;
#如果 长双精度_大小 == 12
    分支 常量_长双精度:
        str[len++] = cv->tab[0];
        str[len++] = cv->tab[1];
        str[len++] = cv->tab[2];
#否则如果 长双精度_大小 == 16
    分支 常量_长双精度:
        str[len++] = cv->tab[0];
        str[len++] = cv->tab[1];
        str[len++] = cv->tab[2];
        str[len++] = cv->tab[3];
#否则如果 长双精度_大小 != 8
#error add long double size support
#结束如果
        跳出;
    default:
        跳出;
    }
    s->len = len;
}

/* 在单词字符串“ *s”中添加当前的解析字符 */
静态_函数 无类型 单词字符串中添加当前解析的字符(单词字符串 *s)
{
    恒定值 cval;

    /* 保存行号信息 */
    如果 (file->line_num != s->最后_行_号) {
        s->最后_行_号 = file->line_num;
        cval.i = s->最后_行_号;
        单词字符串_增加大小2(s, 常量_行号, &cval);
    }
    单词字符串_增加大小2(s, 单词编码, &单词值);
}

/* 从整数数组和增量指针获取标识符. */
静态 内联 无类型 获取_标识符(整数型 *t, 常量 整数型 **pp, 恒定值 *cv)
{
    常量 整数型 *p = *pp;
    整数型 n, *tab;

    tab = cv->tab;
    选择(*t = *p++) {
#如果 LONG_SIZE == 4
    分支 常量_长整数:
#结束如果
    分支 常量_整数:
    分支 常量_字符型:
    分支 常量_长字符型:
    分支 常量_行号:
        cv->i = *p++;
        跳出;
#如果 LONG_SIZE == 4
    分支 常量_无符长整数:
#结束如果
    分支 常量_无符整数:
        cv->i = (无符号)*p++;
        跳出;
    分支 常量_浮点型:
	tab[0] = *p++;
	跳出;
    分支 常量_字符串:
    分支 常量_长字符串:
    分支 常量_预处理编号:
    分支 常量_预处理字符串:
        cv->str.size = *p++;
        cv->str.data = p;
        p += (cv->str.size + 取大小(整数型) - 1) / 取大小(整数型);
        跳出;
    分支 常量_双精度:
    分支 常量_长长整数:
    分支 常量_无符长长整数:
#如果 LONG_SIZE == 8
    分支 常量_长整数:
    分支 常量_无符长整数:
#结束如果
        n = 2;
        去向 copy;
    分支 常量_长双精度:
#如果 长双精度_大小 == 16
        n = 4;
#否则如果 长双精度_大小 == 12
        n = 3;
#否则如果 长双精度_大小 == 8
        n = 2;
#否则
# error add long double size support
#结束如果
    copy:
        执行
            *tab++ = *p++;
        判断 (--n);
        跳出;
    default:
        跳出;
    }
    *pp = p;
}

#如果 0
# 定义 符_GET(t,p,c) 获取_标识符(t,p,c)
#否则
# 定义 符_GET(t,p,c) 执行 { \
    整数型 _t = **(p); \
    如果 (符_有_值(_t)) \
        获取_标识符(t, p, c); \
    否则 \
        *(t) = _t, ++*(p); \
    } 判断 (0)
#结束如果

静态 整数型 宏_等于(常量 整数型 *a, 常量 整数型 *b)
{
    恒定值 cv;
    整数型 t;

    如果 (!a || !b)
        返回 1;

    判断 (*a && *b) {
        /* 第一次预分配macro_equal_buf,下次仅重置位置以开始 */
        动态字符串_重置(&宏_等于_缓冲区);_GET(&t, &a, &cv);
        动态字符串_cat(&宏_等于_缓冲区, 取_单词字符串(t, &cv), 0);_GET(&t, &b, &cv);
        如果 (strcmp(宏_等于_缓冲区.指向字符串的指针, 取_单词字符串(t, &cv)))
            返回 0;
    }
    返回 !(*a || *b);
}

/* 定义处理 */
静态_内联 无类型 宏定义_处理(整数型 v, 整数型 macro_type, 整数型 *str, 符号 *first_arg)
{
    符号 *s, *o;

    o = 宏定义_查找(v);
    s = 符号_推送2(&宏定义符号_堆栈, v, macro_type, 0);
    s->d = str;
    s->next = first_arg;
    单词表[v - 符_识别]->sym_define = s;

    如果 (o && !宏_等于(o->d, s->d))
	zhi_警告("%s 重复定义", 取_单词字符串(v, NULL));
}

/* 没有被定义的定义符号,它的名称仅能设置为零 */
静态_函数 无类型 未宏定义_符号为NULL(符号 *s)
{
    整数型 v = s->v;
    如果 (v >= 符_识别 && v < 单词_识别号)
        单词表[v - 符_识别]->sym_define = NULL;
}

静态_内联 符号 *宏定义_查找(整数型 v)
{
    v -= 符_识别;
    如果 ((无符号)v >= (无符号)(单词_识别号 - 符_识别))
        返回 NULL;
    返回 单词表[v]->sym_define;
}

/* 释放定义堆栈,直到顶部达到“ b” */
静态_函数 无类型 释放_宏定义堆栈(符号 *b)
{
    判断 (宏定义符号_堆栈 != b) {
        符号 *top = 宏定义符号_堆栈;
        宏定义符号_堆栈 = top->prev;
        单词字符串_释放_字符串(top->d);
        未宏定义_符号为NULL(top);
        符号_释放(top);
    }
}

/* 标签查找 */
静态_函数 符号 *标签_查找(整数型 v)
{
    v -= 符_识别;
    如果 ((无符号)v >= (无符号)(单词_识别号 - 符_识别))
        返回 NULL;
    返回 单词表[v]->sym_label;
}

静态_函数 符号 *标签_推送(符号 **ptop, 整数型 v, 整数型 flags)
{
    符号 *s, **ps;
    s = 符号_推送2(ptop, v, 0, 0);
    s->r = flags;
    ps = &单词表[v - 符_识别]->sym_label;
    如果 (ptop == &全局符号_标签_堆栈) {
        /* 修改最上面的本地标识符,以便在弹出时sym_identifier指向“ s” */
        判断 (*ps != NULL)
            ps = &(*ps)->prev_tok;
    }
    s->prev_tok = *ps;
    *ps = s;
    返回 s;
}

/* 弹出标签,直到到达元素的最后一个。 查看是否有未定义的标签。 如果使用'&& label',请定义符号. */
静态_函数 无类型 标签_弹出(符号 **ptop, 符号 *slast, 整数型 keep)
{
    符号 *s, *1;
    循环(s = *ptop; s != slast; s =1) {1 = s->prev;
        如果 (s->r == 标签_被声明) {
            zhi_警告("标签 '%s' 已声明但未使用", 取_单词字符串(s->v, NULL));
        } 否则 如果 (s->r == 标签_正向定义) {
                错误_打印("标签 '%s' 被使用但未定义",
                      取_单词字符串(s->v, NULL));
        } 否则 {
            如果 (s->c) {
                /* 定义相应的符号。 尺寸为1. */
                更新_外部_符号(s, 当前_生成代码_段, s->jnext, 1);
            }
        }
        /* remove label */
        如果 (s->r != 标签_不在范围)
            单词表[s->v - 符_识别]->sym_label = s->prev_tok;
        如果 (!keep)
            符号_释放(s);
        否则
            s->r = 标签_不在范围;
    }
    如果 (!keep)
        *ptop = slast;
}

/* 为zhi -dt -run伪造第n个“ #ifdefined test _...” */
静态 无类型 可能_运行_测试(知心状态机 *s)
{
    常量 字符型 *p;
    如果 (s->包含_堆_ptr != s->包含_堆)
        返回;
    p = 取_单词字符串(单词编码, NULL);
    如果 (0 != memcmp(p, "test_", 5))
        返回;
    如果 (0 != --s->运行_测试)
        返回;
    fprintf(s->预处理输出文件, "\n[%s]\n" + !(s->DX标号 & 32), p), fflush(s->预处理输出文件);
    宏定义_处理(单词编码, 宏_对象, NULL, NULL);
}

/* 评估#如果 /#elif的表达式 */
静态 整数型 预处理_表达式(无类型)
{
    整数型 c, t;
    单词字符串 *str;
    
    str = 单词字符串_分配();
    词法分析_表达式 = 1;
    判断 (单词编码 != 符_换行 && 单词编码 != 符_文件结尾) {
        带有宏替换的下个标记(); /* 做宏替换 */
      redo:
        如果 (单词编码 == 关键字_DEFINED || 单词编码 == 关键字_已定义) {
            取_下个符号_不宏扩展();
            t = 单词编码;
            如果 (t == '(') 
                取_下个符号_不宏扩展();
            如果 (单词编码 < 符_识别)
                应为("identifier");
            如果 (zhi_状态->运行_测试)
                可能_运行_测试(zhi_状态);
            c = 宏定义_查找(单词编码) != 0;
            如果 (t == '(') {
                取_下个符号_不宏扩展();
                如果 (单词编码 != ')')
                    应为("')'");
            }
            单词编码 = 常量_整数;
            单词值.i = c;
        } 否则 如果 (1 && 单词编码 == 符___HAS_INCLUDE) {
            带有宏替换的下个标记();  /* XXX 检查是否正确使用扩展 */
            跳过('(');
            判断 (单词编码 != ')' && 单词编码 != 符_文件结尾)
              带有宏替换的下个标记();
            如果 (单词编码 != ')')
              应为("')'");
            单词编码 = 常量_整数;
            单词值.i = 0;
        } 否则 如果 (单词编码 >= 符_识别) {
            /* 如果未定义宏,则替换为零,检查类似func的宏 */
            t = 单词编码;
            单词编码 = 常量_整数;
            单词值.i = 0;
            单词字符串中添加当前解析的字符(str);
            带有宏替换的下个标记();
            如果 (单词编码 == '(')
                错误_打印("未定义类似函数的宏 '%s' ",
                          取_单词字符串(t, NULL));
            去向 redo;
        }
        单词字符串中添加当前解析的字符(str);
    }
    词法分析_表达式 = 0;
    单词字符串_增加大小(str, -1); /* 模拟文件结尾 */
    单词字符串_增加大小(str, 0);
    /* 现在评估C常数表达式 */
    开始_宏(str, 1);
    带有宏替换的下个标记();
    c = 表达式_常量();
    结束_宏();
    返回 c != 0;
}


/* #define之后解析 */
静态_函数 无类型 解析_宏定义(无类型)
{
    符号 *s, *first, **ps;
    整数型 v, t, varg, is_vaargs, spc;
    整数型 saved_解析_标记 = 解析_标记;

    v = 单词编码;
    如果 (v < 符_识别 || v == 关键字_DEFINED || v == 关键字_已定义)
        错误_打印("无效的宏名称 '%s'", 取_单词字符串(单词编码, &单词值));
    /* XXX: 应该检查是否有相同的宏(ANSI) */
    first = NULL;
    t = 宏_对象;
    /* 我们必须解析整个定义,好像不是在asm模式下一样,尤其是必须忽略带有'#'的行注释。 同样对于函数宏,参数列表也必须不带“。”进行分析。 作为ID字符.  */
    解析_标记 = ((解析_标记 & ~解析_标记_汇编_文件) | 解析_标记_空间);
    /* '(' 必须紧随MACRO_FUNC的宏定义之后 */
    取_下个符号_不宏扩展();
    解析_标记 &= ~解析_标记_空间;
    如果 (单词编码 == '(') {
        整数型 dotid = 设置_等值数('.', 0);
        取_下个符号_不宏扩展();
        ps = &first;
        如果 (单词编码 != ')') 循环 (;;) {
            varg = 单词编码;
            取_下个符号_不宏扩展();
            is_vaargs = 0;
            如果 (varg == 符_三个圆点) {
                varg = 符___VA_ARGS__;
                is_vaargs = 1;
            } 否则 如果 (单词编码 == 符_三个圆点 && gnu_扩展) {
                is_vaargs = 1;
                取_下个符号_不宏扩展();
            }
            如果 (varg < 符_识别)
        bad_list:
                错误_打印("错误的宏参数列表");
            s = 符号_推送2(&宏定义符号_堆栈, varg | 符号_字段, is_vaargs, 0);
            *ps = s;
            ps = &s->next;
            如果 (单词编码 == ')')
                跳出;
            如果 (单词编码 != ',' || is_vaargs)
                去向 bad_list;
            取_下个符号_不宏扩展();
        }
        解析_标记 |= 解析_标记_空间;
        取_下个符号_不宏扩展();
        t = 宏_函数;
        设置_等值数('.', dotid);
    }

    单词字符串_缓冲.len = 0;
    spc = 2;
    解析_标记 |= 解析_标记_接受_转义 | 解析_标记_空间 | 解析_标记_换行符;
    /* 应该对宏定义的主体进行解析,以便像文件模式确定的那样解析标识符(即在asm模式下以'。'为ID字符)。 但是应保留“#”而不是将其视为行注释的引号,因此仍不要在解析_标记中设置ASM_FILE。 */
    判断 (单词编码 != 符_换行 && 单词编码 != 符_文件结尾) {
        /* 删除##周围和'#'之后的空格 */
        如果 (双符号_2个井号 == 单词编码) {
            如果 (2 == spc)
                去向 bad_twosharp;
            如果 (1 == spc)
                --单词字符串_缓冲.len;
            spc = 3;
	    单词编码 = 符_PPJOIN;
        } 否则 如果 ('#' == 单词编码) {
            spc = 4;
        } 否则 如果 (检查_空格(单词编码, &spc)) {
            去向 跳过;
        }
        单词字符串_增加大小2(&单词字符串_缓冲, 单词编码, &单词值);
    跳过:
        取_下个符号_不宏扩展();
    }

    解析_标记 = saved_解析_标记;
    如果 (spc == 1)
        --单词字符串_缓冲.len; /* 删除尾随空间 */
    单词字符串_增加大小(&单词字符串_缓冲, 0);
    如果 (3 == spc)
bad_twosharp:
        错误_打印("'##' 不能出现在宏的任何一端");
    宏定义_处理(v, t, 单词字符串_复制到新内存地址(&单词字符串_缓冲), first);
}

静态 导入文件缓存 *查找_缓存的_导入文件(知心状态机 *状态机1, 常量 字符型 *文件名, 整数型 add)
{
    常量 无符号 字符型 *s;
    无符号 整数型 h;
    导入文件缓存 *e;
    整数型 i;

    h = 符_哈希_初始化;
    s = (无符号 字符型 *) 文件名;
    判断 (*s) {
#如果已定义 _WIN32
        h = 符_哈希_函数(h, toup(*s));
#否则
        h = 符_哈希_函数(h, *s);
#结束如果
        s++;
    }
    h &= (缓存的_导入文件_哈希_大小 - 1);

    i = 状态机1->缓存_包含数_哈希[h];
    循环(;;) {
        如果 (i == 0)
            跳出;
        e = 状态机1->缓存_包含数[i - 1];
        如果 (0 == PATHCMP(e->文件名, 文件名))
            返回 e;
        i = e->hash_next;
    }
    如果 (!add)
        返回 NULL;

    e = 内存_申请(取大小(导入文件缓存) + strlen(文件名));
    strcpy(e->文件名, 文件名);
    e->ifndef_macro = e->once = 0;
    动态数组_追加元素(&状态机1->缓存_包含数, &状态机1->数量_缓存_包含数, e);
    /* 在哈希表中添加 */
    e->hash_next = 状态机1->缓存_包含数_哈希[h];
    状态机1->缓存_包含数_哈希[h] = 状态机1->数量_缓存_包含数;
#如果已定义 导入文件_调试
    printf("添加缓存的 '%s'\n", 文件名);
#结束如果
    返回 e;
}

静态 无类型 语用_解析(知心状态机 *1)
{
    取_下个符号_不宏扩展();
    如果 (单词编码 == 符_push_macro || 单词编码 == 符_pop_macro) {
        整数型 t = 单词编码, v;
        符号 *s;

        如果 (带有宏替换的下个标记(), 单词编码 != '(')
            去向 pragma_err;
        如果 (带有宏替换的下个标记(), 单词编码 != 常量_字符串)
            去向 pragma_err;
        v = 单词表_查找(单词值.str.data, 单词值.str.size - 1)->单词编码;
        如果 (带有宏替换的下个标记(), 单词编码 != ')')
            去向 pragma_err;
        如果 (t == 符_push_macro) {
            判断 (NULL == (s = 宏定义_查找(v)))
                宏定义_处理(v, 0, NULL, NULL);
            s->type.ref = s; /* 设置推送边界 */
        } 否则 {
            循环 (s = 宏定义符号_堆栈; s; s = s->prev)
                如果 (s->v == v && s->type.ref == s) {
                    s->type.ref = NULL;
                    跳出;
                }
        }
        如果 (s)
            单词表[v - 符_识别]->sym_define = s->d ? s : NULL;
        否则
            zhi_警告("不平衡的 #pragma pop_macro");
        词法分析_调试_标识符 = t, 词法分析_调试_字符值 = v;

    } 否则 如果 (单词编码 == 符_once) {
        查找_缓存的_导入文件(1, file->文件名, 1)->once = 词法分析_第一次;

    } 否则 如果 (1->输出_类型 == ZHI_输出_预处理) {
        /* zhi -E:保持语用表保持不变 */
        设为_指定标识符(' ');
        设为_指定标识符(关键字_PRAGMA);
        设为_指定标识符('#');
        设为_指定标识符(符_换行);

    } 否则 如果 (单词编码 == 符_pack) {
        带有宏替换的下个标记();
        跳过('(');
        如果 (单词编码 == 符_汇编_pop) {
            带有宏替换的下个标记();
            如果 (1->包_堆_ptr <=1->包_堆) {
            stk_error:
                错误_打印("超出了堆包");
            }1->包_堆_ptr--;
        } 否则 {
            整数型 val = 0;
            如果 (单词编码 != ')') {
                如果 (单词编码 == 符_汇编_push) {
                    带有宏替换的下个标记();
                    如果 (1->包_堆_ptr >=1->包_堆 + 包_堆栈_大小 - 1)
                        去向 stk_error;1->包_堆_ptr++;
                    跳过(',');
                }
                如果 (单词编码 != 常量_整数)
                    去向 pragma_err;
                val = 单词值.i;
                如果 (val < 1 || val > 16 || (val & (val - 1)) != 0)
                    去向 pragma_err;
                带有宏替换的下个标记();
            }
            *1->包_堆_ptr = val;
        }
        如果 (单词编码 != ')')
            去向 pragma_err;

    } 否则 如果 (单词编码 == 符_comment) {
        字符型 *p; 整数型 t;
        带有宏替换的下个标记();
        跳过('(');
        t = 单词编码;
        带有宏替换的下个标记();
        跳过(',');
        如果 (单词编码 != 常量_字符串)
            去向 pragma_err;
        p = 字符串_宽度加1((字符型 *)单词值.str.data);
        带有宏替换的下个标记();
        如果 (单词编码 != ')')
            去向 pragma_err;
        如果 (t == 符_lib) {
            动态数组_追加元素(&1->语法_库数, &1->数量_语法_库数, p);
        } 否则 {
            如果 (t == 符_option)
                设置编译选项(1, p);
            内存_释放(p);
        }

    } 否则 如果 (1->警告_不支持) {
        zhi_警告("#pragma %s 被忽略", 取_单词字符串(单词编码, &单词值));
    }
    返回;

pragma_err:
    错误_打印(" #pragma 指令格式错误");
    返回;
}

/* 如果文件开头的第一个非空间标识符,则is_bof为true */
静态_函数 无类型 _预处理(整数型 is_bof)
{
    知心状态机 *1 = zhi_状态;
    整数型 i, c, n, saved_解析_标记;
    字符型 buf[1024], *q;
    符号 *s;

    saved_解析_标记 = 解析_标记;
    解析_标记 = 解析_标记_预处理| 解析_标记_标识符_数字| 解析_标记_单词字符串| 解析_标记_换行符| (解析_标记 & 解析_标记_汇编_文件);

    取_下个符号_不宏扩展();
 redo:
    选择(单词编码) {
    分支 关键字_DEFINE:
    分支 关键字_定义:
        词法分析_调试_标识符 = 单词编码;
        取_下个符号_不宏扩展();
        词法分析_调试_字符值 = 单词编码;
        解析_宏定义();
        跳出;
    分支 关键字_UNDEF:
    分支 关键字_取消定义:
        词法分析_调试_标识符 = 单词编码;
        取_下个符号_不宏扩展();
        词法分析_调试_字符值 = 单词编码;
        s = 宏定义_查找(单词编码);
        /* 通过输入无效名称来定义符号 */
        如果 (s)
            未宏定义_符号为NULL(s);
        跳出;
    分支 关键字_INCLUDE:
    分支 关键字_导入:
    分支 关键字_INCLUDE_NEXT:
    分支 关键字_导入_下个:
        当前取到的源码字符 = file->buf_ptr[0];
        /* XXX: 如果注释不正确:以特殊模式使用next_nomacro */
        跳过_空格();
        如果 (当前取到的源码字符 == '<') {
            c = '>';
            去向 read_name;
        } 否则 如果 (当前取到的源码字符 == '\"') {
            c = 当前取到的源码字符;
        read_name:
            读下个符号处理缓冲区结尾();
            q = buf;
            判断 (当前取到的源码字符 != c && 当前取到的源码字符 != '\n' && 当前取到的源码字符 != CH_文件结尾) {
                如果 ((q - buf) < 取大小(buf) - 1)
                    *q++ = 当前取到的源码字符;
                如果 (当前取到的源码字符 == '\\') {
                    如果 (处理_转义_无错误() == 0)
                        --q;
                } 否则
                    读下个符号处理缓冲区结尾();
            }
            *q = '\0';
            仅处理第一个斜杠();
#如果 0
            /* 吃掉所有空格并在包含之后发表评论 */
            /* XXX: 稍微不正确 */
            判断 (ch1 != '\n' && ch1 != CH_文件结尾)
                读下个符号处理缓冲区结尾();
#结束如果
        } 否则 {
	    整数型 len;
            /* 计算出的#导入:将所有内容连接到换行符,结果必须是两种可接受的形式之一。请勿在此处将pp标识符转换为标识符。  */
	    解析_标记 = (解析_标记_预处理
			   | 解析_标记_换行符
			   | (解析_标记 & 解析_标记_汇编_文件));
            带有宏替换的下个标记();
            buf[0] = '\0';
	    判断 (单词编码 != 符_换行) {
		连接_字符串(buf, 取大小(buf), 取_单词字符串(单词编码, &单词值));
		带有宏替换的下个标记();
	    }
	    len = strlen(buf);
	    /* 检查语法并删除'<> |“”'*/
	    如果 ((len < 2 || ((buf[0] != '"' || buf[len-1] != '"') &&
			     (buf[0] != '<' || buf[len-1] != '>'))))
	        错误_打印("'#导入' 之后应该有 \"FILENAME\" 或 <FILENAME>");
	    c = buf[len-1];
	    memmove(buf, buf + 1, len - 2);
	    buf[len - 2] = '\0';
        }

        如果 (1->包含_堆_ptr >=1->包含_堆 + 包含_堆栈_大小)
            错误_打印("#include递归太深");
        /* 将当前文件推送到堆栈 */
        *1->包含_堆_ptr++ = file;
        i = (单词编码 == 关键字_INCLUDE_NEXT || 单词编码 == 关键字_导入_下个) ? file->include_next_index + 1 : 0;
        n = 2 +1->数量_包含_路径 +1->数量_系统包含_路径;
        循环 (; i < n; ++i) {
            字符型 buf1[取大小 file->文件名];
            导入文件缓存 *e;
            常量 字符型 *path;

            如果 (i == 0) {
                /* 检查绝对包含路径 */
                如果 (!IS_ABSPATH(buf))
                    继续;
                buf1[0] = 0;

            } 否则 如果 (i == 1) {
                /* 在文件的目录中搜索“ header.h” */
                如果 (c != '\"')
                    继续;
                /* https://savannah.nongnu.org/bugs/index.php?50847
                 * #line指令损坏了#include搜索路径
                 *  */
                path = file->true_filename;
                复制_字符串(buf1, path, 取_文件基本名(path) - path);

            } 否则 {
                /* 搜索所有包含路径 */
                整数型 j = i - 2, k = j -1->数量_包含_路径;
                path = k < 0 ?1->包含_路径[j] :1->系统包含_路径[k];
                p字符串复制(buf1, 取大小(buf1), path);
                连接_字符串(buf1, 取大小(buf1), "/");
            }

            连接_字符串(buf1, 取大小(buf1), buf);
            e = 查找_缓存的_导入文件(1, buf1, 0);
            如果 (e && (宏定义_查找(e->ifndef_macro) || e->once == 词法分析_第一次)) {
                /* 无需解析包含,因为已定义了“ ifndef宏”(或具有一次#pragma) */
#如果已定义 导入文件_调试
                printf("%s: 跳过缓存的 %s\n", file->文件名, buf1);
#结束如果
                去向 include_done;
            }

            如果 (打开一个新文件(1, buf1) < 0)
                继续;

            file->include_next_index = i;
#如果已定义 导入文件_调试
            printf("%s: 包含 %s\n", file->prev->文件名, file->文件名);
#结束如果
            /* 更新目标部门 */
            如果 (1->生成_依赖) {
                缓冲文件 *bf = file;
                判断 (i == 1 && (bf = bf->prev))
                    i = bf->include_next_index;
                /* 跳过系统导入文件 */
                如果 (n - i >1->数量_系统包含_路径)
                    动态数组_追加元素(&1->目标_依赖, &1->数量_目标_依赖,
                        字符串_宽度加1(buf1));
            }
            /* 添加导入文件调试信息 */
            zhi_调试_导入文件的开头(zhi_状态);
            标识符_标记 |= 符_标记_文件开始前 | 符_标记_行开始前;
            当前取到的源码字符 = file->buf_ptr[0];
            去向 the_end;
        }
        错误_打印("找不到导入文件 '%s' ", buf);
include_done:
        --1->包含_堆_ptr;
        跳出;
    分支 关键字_IFNDEF:
    分支 关键字_如果未定义:
        c = 1;
        去向 do_ifdef;
    分支 关键字_IF:
    分支 关键字_如果:
        c = 预处理_表达式();
        去向 do_if;
    分支 关键字_IFDEF:
    分支 关键字_如果已定义:
        c = 0;
    do_ifdef:
        取_下个符号_不宏扩展();
        如果 (单词编码 < 符_识别)
            错误_打印(" '#如果%sdef' 的无效参数", c ? "n" : "");
        如果 (is_bof) {
            如果 (c) {
#如果已定义 导入文件_调试
                printf("#如果未定义 %s\n", 取_单词字符串(单词编码, NULL));
#结束如果
                file->ifndef_macro = 单词编码;
            }
        }
        c = (宏定义_查找(单词编码) != 0) ^ c;
    do_if:
        如果 (1->如果已宏定义_堆_ptr >=1->如果已宏定义_堆 + 如果定义_堆栈_大小)
            错误_打印("内存已满(如果已定义)");
        *1->如果已宏定义_堆_ptr++ = c;
        去向 test_skip;
    分支 关键字_ELSE:
    分支 关键字_否则:
        如果 (1->如果已宏定义_堆_ptr ==1->如果已宏定义_堆)
            错误_打印("#else不匹配#如果");
        如果 (1->如果已宏定义_堆_ptr[-1] & 2)
            错误_打印("#else之后#否则");
        c = (1->如果已宏定义_堆_ptr[-1] ^= 3);
        去向 test_else;
    分支 关键字_ELIF:
    分支 关键字_否则如果:
        如果 (1->如果已宏定义_堆_ptr ==1->如果已宏定义_堆)
            错误_打印("#elif没有匹配的#如果");
        c =1->如果已宏定义_堆_ptr[-1];
        如果 (c > 1)
            错误_打印("#else之后#否则如果");
        /* 最后的#如果 /#elif表达式为true:我们跳过 */
        如果 (c == 1) {
            c = 0;
        } 否则 {
            c = 预处理_表达式();1->如果已宏定义_堆_ptr[-1] = c;
        }
    test_else:
        如果 (1->如果已宏定义_堆_ptr == file->如果已宏定义_堆_ptr + 1)
            file->ifndef_macro = 0;
    test_skip:
        如果 (!(c & 1)) {
            跳过_预处理();
            is_bof = 0;
            去向 redo;
        }
        跳出;
    分支 关键字_ENDIF:
    分支 关键字_结束如果:
        如果 (1->如果已宏定义_堆_ptr <= file->如果已宏定义_堆_ptr)
            错误_打印("#endif没有匹配的#如果");1->如果已宏定义_堆_ptr--;
        /* “ #ifndef宏”位于文件的开头。 现在,我们检查“ #结束如果”是否恰好在文件末尾 */
        如果 (file->ifndef_macro &&1->如果已宏定义_堆_ptr == file->如果已宏定义_堆_ptr) {
            file->ifndef_macro_saved = file->ifndef_macro;
            /* 如果文件中间还有另一个#如果未定义,则需要将其设置为零以避免错误的匹配 */
            file->ifndef_macro = 0;
            判断 (单词编码 != 符_换行)
                取_下个符号_不宏扩展();
            标识符_标记 |= 符_标记_结束如果;
            去向 the_end;
        }
        跳出;
    分支 常量_预处理编号:
        n = strtoul((字符型*)单词值.str.data, &q, 10);
        去向 _line_num;
    分支 关键字_LINE:
    分支 关键字_行号:
        带有宏替换的下个标记();
        如果 (单词编码 != 常量_整数)
    _line_err:
            错误_打印("错误的#line格式");
        n = 单词值.i;
    _line_num:
        带有宏替换的下个标记();
        如果 (单词编码 != 符_换行) {
            如果 (单词编码 == 常量_字符串) {
                如果 (file->true_filename == file->文件名)
                    file->true_filename = 字符串_宽度加1(file->文件名);
                /* 从真实文件添加目录 */
                p字符串复制(buf, 取大小 buf, file->true_filename);
                *取_文件基本名(buf) = 0;
                连接_字符串(buf, 取大小 buf, (字符型 *)单词值.str.data);
                zhi_调试_备用文件(1, buf);
            } 否则 如果 (解析_标记 & 解析_标记_汇编_文件)
                跳出;
            否则
                去向 _line_err;
            --n;
        }
        如果 (file->fd > 0)
            总_行数 += file->line_num - n;
        file->line_num = n;
        跳出;
    分支 关键字_ERROR:
    分支 关键字_错误:
    分支 关键字_WARNING:
    分支 关键字_警告:
        c = 单词编码;
        当前取到的源码字符 = file->buf_ptr[0];
        跳过_空格();
        q = buf;
        判断 (当前取到的源码字符 != '\n' && 当前取到的源码字符 != CH_文件结尾) {
            如果 ((q - buf) < 取大小(buf) - 1)
                *q++ = 当前取到的源码字符;
            如果 (当前取到的源码字符 == '\\') {
                如果 (处理_转义_无错误() == 0)
                    --q;
            } 否则
                读下个符号处理缓冲区结尾();
        }
        *q = '\0';
        如果 (c == 关键字_ERROR || c == 关键字_错误)
            错误_打印("#error %s", buf);
        否则
            zhi_警告("#warning %s", buf);
        跳出;
    分支 关键字_PRAGMA:
    分支 关键字_杂注:
        语用_解析(1);
        跳出;
    分支 符_换行:
        去向 the_end;
    default:
        /* 忽略“ S”文件中的天然气行注释。 */
        如果 (saved_解析_标记 & 解析_标记_汇编_文件)
            去向 ignore;
        如果 (单词编码 == '!' && is_bof)
            /*'!' 开始时会被忽略以允许使用C脚本。 */
            去向 ignore;
        zhi_警告("忽略未知的预处理指令 #%s", 取_单词字符串(单词编码, &单词值));
    ignore:
        file->buf_ptr = 解析_单行_注释(file->buf_ptr - 1);
        去向 the_end;
    }
    /* 忽略其他预处理命令或#! 对于C脚本 */
    判断 (单词编码 != 符_换行)
        取_下个符号_不宏扩展();
 the_end:
    解析_标记 = saved_解析_标记;
}

静态 无类型 解析_转义_字符串(动态字符串 *outstr, 常量 uint8_t *buf, 整数型 is_long)
{
    整数型 c, n;
    常量 uint8_t *p;

    p = buf;
    循环(;;) {
        c = *p;
        如果 (c == '\0')
            跳出;
        如果 (c == '\\') {
            p++;
            /* 逃逸 */
            c = *p;
            选择(c) {
            分支 '0': 分支 '1': 分支 '2': 分支 '3':
            分支 '4': 分支 '5': 分支 '6': 分支 '7':
                /* 最多三位八进制数字 */
                n = c - '0';
                p++;
                c = *p;
                如果 (isoct(c)) {
                    n = n * 8 + c - '0';
                    p++;
                    c = *p;
                    如果 (isoct(c)) {
                        n = n * 8 + c - '0';
                        p++;
                    }
                }
                c = n;
                去向 add_char_nonext;
            分支 'x':
            分支 'u':
            分支 'U':
                p++;
                n = 0;
                循环(;;) {
                    c = *p;
                    如果 (c >= 'a' && c <= 'f')
                        c = c - 'a' + 10;
                    否则 如果 (c >= 'A' && c <= 'F')
                        c = c - 'A' + 10;
                    否则 如果 (是数字(c))
                        c = c - '0';
                    否则
                        跳出;
                    n = n * 16 + c;
                    p++;
                }
                c = n;
                去向 add_char_nonext;
            分支 'a':
                c = '\a';
                跳出;
            分支 'b':
                c = '\b';
                跳出;
            分支 'f':
                c = '\f';
                跳出;
            分支 'n':
                c = '\n';
                跳出;
            分支 'r':
                c = '\r';
                跳出;
            分支 't':
                c = '\t';
                跳出;
            分支 'v':
                c = '\v';
                跳出;
            分支 'e':
                如果 (!gnu_扩展)
                    去向 invalid_escape;
                c = 27;
                跳出;
            分支 '\'':
            分支 '\"':
            分支 '\\': 
            分支 '?':
                跳出;
            default:
            invalid_escape:
                如果 (c >= '!' && c <= '~')
                    zhi_警告("未知的转义序列: \'\\%c\'", c);
                否则
                    zhi_警告("未知的转义序列: \'\\x%x\'", c);
                跳出;
            }
        } 否则 如果 (is_long && c >= 0x80) {
            /* 假设我们正在处理UTF-8序列 */
            /* 参考:Unicode标准,版本10.0,ch3.9 */

            整数型 cont; /* 连续字节数 */
            整数型 跳过; /* 发生错误时应跳过多少个字节 */
            整数型 i;

            /* 解码前导字节 */
            如果 (c < 0xC2) {
	            跳过 = 1; 去向 invalid_utf8_sequence;
            } 否则 如果 (c <= 0xDF) {
	            cont = 1; n = c & 0x1f;
            } 否则 如果 (c <= 0xEF) {
	            cont = 2; n = c & 0xf;
            } 否则 如果 (c <= 0xF4) {
	            cont = 3; n = c & 0x7;
            } 否则 {
	            跳过 = 1; 去向 invalid_utf8_sequence;
            }

            /* 解码连续字节 */
            循环 (i = 1; i <= cont; i++) {
                整数型 l = 0x80, h = 0xBF;

                /* 调整第二个字节的限制 */
                如果 (i == 1) {
                    选择 (c) {
                    分支 0xE0: l = 0xA0; 跳出;
                    分支 0xED: h = 0x9F; 跳出;
                    分支 0xF0: l = 0x90; 跳出;
                    分支 0xF4: h = 0x8F; 跳出;
                    }
                }

                如果 (p[i] < l || p[i] > h) {
                    跳过 = i; 去向 invalid_utf8_sequence;
                }

                n = (n << 6) | (p[i] & 0x3f);
            }

            /* 前进指针 */
            p += 1 + cont;
            c = n;
            去向 add_char_nonext;

            /* 错误处理 */
        invalid_utf8_sequence:
            zhi_警告("格式错误的UTF-8子序列,开头为: \'\\x%x\'", c);
            c = 0xFFFD;
            p += 跳过;
            去向 add_char_nonext;

        }
        p++;
    add_char_nonext:
        如果 (!is_long)
            动态字符串_追加单个字符(outstr, c);
        否则 {
#如果已定义 ZHI_TARGET_PE
            /* 存储为UTF-16 */
            如果 (c < 0x10000) {
                动态字符串_追加一个宽字符(outstr, c);
            } 否则 {
                c -= 0x10000;
                动态字符串_追加一个宽字符(outstr, (c >> 10) + 0xD800);
                动态字符串_追加一个宽字符(outstr, (c & 0x3FF) + 0xDC00);
            }
#否则
            动态字符串_追加一个宽字符(outstr, c);
#结束如果
        }
    }
    /* 添加结尾 '\0' */
    如果 (!is_long)
        动态字符串_追加单个字符(outstr, '\0');
    否则
        动态字符串_追加一个宽字符(outstr, '\0');
}

静态 无类型 解析_字符串(常量 字符型 *s, 整数型 len)
{
    uint8_t buf[1000], *p = buf;
    整数型 is_long, sep;

    如果 ((is_long = *s == 'L'))
        ++s, --len;
    sep = *s++;
    len -= 2;
    如果 (len >= 取大小 buf)
        p = 内存_申请(len + 1);
    memcpy(p, s, len);
    p[len] = 0;

    动态字符串_重置(&当前单词字符串);
    解析_转义_字符串(&当前单词字符串, p, is_long);
    如果 (p != buf)
        内存_释放(p);

    如果 (sep == '\'') {
        整数型 char_size, i, n, c;
        /* XXX: 使其便携 */
        如果 (!is_long)
            单词编码 = 常量_字符型, char_size = 1;
        否则
            单词编码 = 常量_长字符型, char_size = 取大小(nwchar_t);
        n = 当前单词字符串.字符串长度 / char_size - 1;
        如果 (n < 1)
            错误_打印("空字符常量");
        如果 (n > 1)
            zhi_警告("多字符常量");
        循环 (c = i = 0; i < n; ++i) {
            如果 (is_long)
                c = ((nwchar_t *)当前单词字符串.指向字符串的指针)[i];
            否则
                c = (c << 8) | ((字符型 *)当前单词字符串.指向字符串的指针)[i];
        }
        单词值.i = c;
    } 否则 {
        单词值.str.size = 当前单词字符串.字符串长度;
        单词值.str.data = 当前单词字符串.指向字符串的指针;
        如果 (!is_long)
            单词编码 = 常量_字符串;
        否则
            单词编码 = 常量_长字符串;
    }
}

/* 我们使用64位数字 */
#定义 BN_SIZE 2
静态 无类型 bn_lshift(无符号 整数型 *bn, 整数型 shift, 整数型 or_val)
{
    整数型 i;
    无符号 整数型 v;
    循环(i=0;i<BN_SIZE;i++)
    {
        v = bn[i];
        bn[i] = (v << shift) | or_val;
        or_val = v >> (32 - shift);
    }
}

静态 无类型 bn_零(无符号 整数型 *bn)
{
    整数型 i;
    循环(i=0;i<BN_SIZE;i++) {
        bn[i] = 0;
    }
}

/* 解析空终止字符串'p'中的数字,并以当前标识符返回 */
静态 无类型 解析_数字(常量 字符型 *p)
{
    整数型 b, t, shift, frac_bits, s, exp_val, 当前取到的源码字符;
    字符型 *q;
    无符号 整数型 bn[BN_SIZE];
    double d;

    /* number */
    q = 标识符_缓冲;
    当前取到的源码字符 = *p++;
    t = 当前取到的源码字符;
    当前取到的源码字符 = *p++;
    *q++ = t;
    b = 10;
    如果 (t == '.') {
        去向 float_frac_parse;
    } 否则 如果 (t == '0') {
        如果 (当前取到的源码字符 == 'x' || 当前取到的源码字符 == 'X') {
            q--;
            当前取到的源码字符 = *p++;
            b = 16;
        } 否则 如果 (zhi_状态->zhi_扩展 && (当前取到的源码字符 == 'b' || 当前取到的源码字符 == 'B')) {
            q--;
            当前取到的源码字符 = *p++;
            b = 2;
        }
    }
    /* 解析所有数字。 由于浮点常量,目前无法检查八进制数 */
    判断 (1) {
        如果 (当前取到的源码字符 >= 'a' && 当前取到的源码字符 <= 'f')
            t = 当前取到的源码字符 - 'a' + 10;
        否则 如果 (当前取到的源码字符 >= 'A' && 当前取到的源码字符 <= 'F')
            t = 当前取到的源码字符 - 'A' + 10;
        否则 如果 (是数字(当前取到的源码字符))
            t = 当前取到的源码字符 - '0';
        否则
            跳出;
        如果 (t >= b)
            跳出;
        如果 (q >= 标识符_缓冲 + 字符串_最大_长度) {
        num_too_long:
            错误_打印("数字太长");
        }
        *q++ = 当前取到的源码字符;
        当前取到的源码字符 = *p++;
    }
    如果 (当前取到的源码字符 == '.' ||
        ((当前取到的源码字符 == 'e' || 当前取到的源码字符 == 'E') && b == 10) ||
        ((当前取到的源码字符 == 'p' || 当前取到的源码字符 == 'P') && (b == 16 || b == 2))) {
        如果 (b != 10) {
            /* 注意:strtox应该支持十六进制数字,但是非ISOC99 libcs不支持它,因此我们更愿意手工完成 */
            /* 十六进制或二进制浮点数 */
            /* XXX: 处理溢出 */
            *q = '\0';
            如果 (b == 16)
                shift = 4;
            否则 
                shift = 1;
            bn_零(bn);
            q = 标识符_缓冲;
            判断 (1) {
                t = *q++;
                如果 (t == '\0') {
                    跳出;
                } 否则 如果 (t >= 'a') {
                    t = t - 'a' + 10;
                } 否则 如果 (t >= 'A') {
                    t = t - 'A' + 10;
                } 否则 {
                    t = t - '0';
                }
                bn_lshift(bn, shift, t);
            }
            frac_bits = 0;
            如果 (当前取到的源码字符 == '.') {
                当前取到的源码字符 = *p++;
                判断 (1) {
                    t = 当前取到的源码字符;
                    如果 (t >= 'a' && t <= 'f') {
                        t = t - 'a' + 10;
                    } 否则 如果 (t >= 'A' && t <= 'F') {
                        t = t - 'A' + 10;
                    } 否则 如果 (t >= '0' && t <= '9') {
                        t = t - '0';
                    } 否则 {
                        跳出;
                    }
                    如果 (t >= b)
                        错误_打印("无效数字");
                    bn_lshift(bn, shift, t);
                    frac_bits += shift;
                    当前取到的源码字符 = *p++;
                }
            }
            如果 (当前取到的源码字符 != 'p' && 当前取到的源码字符 != 'P')
                应为("指数");
            当前取到的源码字符 = *p++;
            s = 1;
            exp_val = 0;
            如果 (当前取到的源码字符 == '+') {
                当前取到的源码字符 = *p++;
            } 否则 如果 (当前取到的源码字符 == '-') {
                s = -1;
                当前取到的源码字符 = *p++;
            }
            如果 (当前取到的源码字符 < '0' || 当前取到的源码字符 > '9')
                应为("指数位数");
            判断 (当前取到的源码字符 >= '0' && 当前取到的源码字符 <= '9') {
                exp_val = exp_val * 10 + 当前取到的源码字符 - '0';
                当前取到的源码字符 = *p++;
            }
            exp_val = exp_val * s;
            
            /* 现在我们可以生成数字 */
            /* XXX: 应直接修补浮点数 */
            d = (double)bn[1] * 4294967296.0 + (double)bn[0];
            d = ldexp(d, exp_val - frac_bits);
            t = toup(当前取到的源码字符);
            如果 (t == 'F') {
                当前取到的源码字符 = *p++;
                单词编码 = 常量_浮点型;
                /* float:应该处理溢出 */
                单词值.f = (float)d;
            } 否则 如果 (t == 'L') {
                当前取到的源码字符 = *p++;
#如果已定义 ZHI_TARGET_PE
                单词编码 = 常量_双精度;
                单词值.d = d;
#否则
                单词编码 = 常量_长双精度;
                /* XXX: 不够大 */
                单词值.ld = (long double)d;
#结束如果
            } 否则 {
                单词编码 = 常量_双精度;
                单词值.d = d;
            }
        } 否则 {
            /* 十进制浮点数 */
            如果 (当前取到的源码字符 == '.') {
                如果 (q >= 标识符_缓冲 + 字符串_最大_长度)
                    去向 num_too_long;
                *q++ = 当前取到的源码字符;
                当前取到的源码字符 = *p++;
            float_frac_parse:
                判断 (当前取到的源码字符 >= '0' && 当前取到的源码字符 <= '9') {
                    如果 (q >= 标识符_缓冲 + 字符串_最大_长度)
                        去向 num_too_long;
                    *q++ = 当前取到的源码字符;
                    当前取到的源码字符 = *p++;
                }
            }
            如果 (当前取到的源码字符 == 'e' || 当前取到的源码字符 == 'E') {
                如果 (q >= 标识符_缓冲 + 字符串_最大_长度)
                    去向 num_too_long;
                *q++ = 当前取到的源码字符;
                当前取到的源码字符 = *p++;
                如果 (当前取到的源码字符 == '-' || 当前取到的源码字符 == '+') {
                    如果 (q >= 标识符_缓冲 + 字符串_最大_长度)
                        去向 num_too_long;
                    *q++ = 当前取到的源码字符;
                    当前取到的源码字符 = *p++;
                }
                如果 (当前取到的源码字符 < '0' || 当前取到的源码字符 > '9')
                    应为("指数位数");
                判断 (当前取到的源码字符 >= '0' && 当前取到的源码字符 <= '9') {
                    如果 (q >= 标识符_缓冲 + 字符串_最大_长度)
                        去向 num_too_long;
                    *q++ = 当前取到的源码字符;
                    当前取到的源码字符 = *p++;
                }
            }
            *q = '\0';
            t = toup(当前取到的源码字符);
            errno = 0;
            如果 (t == 'F') {
                当前取到的源码字符 = *p++;
                单词编码 = 常量_浮点型;
                单词值.f = strtof(标识符_缓冲, NULL);
            } 否则 如果 (t == 'L') {
                当前取到的源码字符 = *p++;
#如果已定义 ZHI_TARGET_PE
                单词编码 = 常量_双精度;
                单词值.d = strtod(标识符_缓冲, NULL);
#否则
                单词编码 = 常量_长双精度;
                单词值.ld = strtold(标识符_缓冲, NULL);
#结束如果
            } 否则 {
                单词编码 = 常量_双精度;
                单词值.d = strtod(标识符_缓冲, NULL);
            }
        }
    } 否则 {
        无符号 long long n, n1;
        整数型 lcount, ucount, ov = 0;
        常量 字符型 *p1;

        /* 整数 */
        *q = '\0';
        q = 标识符_缓冲;
        如果 (b == 10 && *q == '0') {
            b = 8;
            q++;
        }
        n = 0;
        判断(1) {
            t = *q++;
            /* 除基数为10/8的错误外,无需检查 */
            如果 (t == '\0')
                跳出;
            否则 如果 (t >= 'a')
                t = t - 'a' + 10;
            否则 如果 (t >= 'A')
                t = t - 'A' + 10;
            否则
                t = t - '0';
            如果 (t >= b)
                错误_打印("无效数字");
            n1 = n;
            n = n * b + t;
            /* 检测溢出 */
            如果 (n1 >= 0x1000000000000000ULL && n / b != n1)
                ov = 1;
        }

        /* 根据常量后缀确定常量类型必须具有的特征(无符号和/或64位) */
        lcount = ucount = 0;
        p1 = p;
        循环(;;) {
            t = toup(当前取到的源码字符);
            如果 (t == 'L') {
                如果 (lcount >= 2)
                    错误_打印("整数常量中的三个 'l'");
                如果 (lcount && *(p - 1) != 当前取到的源码字符)
                    错误_打印("不正确的整数后缀: %s", p1);
                lcount++;
                当前取到的源码字符 = *p++;
            } 否则 如果 (t == 'U') {
                如果 (ucount >= 1)
                    错误_打印("整数常量中的两个 'u'");
                ucount++;
                当前取到的源码字符 = *p++;
            } 否则 {
                跳出;
            }
        }

        /* 确定是否需要64位和/或无符号才能适合 */
        如果 (ucount == 0 && b == 10) {
            如果 (lcount <= (LONG_SIZE == 4)) {
                如果 (n >= 0x80000000U)
                    lcount = (LONG_SIZE == 4) + 1;
            }
            如果 (n >= 0x8000000000000000ULL)
                ov = 1, ucount = 1;
        } 否则 {
            如果 (lcount <= (LONG_SIZE == 4)) {
                如果 (n >= 0x100000000ULL)
                    lcount = (LONG_SIZE == 4) + 1;
                否则 如果 (n >= 0x80000000U)
                    ucount = 1;
            }
            如果 (n >= 0x8000000000000000ULL)
                ucount = 1;
        }

        如果 (ov)
            zhi_警告("整数常量溢出");

        单词编码 = 常量_整数;
	如果 (lcount) {
            单词编码 = 常量_长整数;
            如果 (lcount == 2)
                单词编码 = 常量_长长整数;
	}
	如果 (ucount)
	    ++单词编码; /* 符_CU... */
        单词值.i = n;
    }
    如果 (当前取到的源码字符)
        错误_打印("无效号码\n");
}


#定义 PARSE2(c1, tok1, c2, tok2)              \
    分支 c1:                                    \
        复杂转义(c, p);                            \
        如果 (c == c2) {                          \
            p++;                                \
            单词编码 = tok2;                         \
        } 否则 {                                \
            单词编码 = tok1;                         \
        }                                       \
        跳出;

/* 返回下一个标识符而不进行宏替换 */
静态 内联 无类型 取_下个符号_不宏扩展1(无类型)
{
    整数型 t, c, is_long, len;
    单词存储结构 *ts;
    uint8_t *p, *p1;
    无符号 整数型 h;

    p = file->buf_ptr;
 redo_no_start:
    c = *p;
    选择(c) {
    分支 ' ':
    分支 '\t':
        单词编码 = c;
        p++;
 maybe_space:
        如果 (解析_标记 & 解析_标记_空间)
            去向 keep_标识符_标记;
        判断 (等值_表[*p - CH_文件结尾] & IS_SPC)
            ++p;
        去向 redo_no_start;
    分支 '\f':
    分支 '\v':
    分支 '\r':
        p++;
        去向 redo_no_start;
    分支 '\\':
        /* 首先查看它是否实际上是缓冲区的结尾 */
        c = 处理_转义1(p);
        p = file->buf_ptr;
        如果 (c == '\\')
            去向 parse_simple;
        如果 (c != CH_文件结尾)
            去向 redo_no_start;
        {
            知心状态机 *状态机1 = zhi_状态;
            如果 ((解析_标记 & 解析_标记_换行符)&& !(标识符_标记 & 符_标记_文件结尾))
            {
                标识符_标记 |= 符_标记_文件结尾;
                单词编码 = 符_换行;
                去向 keep_标识符_标记;
            } 否则 如果 (!(解析_标记 & 解析_标记_预处理))
            {
                单词编码 = 符_文件结尾;
            } 否则 如果 (状态机1->如果已宏定义_堆_ptr != file->如果已宏定义_堆_ptr)
            {
                错误_打印("缺少 #结束如果");
            } 否则 如果 (状态机1->包含_堆_ptr == 状态机1->包含_堆)
            {
                /* 没有包括左:文件末尾. */
                单词编码 = 符_文件结尾;
            } 否则 {
                标识符_标记 &= ~符_标记_文件结尾;
                /* 弹出导入文件 */
                
                /* 在文件开始时测试先前的'#结束如果'是否在#ifdef之后 */
                如果 (标识符_标记 & 符_标记_结束如果)
                {
#如果已定义 导入文件_调试
                    printf("#结束如果 %s\n", 取_单词字符串(file->ifndef_macro_saved, NULL));
#结束如果
                    查找_缓存的_导入文件(状态机1, file->文件名, 1)
                        ->ifndef_macro = file->ifndef_macro_saved;
                    标识符_标记 &= ~符_标记_结束如果;
                }

                /* 添加导入文件调试信息的末尾 */
                zhi_调试_导入文件的结尾(zhi_状态);
                /* 弹出包含堆栈 */
                关闭文件();
                状态机1->包含_堆_ptr--;
                p = file->buf_ptr;
                如果 (p == file->buffer)
                    标识符_标记 = 符_标记_文件开始前|符_标记_行开始前;
                去向 redo_no_start;
            }
        }
        跳出;

    分支 '\n':
        file->line_num++;
        标识符_标记 |= 符_标记_行开始前;
        p++;
maybe_newline:
        如果 (0 == (解析_标记 & 解析_标记_换行符))
            去向 redo_no_start;
        单词编码 = 符_换行;
        去向 keep_标识符_标记;

    分支 '#':
        /* XXX: 简化 */
        复杂转义(c, p);
        如果 ((标识符_标记 & 符_标记_行开始前) && 
            (解析_标记 & 解析_标记_预处理)) {
            file->buf_ptr = p;
            _预处理(标识符_标记 & 符_标记_文件开始前);
            p = file->buf_ptr;
            去向 maybe_newline;
        } 否则 {
            如果 (c == '#') {
                p++;
                单词编码 = 双符号_2个井号;
            } 否则 {
                如果 (解析_标记 & 解析_标记_汇编_文件) {
                    p = 解析_单行_注释(p - 1);
                    去向 redo_no_start;
                } 否则 {
                    单词编码 = '#';
                }
            }
        }
        跳出;
    
    /* 不解析asm时,美元可以开始标识符 */
    分支 '$':
        如果 (!(等值_表[c - CH_文件结尾] & IS_ID)|| (解析_标记 & 解析_标记_汇编_文件))
            去向 parse_simple;
    分支 'a': 分支 'b': 分支 'c': 分支 'd':
    分支 'e': 分支 'f': 分支 'g': 分支 'h':
    分支 'i': 分支 'j': 分支 'k': 分支 'l':
    分支 'm': 分支 'n': 分支 'o': 分支 'p':
    分支 'q': 分支 'r': 分支 's': 分支 't':
    分支 'u': 分支 'v': 分支 'w': 分支 'x':
    分支 'y': 分支 'z': 
    分支 'A': 分支 'B': 分支 'C': 分支 'D':
    分支 'E': 分支 'F': 分支 'G': 分支 'H':
    分支 'I': 分支 'J': 分支 'K': 
    分支 'M': 分支 'N': 分支 'O': 分支 'P':
    分支 'Q': 分支 'R': 分支 'S': 分支 'T':
    分支 'U': 分支 'V': 分支 'W': 分支 'X':
    分支 'Y': 分支 'Z': 
    分支 '_':
    parse_ident_fast:
        p1 = p;
        h = 符_哈希_初始化;
        h = 符_哈希_函数(h, c);
        判断 (c = *++p, 等值_表[c - CH_文件结尾] & (IS_ID|IS_NUM))
            h = 符_哈希_函数(h, c);
        len = p - p1;
        如果 (c != '\\') {
            单词存储结构 **pts;

            /* 快速案例:找不到散落的,所以我们有完整的标识符而且我们已经对其进行了哈希处理 */
            h &= (哈希表容量 - 1);
            pts = &单词_哈希表[h];
            循环(;;) {
                ts = *pts;
                如果 (!ts)
                    跳出;
                如果 (ts->len == len && !memcmp(ts->str, p1, len))
                    去向 标识符_found;
                pts = &(ts->hash_next);
            }
            ts = 标识符_分配新内存(pts, (字符型 *) p1, len);
        标识符_found: ;
        } 否则 {
            /* 较慢的情况 */
            动态字符串_重置(&当前单词字符串);
            动态字符串_cat(&当前单词字符串, (字符型 *) p1, len);
            p--;
            复杂转义(c, p);
        parse_ident_slow:
            判断 (等值_表[c - CH_文件结尾] & (IS_ID|IS_NUM))
            {
                动态字符串_追加单个字符(&当前单词字符串, c);
                复杂转义(c, p);
            }
            ts = 单词表_查找(当前单词字符串.指向字符串的指针, 当前单词字符串.字符串长度);
        }
        单词编码 = ts->单词编码;
        跳出;
    分支 'L':
        t = p[1];
        如果 (t != '\\' && t != '\'' && t != '\"') {
            /* 快的方案 */
            去向 parse_ident_fast;
        } 否则 {
            复杂转义(c, p);
            如果 (c == '\'' || c == '\"') {
                is_long = 1;
                去向 str_const;
            } 否则 {
                动态字符串_重置(&当前单词字符串);
                动态字符串_追加单个字符(&当前单词字符串, 'L');
                去向 parse_ident_slow;
            }
        }
        跳出;

    分支 '0': 分支 '1': 分支 '2': 分支 '3':
    分支 '4': 分支 '5': 分支 '6': 分支 '7':
    分支 '8': 分支 '9':
        t = c;
        复杂转义(c, p);
        /* 在第一个数字之后,接受数字,字母“。”。 或以'eEpP'开头的符号 */
    parse_num:
        动态字符串_重置(&当前单词字符串);
        循环(;;) {
            动态字符串_追加单个字符(&当前单词字符串, t);
            如果 (!((等值_表[c - CH_文件结尾] & (IS_ID|IS_NUM))
                  || c == '.'
                  || ((c == '+' || c == '-')
                      && (((t == 'e' || t == 'E')
                            && !(解析_标记 & 解析_标记_汇编_文件
                                /* 0xe + 1是asm中的3个标识符 */
                                && ((字符型*)当前单词字符串.指向字符串的指针)[0] == '0'
                                && toup(((字符型*)当前单词字符串.指向字符串的指针)[1]) == 'X'))
                          || t == 'p' || t == 'P'))))
                跳出;
            t = c;
            复杂转义(c, p);
        }
        /* 我们添加尾随“ \ 0”以简化解析 */
        动态字符串_追加单个字符(&当前单词字符串, '\0');
        单词值.str.size = 当前单词字符串.字符串长度;
        单词值.str.data = 当前单词字符串.指向字符串的指针;
        单词编码 = 常量_预处理编号;
        跳出;

    分支 '.':
        /* 特殊的点处理,因为它也可以以数字开头 */
        复杂转义(c, p);
        如果 (是数字(c)) {
            t = '.';
            去向 parse_num;
        } 否则 如果 ((等值_表['.' - CH_文件结尾] & IS_ID)
                   && (等值_表[c - CH_文件结尾] & (IS_ID|IS_NUM))) {
            *--p = c = '.';
            去向 parse_ident_fast;
        } 否则 如果 (c == '.') {
            复杂转义(c, p);
            如果 (c == '.') {
                p++;
                单词编码 = 符_三个圆点;
            } 否则 {
                *--p = '.'; /* 可能会下溢到file-> unget []中 */
                单词编码 = '.';
            }
        } 否则 {
            单词编码 = '.';
        }
        跳出;
    分支 '\'':
    分支 '\"':
        is_long = 0;
    str_const:
        动态字符串_重置(&当前单词字符串);
        如果 (is_long)
            动态字符串_追加单个字符(&当前单词字符串, 'L');
        动态字符串_追加单个字符(&当前单词字符串, c);
        p = 解析字符串_不解析转义(p, c, &当前单词字符串);
        动态字符串_追加单个字符(&当前单词字符串, c);
        动态字符串_追加单个字符(&当前单词字符串, '\0');
        单词值.str.size = 当前单词字符串.字符串长度;
        单词值.str.data = 当前单词字符串.指向字符串的指针;
        单词编码 = 常量_预处理字符串;
        跳出;

    分支 '<':
        复杂转义(c, p);
        如果 (c == '=') {
            p++;
            单词编码 = 双符号_小于等于;
        } 否则 如果 (c == '<') {
            复杂转义(c, p);
            如果 (c == '=') {
                p++;
                单词编码 = 符_A_SHL;
            } 否则 {
                单词编码 = 双符号_左位移;
            }
        } 否则 {
            单词编码 = 符_LT;
        }
        跳出;
    分支 '>':
        复杂转义(c, p);
        如果 (c == '=') {
            p++;
            单词编码 = 双符号_大于等于;
        } 否则 如果 (c == '>') {
            复杂转义(c, p);
            如果 (c == '=') {
                p++;
                单词编码 = 符_A_SAR;
            } 否则 {
                单词编码 = 双符号_右位移;
            }
        } 否则 {
            单词编码 = 符_GT;
        }
        跳出;
        
    分支 '&':
        复杂转义(c, p);
        如果 (c == '&') {
            p++;
            单词编码 = 双符号_逻辑与;
        } 否则 如果 (c == '=') {
            p++;
            单词编码 = 双符号_先求位与后赋值;
        } 否则 {
            单词编码 = '&';
        }
        跳出;
        
    分支 '|':
        复杂转义(c, p);
        如果 (c == '|') {
            p++;
            单词编码 = 双符号_逻辑或;
        } 否则 如果 (c == '=') {
            p++;
            单词编码 = 双符号_先求位或后赋值;
        } 否则 {
            单词编码 = '|';
        }
        跳出;

    分支 '+':
        复杂转义(c, p);
        如果 (c == '+') {
            p++;
            单词编码 = 双符号_自加1;
        } 否则 如果 (c == '=') {
            p++;
            单词编码 = 双符号_先求和后赋值;
        } 否则 {
            单词编码 = '+';
        }
        跳出;
        
    分支 '-':
        复杂转义(c, p);
        如果 (c == '-') {
            p++;
            单词编码 = 双符号_自减1;
        } 否则 如果 (c == '=') {
            p++;
            单词编码 = 双符号_先求差后赋值;
        } 否则 如果 (c == '>') {
            p++;
            单词编码 = 双符号_结构体指针运算符;
        } 否则 {
            单词编码 = '-';
        }
        跳出;

    PARSE2('!', '!', '=', 双符号_不等于)
    PARSE2('=', '=', '=', 双符号_等于)
    PARSE2('*', '*', '=', 双符号_先求积后赋值)
    PARSE2('%', '%', '=', 双符号_先取模后赋值)
    PARSE2('^', '^', '=', 双符号_先求异或后赋值)
        
        /* 注释或运算符 */
    分支 '/':
        复杂转义(c, p);
        如果 (c == '*') {
            p = 解析_注释(p);
            /* 注释用空格代替 */
            单词编码 = ' ';
            去向 maybe_space;
        } 否则 如果 (c == '/') {
            p = 解析_单行_注释(p);
            单词编码 = ' ';
            去向 maybe_space;
        } 否则 如果 (c == '=') {
            p++;
            单词编码 = 双符号_先求商后赋值;
        } 否则 {
            单词编码 = '/';
        }
        跳出;
        
        /* 单一标识符 */
    分支 '(':
    分支 ')':
    分支 '[':
    分支 ']':
    分支 '{':
    分支 '}':
    分支 ',':
    分支 ';':
    分支 ':':
    分支 '?':
    分支 '~':
    分支 '@': /* 仅用于汇编程序 */
    parse_simple:
        单词编码 = c;
        p++;
        跳出;
    default:
        如果 (c >= 0x80 && c <= 0xFF) /* utf8 identifiers */
	    去向 parse_ident_fast;
        如果 (解析_标记 & 解析_标记_汇编_文件)
            去向 parse_simple;
        错误_打印("无法识别的角色 \\x%02x", c);
        跳出;
    }
    标识符_标记 = 0;
keep_标识符_标记:
    file->buf_ptr = p;
#如果 已定义(PARSE_DEBUG)
    printf("标识符 = %d %s\n", 单词编码, 取_单词字符串(单词编码, &单词值));
#结束如果
}

静态 无类型 宏_替代(
    单词字符串 *tok_str,
    符号 **nested_list,
    常量 整数型 *macro_str
    );

/* 用rgs(字段d)中的值替换macro_str中替换列表中的参数,并返回分配的字符串 */
静态 整数型 *宏_参数_替换(符号 **nested_list, 常量 整数型 *macro_str, 符号 *args)
{
    整数型 t, t0, t1, spc;
    常量 整数型 *st;
    符号 *s;
    恒定值 cval;
    单词字符串 str;
    动态字符串 cstr;

    单词字符串_处理(&str);
    t0 = t1 = 0;
    判断(1) {_GET(&t, &macro_str, &cval);
        如果 (!t)
            跳出;
        如果 (t == '#') {
            /* 串化 */_GET(&t, &macro_str, &cval);
            如果 (!t)
                去向 bad_stringy;
            s = 符号_查找2(args, t);
            如果 (s) {
                动态字符串_初始化(&cstr);
                动态字符串_追加单个字符(&cstr, '\"');
                st = s->d;
                spc = 0;
                判断 (*st >= 0) {_GET(&t, &st, &cval);
                    如果 (t != 符_占位符
                     && t != 符_NOSUBST
                     && 0 == 检查_空格(t, &spc)) {
                        常量 字符型 *s = 取_单词字符串(t, &cval);
                        判断 (*s) {
                            如果 (t == 常量_预处理字符串 && *s != '\'')
                                添加_字符(&cstr, *s);
                            否则
                                动态字符串_追加单个字符(&cstr, *s);
                            ++s;
                        }
                    }
                }
                cstr.字符串长度 -= spc;
                动态字符串_追加单个字符(&cstr, '\"');
                动态字符串_追加单个字符(&cstr, '\0');
#如果已定义 PP_DEBUG
                printf("\nstringize: <%s>\n", (字符型 *)cstr.指向字符串的指针;
#结束如果
                /* 添加字符串 */
                cval.str.size = cstr.字符串长度;
                cval.str.data = cstr.指向字符串的指针;
                单词字符串_增加大小2(&str, 常量_预处理字符串, &cval);
                动态字符串_释放(&cstr);
            } 否则 {
        bad_stringy:
                应为(" '#'后的宏参数");
            }
        } 否则 如果 (t >= 符_识别) {
            s = 符号_查找2(args, t);
            如果 (s) {
                整数型 l0 = str.len;
                st = s->d;
                /* 如果'##'之前或之后存在,则无arg替换 */
                如果 (*macro_str == 符_PPJOIN || t1 == 符_PPJOIN) {
                    /* var arg宏的特殊情况:##如果空的VA_ARGS变量吃掉',' */
                    如果 (t1 == 符_PPJOIN && t0 == ',' && gnu_扩展 && s->type.t) {
                        如果 (*st <= 0) {
                            /* 禁止',''##' */
                            str.len -= 2;
                        } 否则 {
                            /* 取消显示“ ##”并添加变量*/
                            str.len--;
                            去向 add_var;
                        }
                    }
                } 否则 {
            add_var:
		    如果 (!s->next) {
			/* 展开参数令牌并存储它们。 在大多数情况下,如果多次使用,我们还可以重新扩展每个参数,但是如果参数包含__COUNTER__宏,则不能。  */
			单词字符串 str2;
			符号_推送2(&s->next, s->v, s->type.t, 0);
			单词字符串_处理(&str2);
			宏_替代(&str2, nested_list, st);
			单词字符串_增加大小(&str2, 0);
			s->next->d = str2.str;
		    }
		    st = s->next->d;
                }
                循环(;;) {
                    整数型 t2;_GET(&t2, &st, &cval);
                    如果 (t2 <= 0)
                        跳出;
                    单词字符串_增加大小2(&str, t2, &cval);
                }
                如果 (str.len == l0) /* 扩展为空字符串 */
                    单词字符串_增加大小(&str, 符_占位符);
            } 否则 {
                单词字符串_增加大小(&str, t);
            }
        } 否则 {
            单词字符串_增加大小2(&str, t, &cval);
        }
        t0 = t1, t1 = t;
    }
    单词字符串_增加大小(&str, 0);
    返回 str.str;
}

静态 字符型 常量 ab_月份_名称[12][4] =
{
    "Jan", "Feb", "Mar", "Apr", "May", "Jun",
    "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
};

静态 整数型 粘贴_标识符(整数型 t1, 恒定值 *v1, 整数型 t2, 恒定值 *v2)
{
    动态字符串 cstr;
    整数型 n, ret = 1;

    动态字符串_初始化(&cstr);
    如果 (t1 != 符_占位符)
        动态字符串_cat(&cstr, 取_单词字符串(t1, v1), -1);
    n = cstr.字符串长度;
    如果 (t2 != 符_占位符)
        动态字符串_cat(&cstr, 取_单词字符串(t2, v2), -1);
    动态字符串_追加单个字符(&cstr, '\0');

    打开缓存文件(zhi_状态, ":paste:", cstr.字符串长度);
    memcpy(file->buffer, cstr.指向字符串的指针, cstr.字符串长度);
    标识符_标记 = 0;
    循环 (;;) {
        取_下个符号_不宏扩展1();
        如果 (0 == *file->buf_ptr)
            跳出;
        如果 (是_空格(单词编码))
            继续;
        zhi_警告("粘贴 \"%.*s\" 和 \"%s\" 没有给出有效的预处理标识符", n, (字符型 *)cstr.指向字符串的指针, (字符型*)cstr.指向字符串的指针 + n);
        ret = 0;
        跳出;
    }
    关闭文件();
    动态字符串_释放(&cstr);
    返回 ret;
}

/* 处理“ ##”运算符。 如果未看到“ ##”,则返回NULL。 否则返回结果字符串(必须释放). */
静态 内联 整数型 *宏_俩井(常量 整数型 *ptr0)
{
    整数型 t;
    恒定值 cval;
    单词字符串 macro_str1;
    整数型 start_of_nosubsts = -1;
    常量 整数型 *ptr;

    /* 我们搜索第一个“ ##” */
    循环 (ptr = ptr0;;) {_GET(&t, &ptr, &cval);
        如果 (t == 符_PPJOIN)
            跳出;
        如果 (t == 0)
            返回 NULL;
    }

    单词字符串_处理(&macro_str1);

    //标识符_打印(" $$$", ptr0);
    循环 (ptr = ptr0;;) {_GET(&t, &ptr, &cval);
        如果 (t == 0)
            跳出;
        如果 (t == 符_PPJOIN)
            继续;
        判断 (*ptr == 符_PPJOIN) {
            整数型 t1; 恒定值 cv1;
            /* 给定'a ## b',删除'a'之前的nosubstst */
            如果 (start_of_nosubsts >= 0)
                macro_str1.len = start_of_nosubsts;
            /* 给定'a ## b',删除'b'之前的nosubsts */
            判断 ((t1 = *++ptr) == 符_NOSUBST)
                ;
            如果 (t1 && t1 != 符_PPJOIN) {_GET(&t1, &ptr, &cv1);
                如果 (t != 符_占位符 || t1 != 符_占位符) {
                    如果 (粘贴_标识符(t, &cval, t1, &cv1)) {
                        t = 单词编码, cval = 单词值;
                    } 否则 {
                        单词字符串_增加大小2(&macro_str1, t, &cval);
                        t = t1, cval = cv1;
                    }
                }
            }
        }
        如果 (t == 符_NOSUBST) {
            如果 (start_of_nosubsts < 0)
                start_of_nosubsts = macro_str1.len;
        } 否则 {
            start_of_nosubsts = -1;
        }
        单词字符串_增加大小2(&macro_str1, t, &cval);
    }
    单词字符串_增加大小(&macro_str1, 0);
    //标识符_打印(" ###", macro_str1.str);
    返回 macro_str1.str;
}

/* 从函数宏调用中窥视或读取[ws_str == NULL]下一个标记,如有必要,将宏级别提升到文件*/
静态 整数型 从函数宏调用中_读取下一个标记(符号 **nested_list, 单词字符串 *ws_str)
{
    整数型 t;
    常量 整数型 *p;
    符号 *sa;

    循环 (;;) {
        如果 (宏_ptr) {
            p = 宏_ptr, t = *p;
            如果 (ws_str) {
                判断 (是_空格(t) || 符_换行 == t || 符_占位符 == t)
                    单词字符串_增加大小(ws_str, t), t = *++p;
            }
            如果 (t == 0) {
                结束_宏();
                /* 同样,嵌套定义符号的作用域结尾 */
                sa = *nested_list;
                判断 (sa && sa->v == 0)
                    sa = sa->prev;
                如果 (sa)
                    sa->v = 0;
                继续;
            }
        } 否则 {
            当前取到的源码字符 = 处理_块的结尾();
            如果 (ws_str) {
                判断 (是_空格(当前取到的源码字符) || 当前取到的源码字符 == '\n' || 当前取到的源码字符 == '/') {
                    如果 (当前取到的源码字符 == '/') {
                        整数型 c;
                        uint8_t *p = file->buf_ptr;
                        复杂转义(c, p);
                        如果 (c == '*') {
                            p = 解析_注释(p);
                            file->buf_ptr = p - 1;
                        } 否则 如果 (c == '/') {
                            p = 解析_单行_注释(p);
                            file->buf_ptr = p - 1;
                        } 否则
                            跳出;
                        当前取到的源码字符 = ' ';
                    }
                    如果 (当前取到的源码字符 == '\n')
                        file->line_num++;
                    如果 (!(当前取到的源码字符 == '\f' || 当前取到的源码字符 == '\v' || 当前取到的源码字符 == '\r'))
                        单词字符串_增加大小(ws_str, 当前取到的源码字符);
                    cinp();
                }
            }
            t = 当前取到的源码字符;
        }

        如果 (ws_str)
            返回 t;
        取_下个符号_不宏扩展();
        返回 单词编码;
    }
}

/* 用宏“ s”对当前令牌进行宏替换,并将结果添加到(tok_str,tok_len)。 “ nested_list”是我们为了避免递归而进入的所有宏的列表。 如果不需要替换,则返回非零 */
静态 整数型 宏替换_当前标识符(
    单词字符串 *tok_str,
    符号 **nested_list,
    符号 *s)
{
    符号 *args, *sa, *sa1;
    整数型 parlevel, t, t1, spc;
    单词字符串 str;
    字符型 *cstrval;
    恒定值 cval;
    动态字符串 cstr;
    字符型 buf[32];

    /* 如果符号是宏,则准备替换 */
    /* 特殊宏 */
    如果 (单词编码 == 符___LINE__  || 单词编码 == 符___LINE___CN || 单词编码 == 符___COUNTER__ || 单词编码 == 符___COUNTER___CN) {
        t =(单词编码 == 符___LINE__ || 单词编码 == 符___LINE___CN) ? file->line_num : 词法分析_计数器++;
        snprintf(buf, 取大小(buf), "%d", t);
        cstrval = buf;
        t1 = 常量_预处理编号;
        去向 add_cstr1;
    } 否则 如果 (单词编码 == 符___FILE__ || 单词编码 == 符___FILE___CN) {
        cstrval = file->文件名;
        去向 add_cstr;
    } 否则 如果 (单词编码 == 符___DATE__ || 单词编码 == 符___DATE___CN || 单词编码 == 符___TIME__ || 单词编码 == 符___TIME___CN) {
        time_t ti;
        结构体 tm *tm;

        time(&ti);
        tm = localtime(&ti);
        如果 (单词编码 == 符___DATE__ || 单词编码 == 符___DATE___CN) {
            snprintf(buf, 取大小(buf), "%s %2d %d", 
                     ab_月份_名称[tm->tm_mon], tm->tm_mday, tm->tm_year + 1900);
        } 否则 {
            snprintf(buf, 取大小(buf), "%02d:%02d:%02d", 
                     tm->tm_hour, tm->tm_min, tm->tm_sec);
        }
        cstrval = buf;
    add_cstr:
        t1 = 常量_字符串;
    add_cstr1:
        动态字符串_初始化(&cstr);
        动态字符串_cat(&cstr, cstrval, 0);
        cval.str.size = cstr.字符串长度;
        cval.str.data = cstr.指向字符串的指针;
        单词字符串_增加大小2(tok_str, t1, &cval);
        动态字符串_释放(&cstr);
    } 否则 如果 (s->d) {
        整数型 saved_解析_标记 = 解析_标记;
	整数型 *joined_str = NULL;
        整数型 *mstr = s->d;

        如果 (s->type.t == 宏_函数) {
            /* 宏名称和参数列表之间的空格 */
            单词字符串 ws_str;
            单词字符串_处理(&ws_str);

            spc = 0;
            解析_标记 |= 解析_标记_空间 | 解析_标记_换行符
                | 解析_标记_接受_转义;

            /* 从参数流中获取下一个标记 */
            t = 从函数宏调用中_读取下一个标记(nested_list, &ws_str);
            如果 (t != '(') {
                /* 毕竟不是宏替换,请恢复宏令牌以及我们已阅读的所有空白。故意不合并空白以保留换行符。 */
                解析_标记 = saved_解析_标记;
                单词字符串_增加大小(tok_str, 单词编码);
                如果 (解析_标记 & 解析_标记_空间) {
                    整数型 i;
                    循环 (i = 0; i < ws_str.len; i++)
                        单词字符串_增加大小(tok_str, ws_str.str[i]);
                }
                单词字符串_释放_字符串(ws_str.str);
                返回 0;
            } 否则 {
                单词字符串_释放_字符串(ws_str.str);
            }
	    执行 {
		取_下个符号_不宏扩展(); /* eat '(' */
	    } 判断 (单词编码 == 符_占位符 || 是_空格(单词编码));

            /* 参数宏 */
            args = NULL;
            sa = s->next;
            /* 注意:允许使用空参数,除非没有参数 */
            循环(;;) {
                执行 {
                    从函数宏调用中_读取下一个标记(nested_list, NULL);
                } 判断 (是_空格(单词编码) || 符_换行 == 单词编码);
    empty_arg:
                /* 处理'()'实例 */
                如果 (!args && !sa && 单词编码 == ')')
                    跳出;
                如果 (!sa)
                    错误_打印("宏 '%s' 与过多的参数一起使用",
                          取_单词字符串(s->v, 0));
                单词字符串_处理(&str);
                parlevel = spc = 0;
                /* 注意:非零sa-> t表示VA_ARGS */
                判断 ((parlevel > 0 || 
                        (单词编码 != ')' && 
                         (单词编码 != ',' || sa->type.t)))) {
                    如果 (单词编码 == 符_文件结尾 || 单词编码 == 0)
                        跳出;
                    如果 (单词编码 == '(')
                        parlevel++;
                    否则 如果 (单词编码 == ')')
                        parlevel--;
                    如果 (单词编码 == 符_换行)
                        单词编码 = ' ';
                    如果 (!检查_空格(单词编码, &spc))
                        单词字符串_增加大小2(&str, 单词编码, &单词值);
                    从函数宏调用中_读取下一个标记(nested_list, NULL);
                }
                如果 (parlevel)
                    应为(")");
                str.len -= spc;
                单词字符串_增加大小(&str, -1);
                单词字符串_增加大小(&str, 0);
                sa1 = 符号_推送2(&args, sa->v & ~符号_字段, sa->type.t, 0);
                sa1->d = str.str;
                sa = sa->next;
                如果 (单词编码 == ')') {
                    /* gcc var args的特殊情况:如果省略,则添加一个空的var arg参数*/
                    如果 (sa && sa->type.t && gnu_扩展)
                        去向 empty_arg;
                    跳出;
                }
                如果 (单词编码 != ',')
                    应为(",");
            }
            如果 (sa) {
                错误_打印("宏 '%s' 使用的参数太少",
                      取_单词字符串(s->v, 0));
            }

            /* 现在替换每个arg */
            mstr = 宏_参数_替换(nested_list, mstr, args);
            /* 内存_释放 */
            sa = args;
            判断 (sa) {
                sa1 = sa->prev;
                单词字符串_释放_字符串(sa->d);
                如果 (sa->next) {
                    单词字符串_释放_字符串(sa->next->d);
                    符号_释放(sa->next);
                }
                符号_释放(sa);
                sa = sa1;
            }
            解析_标记 = saved_解析_标记;
        }

        符号_推送2(nested_list, s->v, 0, 0);
        解析_标记 = saved_解析_标记;
        joined_str = 宏_俩井(mstr);
        宏_替代(tok_str, nested_list, joined_str ? joined_str : mstr);

        /* 弹出嵌套定义的符号 */
        sa1 = *nested_list;
        *nested_list = sa1->prev;
        符号_释放(sa1);
	如果 (joined_str)
	    单词字符串_释放_字符串(joined_str);
        如果 (mstr != s->d)
            单词字符串_释放_字符串(mstr);
    }
    返回 0;
}

/* 对macro_str进行宏替换,并将结果添加到(tok_str,tok_len)。 “ nested_list”是我们为了避免递归而进入的所有宏的列表。 */
静态 无类型 宏_替代(
    单词字符串 *tok_str,
    符号 **nested_list,
    常量 整数型 *macro_str
    )
{
    符号 *s;
    整数型 t, spc, nosubst;
    恒定值 cval;
    
    spc = nosubst = 0;

    判断 (1) {_GET(&t, &macro_str, &cval);
        如果 (t <= 0)
            跳出;

        如果 (t >= 符_识别 && 0 == nosubst) {
            s = 宏定义_查找(t);
            如果 (s == NULL)
                去向 no_subst;

            /* 如果嵌套替换,则不执行任何操作 */
            如果 (符号_查找2(*nested_list, t)) {
                /* 并将其标记为符_NOSUBST,因此不会再次被替换 */
                单词字符串_增加大小2(tok_str, 符_NOSUBST, NULL);
                去向 no_subst;
            }

            {
                单词字符串 *str = 单词字符串_分配();
                str->str = (整数型*)macro_str;
                开始_宏(str, 2);

                单词编码 = t;
                宏替换_当前标识符(tok_str, nested_list, s);

                如果 (宏_堆栈 != str) {
                    /* 通过读取函数宏参数已完成 */
                    跳出;
                }

                macro_str = 宏_ptr;
                结束_宏 ();
            }
            如果 (tok_str->len)
                spc = 是_空格(t = tok_str->str[tok_str->lastlen]);
        } 否则 {
no_subst:
            如果 (!检查_空格(t, &spc))
                单词字符串_增加大小2(tok_str, t, &cval);

            如果 (nosubst) {
                如果 (nosubst > 1 && (spc || (++nosubst == 3 && t == '(')))
                    继续;
                nosubst = 0;
            }
            如果 (t == 符_NOSUBST)
                nosubst = 1;
        }
        /* 由于宏替换,GCC支持“def” */
        如果 ((t == 关键字_DEFINED || t == 关键字_已定义)  && 词法分析_表达式)
            nosubst = 2;
    }
}

/* 返回下一个标记而不进行宏替换。 可以从宏_ptr缓冲区读取输入 */
静态 无类型 取_下个符号_不宏扩展(无类型)
{
    整数型 t;
    如果 (宏_ptr) {
 redo:
        t = *宏_ptr;
        如果 (符_有_值(t)) {
            获取_标识符(&单词编码, &宏_ptr, &单词值);
            如果 (t == 常量_行号) {
                file->line_num = 单词值.i;
                去向 redo;
            }
        } 否则 {
            宏_ptr++;
            如果 (t < 符_识别) {
                如果 (!(解析_标记 & 解析_标记_空间)
                    && (等值_表[t - CH_文件结尾] & IS_SPC))
                    去向 redo;
            }
            单词编码 = t;
        }
    } 否则 {
        取_下个符号_不宏扩展1();
    }
}

/* 返回带有宏替换的下一个标记 */
静态_函数 无类型 带有宏替换的下个标记(无类型)
{
    整数型 t;
 redo:
    取_下个符号_不宏扩展();
    t = 单词编码;
    如果 (宏_ptr) {
        如果 (!符_有_值(t)) {
            如果 (t == 符_NOSUBST || t == 符_占位符) {
                /* 丢弃预处理器标记 */
                去向 redo;
            } 否则 如果 (t == 0) {
                /* 宏结尾或获取令牌字符串 */
                结束_宏();
                去向 redo;
            } 否则 如果 (t == '\\') {
                如果 (!(解析_标记 & 解析_标记_接受_转义))
                    错误_打印("程序中流浪 '\\' ");
            }
            返回;
        }
    } 否则 如果 (t >= 符_识别 && (解析_标记 & 解析_标记_预处理)) {
        /* 如果从文件读取,请尝试替换宏 */
        符号 *s = 宏定义_查找(t);
        如果 (s) {
            符号 *nested_list = NULL;
            单词字符串_缓冲.len = 0;
            宏替换_当前标识符(&单词字符串_缓冲, &nested_list, s);
            单词字符串_增加大小(&单词字符串_缓冲, 0);
            开始_宏(&单词字符串_缓冲, 0);
            去向 redo;
        }
        返回;
    }
    /* 将预处理器标识符转换为C标识符 */
    如果 (t == 常量_预处理编号) {
        如果  (解析_标记 & 解析_标记_标识符_数字)
            解析_数字((字符型 *)单词值.str.data);
    } 否则 如果 (t == 常量_预处理字符串) {
        如果 (解析_标记 & 解析_标记_单词字符串)
            解析_字符串((字符型 *)单词值.str.data, 单词值.str.size - 1);
    }
}

/* 推回当前令牌并将当前令牌设置为“ last_tok”。 仅处理标签的标识符大小写. */
静态_内联 无类型 设为_指定标识符(整数型 last_tok)
{

    单词字符串 *str = 单词字符串_分配();
    单词字符串_增加大小2(str, 单词编码, &单词值);
    单词字符串_增加大小(str, 0);
    开始_宏(str, 1);
    单词编码 = last_tok;
}

静态 无类型 zhi_预定义(动态字符串 *cstr)
{
    动态字符串_cat(cstr,
#如果 已定义 ZHI_TARGET_X86_64
#如果未定义 ZHI_TARGET_PE
    /* va_list的GCC兼容定义。 这应该与我们的lib / hexinku1.c中的声明同步 */
    "类型定义 结构体{\n"
    "无符号 gp_offset,fp_offset;\n"
    "共用体{\n"
    "无符号 overflow_offset;\n"
    "字符型*overflow_arg_area;\n"
    "};\n"
    "字符型*reg_save_area;\n"
    "}__builtin_va_list[1];\n"
    "无类型*__va_arg(__builtin_va_list ap,整数型 arg_type,整数型 size,整数型 align);\n"
    "#定义 __builtin_va_start(ap,last) (*(ap)=*(__builtin_va_list)((字符型*)__builtin_frame_address(0)-24))\n"
    "#定义 __builtin_va_arg(ap,t) (*(t*)(__va_arg(ap,__builtin_va_arg_types(t),取大小(t),__alignof__(t))))\n"
    "#定义 __builtin_va_copy(dest,src) (*(dest)=*(src))\n"
#否则 /* ZHI_TARGET_PE */
    "类型定义 字符型*__builtin_va_list;\n"
    "#定义 __builtin_va_arg(ap,t) ((取大小(t)>8||(取大小(t)&(取大小(t)-1)))?**(t**)((ap+=8)-8):*(t*)((ap+=8)-8))\n"
    "#定义 __builtin_va_copy(dest,src) (dest)=(src)\n"
#结束如果
#否则如果 已定义 ZHI_TARGET_ARM
    "类型定义 字符型*__builtin_va_list;\n"
    "#定义 _zhi_alignof(type) ((整数型)&((结构体{字符型 c;type x;}*)0)->x)\n"
    "#定义 _zhi_align(addr,type) (((无符号)addr+_zhi_alignof(type)-1)&~(_zhi_alignof(type)-1))\n"
    "#定义 __builtin_va_start(ap,last) (ap=((字符型*)&(last))+((取大小(last)+3)&~3))\n"
    "#定义 __builtin_va_arg(ap,type) (ap=(无类型*)((_zhi_align(ap,type)+取大小(type)+3)&~3),*(type*)(ap-((取大小(type)+3)&~3)))\n"
    "#定义 __builtin_va_copy(dest,src) (dest)=(src)\n"
#否则如果 已定义 ZHI_TARGET_ARM64
    "类型定义 结构体{\n"
    "无类型*__stack,*__gr_top,*__vr_top;\n"
    "整数型 __gr_offs,__vr_offs;\n"
    "}__builtin_va_list;\n"
    "#定义 __builtin_va_copy(dest,src) (dest)=(src)\n"
#否则如果 已定义 ZHI_TARGET_RISCV64
    "类型定义 字符型*__builtin_va_list;\n"
    "#定义 __va_reg_size (__riscv_xlen>>3)\n"
    "#定义 _zhi_align(addr,type) (((无符号 long)addr+__alignof__(type)-1)&-(__alignof__(type)))\n"
    "#定义 __builtin_va_arg(ap,type) (*(取大小(type)>(2*__va_reg_size)?*(type**)((ap+=__va_reg_size)-__va_reg_size):(ap=(va_list)(_zhi_align(ap,type)+(取大小(type)+__va_reg_size-1)&-__va_reg_size),(type*)(ap-((取大小(type)+__va_reg_size-1)&-__va_reg_size)))))\n"
    "#定义 __builtin_va_copy(dest,src) (dest)=(src)\n"
#否则 /* ZHI_TARGET_I386 */
    "类型定义 字符型*__builtin_va_list;\n"
    "#定义 __builtin_va_start(ap,last) (ap=((字符型*)&(last))+((取大小(last)+3)&~3))\n"
    "#定义 __builtin_va_arg(ap,t) (*(t*)((ap+=(取大小(t)+3)&~3)-((取大小(t)+3)&~3)))\n"
    "#定义 __builtin_va_copy(dest,src) (dest)=(src)\n"
#结束如果
    "#定义 __builtin_va_end(ap) (无类型)(ap)\n"
    , -1);
}

静态_函数 无类型 开始_预处理(知心状态机 *状态机1, 整数型 is_asm)
{
    动态字符串 cstr;

    词法分析_开始(状态机1);

    状态机1->包含_堆_ptr = 状态机1->包含_堆;
    状态机1->如果已宏定义_堆_ptr = 状态机1->如果已宏定义_堆;
    file->如果已宏定义_堆_ptr = 状态机1->如果已宏定义_堆_ptr;
    词法分析_表达式 = 0;
    词法分析_计数器 = 0;
    词法分析_调试_标识符 = 词法分析_调试_字符值 = 0;
    词法分析_第一次++;
    状态机1->包_堆[0] = 0;
    状态机1->包_堆_ptr = 状态机1->包_堆;

    设置_等值数('$', !is_asm && 状态机1->允许_在标识符中使用美元符号 ? IS_ID : 0);
    设置_等值数('.', is_asm ? IS_ID : 0);

    动态字符串_初始化(&cstr);
    如果 (状态机1->命令行_定义.字符串长度)
        动态字符串_cat(&cstr, 状态机1->命令行_定义.指向字符串的指针, 状态机1->命令行_定义.字符串长度);
    动态字符串_打印(&cstr, "#定义 __BASE_FILE__ \"%s\"\n", file->文件名);
    如果 (is_asm)
        动态字符串_打印(&cstr, "#定义 __ASSEMBLER__ 1\n");
    如果 (状态机1->输出_类型 == ZHI_输出_内存中运行)
        动态字符串_打印(&cstr, "#定义 __ZHI_RUN__ 1\n");
    如果 (!is_asm && 状态机1->输出_类型 != ZHI_输出_预处理)
        zhi_预定义(&cstr);
    如果 (状态机1->命令行_包含.字符串长度)
        动态字符串_cat(&cstr, 状态机1->命令行_包含.指向字符串的指针, 状态机1->命令行_包含.字符串长度);
    //printf("%s\n", (字符型*)cstr.data);
    *状态机1->包含_堆_ptr++ = file;
    打开缓存文件(状态机1, "<command line>", cstr.字符串长度);
    memcpy(file->buffer, cstr.指向字符串的指针, cstr.字符串长度);
    动态字符串_释放(&cstr);

    解析_标记 = is_asm ? 解析_标记_汇编_文件 : 0;
    标识符_标记 = 符_标记_行开始前 | 符_标记_文件开始前;
}

/* 从错误/ setjmp中清除 */
静态_函数 无类型 结束_预处理(知心状态机 *状态机1)
{
    判断 (宏_堆栈)
        结束_宏();
    宏_ptr = NULL;
    判断 (file)
        关闭文件();
    zhi词法_删除(状态机1);
}

静态_函数 无类型 词法分析_开始(知心状态机 *s)
{
    整数型 i, c;
    常量 字符型 *p, *r;

    /* 初始化是id表 */
    循环(i = CH_文件结尾; i<128; i++)
        设置_等值数(i,
            是_空格(i) ? IS_SPC
            :id(i) ? IS_ID
            : 是数字(i) ? IS_NUM
            : 0);

    循环(i = 128; i<256; i++)
        设置_等值数(i, IS_ID);

    /* 初始化分配器 */
    小分配器_新建(&单词字符_分配内存, 单词字符_小分配器_限制, 单词字符_小分配器_大小);
    小分配器_新建(&单词字符串_分配内存, 单词字符串_小分配器_限制, 单词字符串_小分配器_大小);

    memset(单词_哈希表, 0, 哈希表容量 * 取大小(单词存储结构 *));
    memset(s->缓存_包含数_哈希, 0, 取大小 s->缓存_包含数_哈希);

    动态字符串_初始化(&动态字符串_缓冲);
    动态字符串_重分配内存(&动态字符串_缓冲, 字符串_最大_长度);
    单词字符串_处理(&单词字符串_缓冲);
    单词字符串_重分配(&单词字符串_缓冲, 单词字符串_最大_长度);

    单词_识别号 = 符_识别;
    p = 编译_关键词;
    判断 (*p) {
        r = p;
        循环(;;) {
            c = *r++;
            如果 (c == '\0')
                跳出;
        }
        单词表_查找(p, r - p - 1);
        p = r;
    }

    /* 我们为一些特殊的宏添加了虚拟定义,以加快测试速度,并具有有效的define() */
    宏定义_处理(符___LINE__, 宏_对象, NULL, NULL);
    宏定义_处理(符___FILE__, 宏_对象, NULL, NULL);
    宏定义_处理(符___DATE__, 宏_对象, NULL, NULL);
    宏定义_处理(符___TIME__, 宏_对象, NULL, NULL);
    宏定义_处理(符___COUNTER__, 宏_对象, NULL, NULL);
}

静态_函数 无类型 zhi词法_删除(知心状态机 *s)
{
    整数型 i, n;

    动态数组_重分配容量(&s->缓存_包含数, &s->数量_缓存_包含数);

    /* 释放标识符 */
    n = 单词_识别号 - 符_识别;
    如果 (n > 总_idents)
        总_idents = n;
    循环(i = 0; i < n; i++)
        小分配器_释放(单词字符_分配内存, 单词表[i]);
    内存_释放(单词表);
    单词表 = NULL;

    /* 释放静态缓冲区 */
    动态字符串_释放(&当前单词字符串);
    动态字符串_释放(&动态字符串_缓冲);
    动态字符串_释放(&宏_等于_缓冲区);
    单词字符串_释放_字符串(单词字符串_缓冲.str);

    /* 释放分配器 */
    小分配器_删除(单词字符_分配内存);
    单词字符_分配内存 = NULL;
    小分配器_删除(单词字符串_分配内存);
    单词字符串_分配内存 = NULL;
}

/* ------------------------------------------------------------------------- */

静态 无类型 标识符_打印(常量 字符型 *msg, 常量 整数型 *str)
{
    FILE *fp;
    整数型 t, s = 0;
    恒定值 cval;

    fp = zhi_状态->预处理输出文件;
    fprintf(fp, "%s", msg);
    判断 (str) {_GET(&t, &str, &cval);
	如果 (!t)
	    跳出;
	fprintf(fp, " %s" + s, 取_单词字符串(t, &cval)), s = 1;
    }
    fprintf(fp, "\n");
}

静态 无类型 词法_行(知心状态机 *状态机1, 缓冲文件 *f, 整数型 level)
{
    整数型 d = f->line_num - f->line_ref;

    如果 (状态机1->DX标号 & 4)
	返回;

    如果 (状态机1->P标号 == LINE_MACRO_OUTPUT_FORMAT_NONE) {
        ;
    } 否则 如果 (level == 0 && f->line_ref && d < 8) {
	判断 (d > 0)
	    fputs("\n", 状态机1->预处理输出文件), --d;
    } 否则 如果 (状态机1->P标号 == LINE_MACRO_OUTPUT_FORMAT_STD) {
	fprintf(状态机1->预处理输出文件, "#line %d \"%s\"\n", f->line_num, f->文件名);
    } 否则 {
	fprintf(状态机1->预处理输出文件, "# %d \"%s\"%s\n", f->line_num, f->文件名,
	    level > 0 ? " 1" : level < 0 ? " 2" : "");
    }
    f->line_ref = f->line_num;
}

静态 无类型 宏定义_打印(知心状态机 *状态机1, 整数型 v)
{
    FILE *fp;
    符号 *s;

    s = 宏定义_查找(v);
    如果 (NULL == s || NULL == s->d)
        返回;

    fp = 状态机1->预处理输出文件;
    fprintf(fp, "#定义 %s", 取_单词字符串(v, NULL));
    如果 (s->type.t == 宏_函数) {
        符号 *a = s->next;
        fprintf(fp,"(");
        如果 (a)
            循环 (;;) {
                fprintf(fp,"%s", 取_单词字符串(a->v & ~符号_字段, NULL));
                如果 (!(a = a->next))
                    跳出;
                fprintf(fp,",");
            }
        fprintf(fp,")");
    }
    标识符_打印("", s->d);
}

静态 无类型 词法_调试_宏定义(知心状态机 *状态机1)
{
    整数型 v, t;
    常量 字符型 *vs;
    FILE *fp;

    t = 词法分析_调试_标识符;
    如果 (t == 0)
        返回;

    file->line_num--;
    词法_行(状态机1, file, 0);
    file->line_ref = ++file->line_num;

    fp = 状态机1->预处理输出文件;
    v = 词法分析_调试_字符值;
    vs = 取_单词字符串(v, NULL);
    如果 (t == 关键字_DEFINE || t == 关键字_定义) {
        宏定义_打印(状态机1, v);
    } 否则 如果 (t == 关键字_UNDEF || t == 关键字_取消定义) {
        fprintf(fp, "#取消定义 %s\n", vs);
    } 否则 如果 (t == 符_push_macro) {
        fprintf(fp, "#pragma push_macro(\"%s\")\n", vs);
    } 否则 如果 (t == 符_pop_macro) {
        fprintf(fp, "#pragma pop_macro(\"%s\")\n", vs);
    }
    词法分析_调试_标识符 = 0;
}

静态 无类型 词法_调试_内置(知心状态机 *状态机1)
{
    整数型 v;
    循环 (v = 符_识别; v < 单词_识别号; ++v)
        宏定义_打印(状态机1, v);
}

/* 在标记a和b之间添加一个空格,以避免不必要的文本粘贴 */
静态 整数型 词法_添加_空格(整数型 a, 整数型 b)
{
    返回 'E' == a ? '+' == b || '-' == b
        : '+' == a ? 双符号_自加1 == b || '+' == b
        : '-' == a ? 双符号_自减1 == b || '-' == b
        : a >= 符_识别 ? b >= 符_识别
	: a == 常量_预处理编号 ? b >= 符_识别
        : 0;
}

/* 也许像0x1e这样的十六进制 */
静态 整数型 词法_检查_he0xE(整数型 t, 常量 字符型 *p)
{
    如果 (t == 常量_预处理编号 && toup(strchr(p, 0)[-1]) == 'E')
        返回 'E';
    返回 t;
}

/* 预处理当前文件 */
静态_函数 整数型 预处理_源文件(知心状态机 *状态机1)
{
    缓冲文件 **iptr;
    整数型 标识符_seen, spcs, level;
    常量 字符型 *p;
    字符型 white[400];

    解析_标记 = 解析_标记_预处理 | (解析_标记 & 解析_标记_汇编_文件) | 解析_标记_换行符 | 解析_标记_空间 | 解析_标记_接受_转义;
    如果 (状态机1->P标号 == LINE_MACRO_OUTPUT_FORMAT_P10)
        解析_标记 |= 解析_标记_标识符_数字, 状态机1->P标号 = 1;

#如果已定义 PP_BENCH
    /* 用于PP基准 */
    执行 带有宏替换的下个标记(); 判断 (单词编码 != 符_文件结尾);
    返回 0;
#结束如果

    如果 (状态机1->DX标号 & 1) {
        词法_调试_内置(状态机1);
        状态机1->DX标号 &= ~1;
    }

    标识符_seen = 符_换行, spcs = 0, level = 0;
    如果 (file->prev)
        词法_行(状态机1, file->prev, level++);
    词法_行(状态机1, file, level);
    循环 (;;) {
        iptr = 状态机1->包含_堆_ptr;
        带有宏替换的下个标记();
        如果 (单词编码 == 符_文件结尾)
            跳出;

        level = 状态机1->包含_堆_ptr - iptr;
        如果 (level) {
            如果 (level > 0)
                词法_行(状态机1, *iptr, 0);
            词法_行(状态机1, file, level);
        }
        如果 (状态机1->DX标号 & 7) {
            词法_调试_宏定义(状态机1);
            如果 (状态机1->DX标号 & 4)
                继续;
        }

        如果 (是_空格(单词编码)) {
            如果 (spcs < 取大小 white - 1)
                white[spcs++] = 单词编码;
            继续;
        } 否则 如果 (单词编码 == 符_换行) {
            spcs = 0;
            如果 (标识符_seen == 符_换行)
                继续;
            ++file->line_ref;
        } 否则 如果 (标识符_seen == 符_换行) {
            词法_行(状态机1, file, 0);
        } 否则 如果 (spcs == 0 && 词法_添加_空格(标识符_seen, 单词编码)) {
            white[spcs++] = ' ';
        }

        white[spcs] = 0, fputs(white, 状态机1->预处理输出文件), spcs = 0;
        fputs(p = 取_单词字符串(单词编码, &单词值), 状态机1->预处理输出文件);
        标识符_seen = 词法_检查_he0xE(单词编码, p);
    }
    返回 0;
}

/* ------------------------------------------------------------------------- */