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

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(打开的文件流);
	    返回 返回值;
}