TCC(TinyC)编译器汉化(中文编译器、汉语编程)之一:主文件汉化
程序员文章站
2022-03-30 20:21:35
...
一直想学习编译器,偶然的机会接触到TCC(TinyC)编译器源码。分析源代码是学习一个项目的最好的学习途径之一。自己最爱的母语—中文(汉语或华语)竟然没有一个编译器。果断自己汉化一个。现将汉化源码分享出来。可以实现编译器自举(自我迭代)。
特别声明:本编译器基于tcc(TCC - Tiny C Compiler。 Copyright © 2001-2004 Fabrice Bellard)优化汉化。
zhi.c完整源码如下:
#导入 "zhi.h"
#如果 是_源文件
# 导入 "hexinku.c"
#结束如果
#导入 "工具集.c"
/*****************************帮助*****************************/
静态 常量 字符型 帮助[] =
"————————————————————————————————————————————————\n"
" 知心编译器 "ZHI_VERSION" - 版权 (C) 2020-2020 Fabrice Bellard \n"
"————————————————————————————————————————————————\n"
" 用法: zhi [选项...] [-o 输出文件] [-c] 输入文件...\n"
" zhi [选项...] -run 输入文件 [参数...]\n"
"————————————————————————————————————————————————\n"
"常规指令:\n"
" -c 仅编译-生成目标文件(zhi -c 文件名.c -o 文件名.o)\n"
" -o outfile 设置输出文件名(zhi 文件名.c -o 文件名.exe)\n"
" -run run 编译源文件。\n"
" -fflag 设置或重置 (带“ no-”前缀)“ flag”(详见zhi -hh)\n"
" -std=c99 符合ISO 1999 C标准 (默认).\n"
" -std=c11 符合ISO 2011 C标准.\n"
" -Wwarning 设置或重置 (带“ no-”前缀)“警告”(请参见zhi -hh)\n"
" -w 禁用所有警告\n"
" -version/-v 显示版本信息\n"
" -vv 显示搜索路径或加载的文件\n"
" -h -hh 显示帮助,显示更多帮助\n"
" -bench 显示编译统计\n"
" -帮助/-about 显示关于知心编译器的信息\n"
" - use stdin pipe as infile\n"
" @listfile 从列表文件读取参数\n"
"————————————————————————————————————————————————\n"
"预处理指令:\n"
" -Idir 添加包含路径“ dir”\n"
" -Dsym[=val] 用值'val'def'sym'\n"
" -Usym 未定义的 'sym'\n"
" -E 仅预处理(zhi -E 文件名.c -o 文件名.i)\n"
"————————————————————————————————————————————————\n"
"链接器指令:\n"
" -Ldir 添加库路径“ dir”\n"
" -llib 与动态或静态库“ lib”链接\n"
" -r 生成(可重定位)目标文件\n"
" -shared 生成共享库/ dll。(zhi -shared dll.c,生成dll.dll文件。).\n"
" -rdynamic 将所有全局符号导出到动态链接器\n"
" -soname 设置要在运行时使用的共享库的名称\n"
" -Wl,-opt[=val] 设置链接器选项(请参见zhi -hh)\n"
"————————————————————————————————————————————————\n"
"调试器指令:\n"
" -g 生成运行时调试信息\n"
#如果已定义 配置_ZHI_边界检查
" -b 使用内置内存和边界检查器进行编译(隐含-g)\n"
#结束如果
#如果已定义 ZHI_配置_记录回滚
" -bt[N] 与backtrace链接(堆栈转储)支持[显示最多N个调用者]\n"
#结束如果
"————————————————————————————————————————————————\n"
"综合指令:\n"
" -x[c|a|b|n] 指定下一个文件的类型(C,ASM,BIN,NONE)\n"
" -nostdinc 不使用标准系统包含路径\n"
" -nostdlib 不与标准crt和库链接\n"
" -Bdir 设置zhi的私有include / library目录\n"
" -MD 生成make的依赖文件\n"
" -MF file 指定依赖文件名\n"
#如果 已定义(ZHI_TARGET_I386) || 已定义(ZHI_TARGET_X86_64)
" -m32/64 遵循i386 / x86_64交叉编译器\n"
#结束如果
"————————————————————————————————————————————————\n"
"工具:\n"
" 创建库 : zhi -ar [rcsv] lib.a 文件\n"
#如果已定义 ZHI_TARGET_PE
" 创建定义文件: zhi -impdef lib.dll [-v] [-o lib.def]\n"
#结束如果
"————————————————————————————————————————————————\n"
"特殊指令:\n"
" -P -P1 使用-E:无/替代#line输出\n"
" -dD -dM 使用-E:输出#define指令\n"
" -pthread 与-D_REENTRANT和-lpthread相同\n"
" -On 与-D__OPTIMIZE__对于n相同 > 0\n"
" -Wp,-opt 与-opt相同\n"
" -include file 在每个输入文件上方包含“文件”\n"
" -isystem dir 将'dir'添加到系统包含路径\n"
" -static 链接到静态库(不推荐)\n"
" -dumpversion 印刷版\n"
" -print-search-dirs 打印搜索路径\n"
" -dt 使用-run / -E:自动定义“ test _...”宏\n"
"————————————————————————————————————————————————\n"
"忽略的指令:\n"
" --param -pedantic -pipe -s -traditional\n"
"-W... 警告:\n"
" all 打开一些(*)警告\n"
" error 第一次警告后停止\n"
" unsupported 警告有关被忽略的选项,编译指示等。\n"
" write-strings 字符串是常量\n"
" implicit-function-declaration 警告缺少原型 (*)\n"
"-f[no-]... 标记:\n"
" 无符号-字符型 默认字符是无符号的\n"
" signed-字符型 默认字符已签名\n"
" common 使用公共部分而不是bss\n"
" leading-underscore 修饰外部符号\n"
" ms-extensions 在结构中允许匿名结构\n"
" dollars-in-identifiers 在C符号中允许使用'$'\n"
"-m... 针对特定选项:\n"
" ms-bitfields 使用MSVC位域布局\n"
#如果已定义 ZHI_TARGET_ARM
" float-abi hard/softfp on arm\n"
#结束如果
#如果已定义 ZHI_TARGET_X86_64
" no-sse 在x86_64上禁用浮动\n"
#结束如果
"————————————————————————————————————————————————\n"
"-Wl,... 连接器指令:\n"
" -nostdlib 不要与标准crt / libs链接\n"
" -[no-]whole-archive 完全/仅根据需要加载库\n"
" -export-all-symbols 与-rdynamic相同\n"
" -export-dynamic 与-rdynamic相同\n"
" -image-base= -Ttext= 设置可执行文件的基地址\n"
" -section-alignment= 在可执行文件中设置节对齐\n"
#如果已定义 ZHI_TARGET_PE
" -file-alignment= 设置PE文件对齐\n"
" -stack= 设置PE堆栈储备\n"
" -large-address-aware 设置相关的PE选项\n"
" -subsystem=[console/windows] 设置PE子系统\n"
" -oformat=[pe-* binary] 设置可执行输出格式\n"
"————————————————————————————————————————————————\n"
"预定义的宏:\n"
" zhi -E -dM - < nul\n"
#否则
" -rpath= 设置动态库搜索路径\n"
" -enable-new-dtags 设置DT_RUNPATH而不是DT_RPATH\n"
" -soname= 设置DT_SONAME elf标签\n"
" -Bsymbolic 设置DT_SYMBOLIC elf标签\n"
" -oformat=[elf32/64-* binary] 设置可执行输出格式\n"
" -init= -fini= -as-needed -O (忽略)\n"
"————————————————————————————————————————————————\n"
"预定义的宏:\n"
" zhi -E -dM - < /dev/null\n"
#结束如果
"————————————————————————————————————————————————\n"
"另请参见知心编译器手册以获取更多详细信息.\n"
"————————————————————————————————————————————————\n"
;
静态 常量 字符型 关于[] =
" 知心编译器是完全支持中文(汉语或华语)的全中文编译器,可跨平台(windows和linux)。\n"
" 目标:为中文提供更好的中文编程开源编译器,编译出的源代码更优化更高效。\n"
" 知心编译器、知音IDE和知意server共同构建完善的编程环境。开源编译器源码下载。\n"
" 特别声明:本编译器基于tcc(TCC - Tiny C Compiler。 Copyright (c) 2001-2004 Fabrice Bellard)优化汉化。\n"
" 为编译器学习爱好者提供更好的完整的开源的中文编译器。\n"
" 邮 箱:[email protected] \n"
" 码云:https://gitee.com/zhi-yu-yan/zhixin.git\n"
;
静态 常量 字符型 版本信息[] =
"zhi 版本 "ZHI_VERSION" ("
#如果已定义 ZHI_TARGET_I386
"i386"
#否则如果 已定义 ZHI_TARGET_X86_64
"x86_64"
#否则如果 已定义 ZHI_TARGET_C67
"C67"
#否则如果 已定义 ZHI_TARGET_ARM
"ARM"
#否则如果 已定义 ZHI_TARGET_ARM64
"AArch64"
#否则如果 已定义 ZHI_TARGET_RISCV64
"riscv64"
#结束如果
#如果已定义 ZHI_ARM_HARDFLOAT
" Hard Float"
#结束如果
#如果已定义 ZHI_TARGET_PE
" Windows"
#否则如果 已定义(ZHI_TARGET_MACHO)
" Darwin"
#否则如果 已定义(__FreeBSD__) || 已定义(__FreeBSD_kernel__)
" FreeBSD"
#否则
" Linux"
#结束如果
")\n"
;
静态 无类型 打印_目录(常量 字符型 *目录类型, 字符型 **paths, 整数型 数量_paths)
{
整数型 i;
printf("%s:\n%s", 目录类型, 数量_paths ? "" : " -\n");
循环(i = 0; i < 数量_paths; i++)
printf(" %s\n", paths[i]);
}
静态 无类型 打印搜索目录(知心状态机 *s)
{
printf("安装路径: %s\n", s->zhi_库_路径);
打印_目录("文件导入路径", s->系统包含_路径, s->数量_系统包含_路径);
打印_目录("动态库路径", s->库_路径, s->数量_库_路径);
#如果已定义 ZHI_TARGET_PE
printf("hexinku1:\n %s/lib/"ZHI_HEXINKU1"\n", s->zhi_库_路径);
#否则
printf("hexinku1:\n %s/"ZHI_HEXINKU1"\n", s->zhi_库_路径);
打印_目录("crt", s->crt_路径, s->数量_crt_路径);
printf("elfinterp:\n %s\n", 默认_ELF解释程序路径(s));
#结束如果
}
静态 无类型 设置系统环境变量(知心状态机 *s)
{
字符型 * path;
/*该函数返回一个以 null 结尾的字符串,该字符串为被请求环境变量的值。如果该环境变量不存在,则返回 NULL。
* 函数是一个用于获取环境变量的函数,根据提供不同的参数可以获取不同的环境变量*/
path = getenv("C_INCLUDE_PATH");
如果(path != NULL) {
添加到系统包含路径(s, path);
}
path = getenv("CPATH");
如果(path != NULL) {
添加包含路径(s, path);
}
path = getenv("LIBRARY_PATH");
如果(path != NULL) {
添加库路径(s, path);
}
}
静态 字符型 *默认_输出文件获取扩展名(知心状态机 *s, 常量 字符型 *源文件)
{
字符型 buf[1024];
字符型 *扩展名;
常量 字符型 *name = "a";
如果 (源文件 && strcmp(源文件, "-"))
name = 取_文件基本名(源文件);
snprintf(buf, 取大小(buf), "%s", name);
扩展名 = 取_文件扩展名(buf);
#如果已定义 ZHI_TARGET_PE
如果 (s->输出_类型 == ZHI_输出_DLL)
strcpy(扩展名, ".dll");
否则
如果 (s->输出_类型 == ZHI_输出_EXE)
strcpy(扩展名, ".exe");
否则
#结束如果
如果 (s->输出_类型 == ZHI_输出_目标文件 && !s->选项_可重定位目标文件 && *扩展名)
strcpy(扩展名, ".o");
否则
strcpy(buf, "a.out");
返回 字符串_宽度加1(buf);
}
静态 无符号 获取时钟毫秒数(无类型)
{
#如果已定义 _WIN32
返回 GetTickCount();
#否则
结构体 timeval tv;
gettimeofday(&tv, NULL);
返回 tv.tv_sec*1000 + (tv.tv_usec+500)/1000;
#结束如果
}
整数型 主函数(整数型 参数数量, 字符型 **参数数组)
{
知心状态机 *状态机, *状态机1; /*s1不能换成其他名称,对其他文件有依赖*/
整数型 返回值, 编译指令, n = 0, 测试 = 0, 完成;
无符号 开始_时间 = 0;
常量 字符型 *源文件;
整数型 参数数量0; 字符型 **参数数组0;
FILE *打开的文件流 = stdout;/*FILE在stdio.h里的结构体;stdout,在stdio.h里的宏扩展,*/
重复执行:
参数数量0 = 参数数量, 参数数组0 = 参数数组;
状态机 = 状态机1 = 初始化状态机();
编译指令 = 解析命令行参数(状态机, &参数数量0, &参数数组0, 1);
/*****************************解析命令行参数结果处理,结束于:第79行*****************************/
如果 (n == 0) {
如果 (编译指令 == 指令_HELP)
{
fputs(帮助, stdout);
如果 (!状态机->显示信息)
返回 0;
++编译指令;
}
如果 (编译指令 == 指令_ABOUT)
{
fputs(关于, stdout);
返回 0;
}
如果 (编译指令 == 指令_M32 || 编译指令 == 指令_M64)
编译器工具交叉(状态机, 参数数组0, 编译指令); /* 提示无法运行:“无法运行i386-win32-zhi.exe” */
如果 (状态机->显示信息)
printf(版本信息);
如果 (编译指令 == 指令_AR)
返回 创建静态库文件(状态机, 参数数量0, 参数数组0);
#如果已定义 ZHI_TARGET_PE
如果 (编译指令 == 指令_IMPDEF)
返回 创建定义文件(状态机, 参数数量0, 参数数组0);
#结束如果
如果 (编译指令 == 指令_V)
返回 0;
如果 (编译指令 == 指令_打印_目录)
{
设置系统环境变量(状态机);
设置输出类型(状态机, ZHI_输出_内存中运行);
打印搜索目录(状态机);
返回 0;
}
如果 (状态机->数量_文件数 == 0)
错误_打印("没有输入文件\n");
如果 (状态机->输出_类型 == ZHI_输出_预处理)
{
如果 (状态机->输出文件 && 0!=strcmp("-",状态机->输出文件))
{
打开的文件流 = fopen(状态机->输出文件, "w");/*fopen()打开“状态机->输出文件”文件,进行写操作。w:只允许写;r:只允许读;rb:只允许按照二进制读;wb:只允许二进制写*/
如果 (!打开的文件流)
错误_打印("无法写 '%s'", 状态机->输出文件);
}
} 否则 如果 (状态机->输出_类型 == ZHI_输出_目标文件 && !状态机->选项_可重定位目标文件)
{
如果 (状态机->数量_库数)
错误_打印("无法使用-c指定库");
如果 (状态机->数量_文件数 > 1 && 状态机->输出文件)
错误_打印("无法使用-c指定输出文件");
}
如果 (状态机->显示_编译统计)
开始_时间 = 获取时钟毫秒数();
}
/*****************************解析命令行参数结果处理,结束于:第29行*****************************/
设置系统环境变量(状态机);
如果 (状态机->输出_类型 == 0)
状态机->输出_类型 = ZHI_输出_EXE;
设置输出类型(状态机, 状态机->输出_类型);
状态机->预处理输出文件 = 打开的文件流;
如果 ((状态机->输出_类型 == ZHI_输出_内存中运行|| 状态机->输出_类型 == ZHI_输出_预处理)&& (状态机->DX标号 & 16))
{ /* -dt 选项 */
如果 (测试)
状态机->DX标号 |= 32;
状态机->运行_测试 = ++测试;
如果 (n)
--n;
}
/* 编译或添加每个文件或库 */
源文件 = NULL, 返回值 = 0;
执行
{
文件名称类型结构 *文件 = 状态机->文件数[n];
状态机->文件类型 = 文件->类型;
如果 (文件->类型 & 文件格式_类型_库)
{
如果 (添加库错误(状态机, 文件->名称) < 0)
返回值 = 1;
} 否则
{
如果 (1 == 状态机->显示信息)
printf("-> %s\n", 文件->名称);
如果 (!源文件)
源文件 = 文件->名称;
如果 (添加文件(状态机, 文件->名称) < 0)//添加读取文件流,开始编译文件。
返回值 = 1;
}
完成 = 返回值 || ++n >= 状态机->数量_文件数;
} 判断 (!完成 && (状态机->输出_类型 != ZHI_输出_目标文件 || 状态机->选项_可重定位目标文件));
如果(状态机->运行_测试)
{
测试 = 0;
}
否则 如果 (状态机->输出_类型 == ZHI_输出_预处理)
{
;
}
否则 如果 (0 == 返回值)
{
如果 (状态机->输出_类型 == ZHI_输出_内存中运行)
{
#如果已定义 ZHI_是_本机
返回值 = ZHI_运行(状态机, 参数数量0, 参数数组0);//运行脚本执行的这句
#结束如果
}
否则
{
如果 (!状态机->输出文件)
状态机->输出文件 = 默认_输出文件获取扩展名(状态机, 源文件);
如果 (输出可执行文件或库文件或目标文件(状态机, 状态机->输出文件))
返回值 = 1;
否则 如果 (状态机->生成_依赖)
生成_makedeps(状态机, 状态机->输出文件, 状态机->依赖_输出文件);
}
}
如果 (状态机->显示_编译统计 && 完成 && !(测试 | 返回值))
显示编译统计信息(状态机, 获取时钟毫秒数() - 开始_时间);
释放状态机(状态机);
如果 (!完成)
去向 重复执行; /* 用-c编译更多文件 */
如果 (测试)
去向 重复执行; /* 使用-dt -run运行更多测试 */
如果 (打开的文件流 && 打开的文件流 != stdout)
fclose(打开的文件流);
返回 返回值;
}
上一篇: Java 运行 bat 文件
下一篇: 【bat】以bat文件运行jar文件
推荐阅读
-
TCC(TinyC)编译器汉化(中文编译器、汉语编程)之四:语法分析上
-
TCC(TinyC)编译器汉化(中文编译器、汉语编程)之三:词法分析
-
TCC(TinyC)编译器汉化(中文编译器、汉语编程)之二:字符(token)汉化
-
TCC(TinyC)编译器汉化(中文编译器、汉语编程)之九:核心库源码
-
TCC(TinyC)编译器汉化(中文编译器、汉语编程)之七:中间语言生成器
-
TCC(TinyC)编译器汉化(中文编译器、汉语编程)之六:中间操作码
-
TCC(TinyC)编译器汉化(中文编译器、汉语编程)之八:汇编处理
-
TCC(TinyC)编译器汉化(中文编译器、汉语编程)之一:主文件汉化
-
TCC(TinyC)编译器汉化(中文编译器、汉语编程)之五:语法分析下