├── .github └── workflows │ ├── cmake.yml │ └── make.yml ├── .gitignore ├── CMakeLists.txt ├── LICENSE ├── Makefile ├── README.md ├── codegen.c ├── hashmap.c ├── include ├── float.h ├── stdalign.h ├── stdarg.h ├── stdatomic.h ├── stdbool.h ├── stddef.h └── stdnoreturn.h ├── main.c ├── parse.c ├── preprocess.c ├── rvcc.h ├── string.c ├── test ├── alignof.c ├── alloca.c ├── arith.c ├── asm.c ├── atomic.c ├── attribute.c ├── bitfield.c ├── builtin.c ├── cast.c ├── common ├── commonsym.c ├── compat.c ├── complit.c ├── const.c ├── constexpr.c ├── control.c ├── decl.c ├── driver.sh ├── enum.c ├── extern.c ├── float.c ├── function.c ├── generic.c ├── include1.h ├── include2.h ├── include3.h ├── include4.h ├── initializer.c ├── line.c ├── literal.c ├── macro.c ├── offsetof.c ├── pointer.c ├── pragma-once.c ├── sizeof.c ├── stdhdr.c ├── string.c ├── struct.c ├── test.h ├── thirdparty │ ├── common │ ├── cpython.sh │ ├── git.sh │ ├── libpng.sh │ ├── lua.sh │ ├── sqlite.sh │ └── tinycc.sh ├── tls.c ├── typedef.c ├── typeof.c ├── unicode.c ├── union.c ├── usualconv.c ├── varargs.c ├── variable.c └── vla.c ├── tokenize.c ├── type.c └── unicode.c /.github/workflows/cmake.yml: -------------------------------------------------------------------------------- 1 | name: CMake Build RVCC 2 | 3 | on: 4 | # 推送时进行测试main分支 5 | push: 6 | branches: [ "*" ] 7 | # 发起PR时进行测试main分支 8 | pull_request: 9 | branches: [ "*" ] 10 | 11 | env: 12 | # 自定义构建的程序类型 13 | BUILD_TYPE: Release 14 | 15 | jobs: 16 | build: 17 | # 选择构建RVCC基于的操作系统 18 | runs-on: ${{ matrix.os }} 19 | strategy: 20 | matrix: 21 | os: [ubuntu-latest, macos-latest] 22 | 23 | steps: 24 | # 执行checkout操作 25 | - uses: actions/checkout@v3 26 | 27 | - name: Configure CMake 28 | # 执行cmake命令进行构建,-B指定构建的目录,CMAKE_BUILD_TYPE指定构建的程序类型 29 | run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}} 30 | 31 | - name: Build 32 | # 执行构建 33 | run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} 34 | 35 | - name: Test 36 | working-directory: ${{github.workspace}}/build 37 | # 对生成的程序进行测试 38 | run: ctest -C ${{env.BUILD_TYPE}} 39 | -------------------------------------------------------------------------------- /.github/workflows/make.yml: -------------------------------------------------------------------------------- 1 | name: Make Build RVCC 2 | 3 | on: 4 | # 推送时进行测试main分支 5 | push: 6 | branches: [ "*" ] 7 | # 发起PR时进行测试main分支 8 | pull_request: 9 | branches: [ "*" ] 10 | 11 | jobs: 12 | build: 13 | # 选择构建RVCC基于的操作系统 14 | runs-on: ${{ matrix.os }} 15 | strategy: 16 | matrix: 17 | os: [ubuntu-latest, macos-latest] 18 | 19 | steps: 20 | # 执行checkout操作 21 | - uses: actions/checkout@v3 22 | # 执行构建 23 | - name: make 24 | run: make 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # 日志文件 2 | # *表示当前路径下的任意字符 3 | *.log 4 | 5 | # 可重定位文件,C编译过程的中间文件,等待被链接成二进制文件 6 | # **表示递归匹配路径下的任意字符 7 | **/*.o 8 | 9 | # 汇编文件 10 | **/*.s 11 | 12 | # 临时文件,文件夹内以tmp开头的文件 13 | /tmp* 14 | 15 | # 编译器默认生成的运行文件名 16 | a.out 17 | 18 | # 第三方程序 19 | /thirdparty 20 | 21 | # 生成的最终的rvcc可执行文件 22 | /rvcc 23 | 24 | # 测试生成的可执行文件 25 | /test/*.exe 26 | 27 | # CMake生成的文件目录 28 | build/ 29 | 30 | # stage2相关文件夹 31 | /stage2 32 | 33 | # IDE相关文件夹 34 | .cache/ 35 | .vscode/ 36 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # cmake最低版本号 2 | cmake_minimum_required( VERSION 3.10.0 ) 3 | 4 | # 项目名称 5 | project( rvcc C ) 6 | 7 | # 可执行文件rvcc的依赖文件 8 | add_executable( rvcc 9 | main.c 10 | preprocess.c 11 | string.c 12 | tokenize.c 13 | parse.c 14 | type.c 15 | codegen.c 16 | unicode.c 17 | hashmap.c 18 | ) 19 | 20 | # 编译参数 21 | target_compile_options(rvcc PRIVATE -std=c11 -g -fno-common) 22 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2022 Shao-Ce SUN & ksco, PLCT Lab 4 | Copyright (c) 2019 Rui Ueyama 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in all 14 | copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 22 | SOFTWARE. 23 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | # C编译器参数:使用C11标准,生成debug信息,禁止将未初始化的全局变量放入到common段 2 | CFLAGS=-std=c11 -g -fno-common -Wall -Wno-switch 3 | # 指定C编译器,来构建项目 4 | CC=gcc 5 | # C源代码文件,表示所有的.c结尾的文件 6 | SRCS=$(wildcard *.c) 7 | # C文件编译生成的未链接的可重定位文件,将所有.c文件替换为同名的.o结尾的文件名 8 | OBJS=$(SRCS:.c=.o) 9 | # test/文件夹的c测试文件 10 | TEST_SRCS=$(wildcard test/*.c) 11 | # test/文件夹的c测试文件编译出的可执行文件 12 | TESTS=$(TEST_SRCS:.c=.exe) 13 | 14 | # Stage 1 15 | 16 | # rvcc标签,表示如何构建最终的二进制文件,依赖于所有的.o文件 17 | # $@表示目标文件,此处为rvcc,$^表示依赖文件,此处为$(OBJS) 18 | rvcc: $(OBJS) 19 | # 将多个*.o文件编译为rvcc 20 | $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) 21 | 22 | # 所有的可重定位文件依赖于rvcc.h的头文件 23 | $(OBJS): rvcc.h 24 | 25 | # 测试标签,运行测试 26 | test/%.exe: rvcc test/%.c 27 | ./rvcc -Iinclude -Itest -I$(RISCV)/sysroot/usr/include -c -o test/$*.o test/$*.c 28 | $(CC) -pthread -o $@ test/$*.o -xc test/common 29 | # $(RISCV)/bin/riscv64-unknown-linux-gnu-gcc -pthread -static -o $@ test/$*.o -xc test/common 30 | 31 | test: $(TESTS) 32 | for i in $^; do echo $$i; ./$$i || exit 1; echo; done 33 | # for i in $^; do echo $$i; $(RISCV)/bin/qemu-riscv64 -L $(RISCV)/sysroot ./$$i || exit 1; echo; done 34 | # for i in $^; do echo $$i; $(RISCV)/bin/spike --isa=rv64gc $(RISCV)/riscv64-unknown-linux-gnu/bin/pk ./$$i || exit 1; echo; done 35 | test/driver.sh ./rvcc 36 | 37 | # 进行全部的测试 38 | test-all: test test-stage2 39 | 40 | # Stage 2 41 | 42 | # 此时构建的stage2/rvcc是RISC-V版本的,跟平台无关 43 | stage2/rvcc: $(OBJS:%=stage2/%) 44 | $(CC) $(CFLAGS) -o $@ $^ $(LDFLAGS) 45 | 46 | # 利用stage1的rvcc去将rvcc的源代码编译为stage2的可重定位文件 47 | stage2/%.o: rvcc %.c 48 | mkdir -p stage2/test 49 | ./rvcc -c -o $(@D)/$*.o $*.c 50 | 51 | # 利用stage2的rvcc去进行测试 52 | stage2/test/%.exe: stage2/rvcc test/%.c 53 | mkdir -p stage2/test 54 | ./stage2/rvcc -Iinclude -Itest -c -o stage2/test/$*.o test/$*.c 55 | $(CC) -pthread -o $@ stage2/test/$*.o -xc test/common 56 | 57 | test-stage2: $(TESTS:test/%=stage2/test/%) 58 | for i in $^; do echo $$i; ./$$i || exit 1; echo; done 59 | test/driver.sh ./stage2/rvcc 60 | 61 | # 测试第三方程序 62 | test-libpng: rvcc 63 | ./test/thirdparty/libpng.sh 64 | 65 | test-sqlite: rvcc 66 | ./test/thirdparty/sqlite.sh 67 | 68 | test-tinycc: rvcc 69 | ./test/thirdparty/tinycc.sh 70 | 71 | test-lua: rvcc 72 | ./test/thirdparty/lua.sh 73 | 74 | test-git: rvcc 75 | ./test/thirdparty/git.sh 76 | 77 | 78 | # 清理标签,清理所有非源代码文件 79 | clean: 80 | rm -rf rvcc tmp* $(TESTS) test/*.s test/*.exe stage2/ thirdparty/ 81 | find * -type f '(' -name '*~' -o -name '*.o' -o -name '*.s' ')' -exec rm {} ';' 82 | 83 | # 伪目标,没有实际的依赖文件 84 | .PHONY: test clean test-stage2 85 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## rvcc 2 | 3 | 本课程基于Rui的[chibicc](https://github.com/rui314/chibicc),@sunshaoce和@ksco将其由原来的X86架构改写为RISC-V 64架构,同时加入了大量的中文注释,并且配有316节对应于每一个commit的课程,帮助读者可以层层推进、逐步深入的学习编译器的构造。 4 | 5 | ### rvcc课程资料 6 | 7 | 课程用到的资料(环境构建,Q&A等)都在[rvcc-course](https://github.com/sunshaoce/rvcc-course)。 8 | 9 | 如需发起Issue或者PR,或者是其他问题,也请访问:https://github.com/sunshaoce/rvcc-course 。 10 | 11 | ### 构建 12 | 项目的构建命令为:`make`。 13 | 14 | (可选)项目使用CMake的构建命令为: 15 | ```shell 16 | cmake -Bbuild . 17 | cd build/ 18 | make 19 | ``` 20 | 21 | ### RISC-V介绍 22 | RISC-V是一个开源的精简指令集,相较于常见的X86、ARM架构,其简单易学,并且发展迅猛。现在已经出现了支持RISC-V的各类设备,未来还将出现RISC-V架构的笔记本电脑,可谓是前景一片光明。 23 | 24 | ### chibicc 25 | 26 | [chibicc](https://github.com/rui314/chibicc)是Rui开发的一个X86架构的迷你编译器。Rui同时也是8cc、9cc、mold、lld等著名项目的主要开发者,chibicc是他最新的编译器项目。chibicc项目以commit为阶段,借助于316个commits实现了一个能够编译Git等项目的C编译器,同时层层深入的课程,也大大降低了难度,帮助更多人来上手chibicc。 27 | 28 | ### TODOs 29 | 30 | 这里记录一些需要修复的问题。 31 | -------------------------------------------------------------------------------- /hashmap.c: -------------------------------------------------------------------------------- 1 | // 本文件是对开放寻址哈希表(Open Addressing Hash Table)的一种实现。 2 | 3 | #include "rvcc.h" 4 | 5 | // 初始哈希表的大小,即哈希表一开始能存储16个键值对 6 | #define INIT_SIZE 16 7 | 8 | // 高容量线,超过70%重新进行哈希计算 9 | #define HIGH_WATERMARK 70 10 | 11 | // 低容量线,超过后会需要扩充空间 12 | #define LOW_WATERMARK 50 13 | 14 | // 表示一个删除掉的哈希键值对 15 | // 插入新元素时,优先选择标记删除的键值对,可以尽量避免增加哈希表的容量 16 | #define TOMBSTONE ((void *)-1) 17 | 18 | // 64位FNV-1哈希算法 19 | // 能对字符串进行高效的哈希值计算 20 | static uint64_t fnvHash(char *S, int Len) { 21 | // FNV初始偏移值(FNV_offset_basis) 22 | uint64_t Hash = 0xCBF29CE484222325; 23 | // 遍历字符串中的每个字节进行计算 24 | for (int I = 0; I < Len; I++) { 25 | // 哈希值乘以FNV质数(FNV_prime,此处为64位的) 26 | Hash *= 0x100000001B3; 27 | // 哈希值与该字节的值进行异或 28 | Hash ^= (unsigned char)S[I]; 29 | } 30 | // 返回最后计算出的哈希值 31 | return Hash; 32 | } 33 | 34 | // 通过删除墓碑标记,为新的键值对开辟空间,并有可能拓展桶大小 35 | static void rehash(HashMap *Map) { 36 | // 计算新哈希表的大小 37 | // 记录当前哈希表中使用的键值对数量 38 | int NKeys = 0; 39 | // 遍历当前哈希表的每个桶 40 | for (int I = 0; I < Map->Capacity; I++) 41 | // 如果当前桶中使用的键值对并且未被标记删除 42 | if (Map->Buckets[I].Key && Map->Buckets[I].Key != TOMBSTONE) 43 | NKeys++; 44 | 45 | // Cap存储新的容量,初始值为当前哈希表的容量 46 | int Cap = Map->Capacity; 47 | // 如果键值对使用数量超过了LOW_WATERMARK,则 48 | while ((NKeys * 100) / Cap >= LOW_WATERMARK) 49 | // 将Cap的值乘以2,这样就能翻倍哈希表的容量 50 | Cap = Cap * 2; 51 | // 若Cap的值不大于0,则终止程序 52 | assert(Cap > 0); 53 | 54 | // 定义一个新的哈希表Map2,并拷贝所有的键值对 55 | HashMap Map2 = {}; 56 | // 为Map2分配足够的内存来存储Cap个桶 57 | Map2.Buckets = calloc(Cap, sizeof(HashEntry)); 58 | // 设置Map2的容量为Cap 59 | Map2.Capacity = Cap; 60 | 61 | // 遍历当前哈希表的每个桶 62 | for (int I = 0; I < Map->Capacity; I++) { 63 | // 指向当前桶 64 | HashEntry *Ent = &Map->Buckets[I]; 65 | // 如果当前桶中存在键值对并且未被标记删除 66 | if (Ent->Key && Ent->Key != TOMBSTONE) 67 | // 将该键值对放入新的哈希表Map2中 68 | hashmapPut2(&Map2, Ent->Key, Ent->KeyLen, Ent->Val); 69 | } 70 | 71 | // 断言Map2中的键值对数量等于NKeys 72 | assert(Map2.Used == NKeys); 73 | // 用新的哈希表Map2替换旧的哈希表 74 | *Map = Map2; 75 | } 76 | 77 | // 判断指定键是否匹配给定的键值对 78 | static bool match(HashEntry *Ent, char *Key, int KeyLen) { 79 | // 键值对不为空,键值对未被标记删除,键值对与指定键长相同 80 | // 键值对的键与指定键相同 81 | return Ent->Key && Ent->Key != TOMBSTONE && Ent->KeyLen == KeyLen && 82 | memcmp(Ent->Key, Key, KeyLen) == 0; 83 | } 84 | 85 | // 获取给定的键在哈希表中的键值对 86 | static HashEntry *getEntry(HashMap *Map, char *Key, int KeyLen) { 87 | // 如果没有桶,则为空 88 | if (!Map->Buckets) 89 | return NULL; 90 | 91 | // 计算键对应的哈希值 92 | uint64_t Hash = fnvHash(Key, KeyLen); 93 | 94 | // 遍历哈希表中的所有桶 95 | for (int I = 0; I < Map->Capacity; I++) { 96 | // 开放寻址,当前位置存不下时,会在相邻位置存储 97 | // 如果当前位置没有匹配到,则加上I的偏移量,进行测试 98 | HashEntry *Ent = &Map->Buckets[(Hash + I) % Map->Capacity]; 99 | // 若当前键值对的键,与所查找的键和键长相同 100 | if (match(Ent, Key, KeyLen)) 101 | return Ent; 102 | // 所有的键值对都遍历完了,则返回空 103 | if (Ent->Key == NULL) 104 | return NULL; 105 | } 106 | unreachable(); 107 | } 108 | 109 | // 若获取到键值对则返回,否则插入键值对后返回 110 | static HashEntry *getOrInsertEntry(HashMap *Map, char *Key, int KeyLen) { 111 | if (!Map->Buckets) { 112 | // 如果哈希表没有初始化,则初始化INIT_SIZE个 113 | Map->Buckets = calloc(INIT_SIZE, sizeof(HashEntry)); 114 | Map->Capacity = INIT_SIZE; 115 | } else if ((Map->Used * 100) / Map->Capacity >= HIGH_WATERMARK) { 116 | // 如果哈希表使用量超过了HIGH_WATERMARK,则重新进行哈希计算 117 | rehash(Map); 118 | } 119 | 120 | // 计算指定键的哈希值 121 | uint64_t Hash = fnvHash(Key, KeyLen); 122 | 123 | // 遍历所有的桶 124 | for (int I = 0; I < Map->Capacity; I++) { 125 | // 开放寻址,当前位置存不下时,会在相邻位置存储 126 | // 如果当前位置没有匹配到,则加上I的偏移量,进行测试 127 | HashEntry *Ent = &Map->Buckets[(Hash + I) % Map->Capacity]; 128 | 129 | // 若当前键值对的键,与所查找的键和键长相同 130 | if (match(Ent, Key, KeyLen)) 131 | return Ent; 132 | 133 | // 若当前键值对的键,被标记删除 134 | // 则赋值后使用该键值对 135 | if (Ent->Key == TOMBSTONE) { 136 | Ent->Key = Key; 137 | Ent->KeyLen = KeyLen; 138 | return Ent; 139 | } 140 | 141 | // 若当前键值对的键,为空 142 | // 则赋值后使用该键值对 143 | if (Ent->Key == NULL) { 144 | Ent->Key = Key; 145 | Ent->KeyLen = KeyLen; 146 | // 增加已使用量的计数 147 | Map->Used++; 148 | return Ent; 149 | } 150 | } 151 | unreachable(); 152 | } 153 | 154 | // 查找哈希表中的键值对 155 | void *hashmapGet(HashMap *Map, char *Key) { 156 | return hashmapGet2(Map, Key, strlen(Key)); 157 | } 158 | 159 | void *hashmapGet2(HashMap *Map, char *Key, int KeyLen) { 160 | // 获取键值对 161 | HashEntry *Ent = getEntry(Map, Key, KeyLen); 162 | // 如果查找到键值对则返回,否则为空 163 | return Ent ? Ent->Val : NULL; 164 | } 165 | 166 | // 插入指定的键值对 167 | void hashmapPut(HashMap *Map, char *Key, void *Val) { 168 | hashmapPut2(Map, Key, strlen(Key), Val); 169 | } 170 | 171 | void hashmapPut2(HashMap *Map, char *Key, int KeyLen, void *Val) { 172 | // 返回或创建键值对 173 | HashEntry *Ent = getOrInsertEntry(Map, Key, KeyLen); 174 | // 修改键值对的值 175 | Ent->Val = Val; 176 | } 177 | 178 | // 标记删除哈希表中的键值对 179 | void hashmapDelete(HashMap *Map, char *Key) { 180 | hashmapDelete2(Map, Key, strlen(Key)); 181 | } 182 | 183 | void hashmapDelete2(HashMap *Map, char *Key, int KeyLen) { 184 | // 查找指定的键值对 185 | HashEntry *Ent = getEntry(Map, Key, KeyLen); 186 | // 若键值对存在,则标记删除 187 | if (Ent) 188 | Ent->Key = TOMBSTONE; 189 | } 190 | 191 | // 用于哈希功能测试的函数 192 | void hashmapTest(void) { 193 | // 新建一个容量为0的哈希表 194 | HashMap *Map = calloc(1, sizeof(HashMap)); 195 | 196 | // 0 - 1000 - 1500 - 1600 - 2000 - 5000 - 6000 - 7000 197 | // | 存在 | 删除 | 存在 | 删除 | 存在 | 空 | 存在 | 198 | for (int I = 0; I < 5000; I++) 199 | hashmapPut(Map, format("key %d", I), (void *)(size_t)I); 200 | for (int I = 1000; I < 2000; I++) 201 | hashmapDelete(Map, format("key %d", I)); 202 | for (int I = 1500; I < 1600; I++) 203 | hashmapPut(Map, format("key %d", I), (void *)(size_t)I); 204 | for (int I = 6000; I < 7000; I++) 205 | hashmapPut(Map, format("key %d", I), (void *)(size_t)I); 206 | 207 | for (int I = 0; I < 1000; I++) 208 | assert((size_t)hashmapGet(Map, format("key %d", I)) == I); 209 | for (int I = 1000; I < 1500; I++) 210 | assert(hashmapGet(Map, "no such key") == NULL); 211 | for (int I = 1500; I < 1600; I++) 212 | assert((size_t)hashmapGet(Map, format("key %d", I)) == I); 213 | for (int I = 1600; I < 2000; I++) 214 | assert(hashmapGet(Map, "no such key") == NULL); 215 | for (int I = 2000; I < 5000; I++) 216 | assert((size_t)hashmapGet(Map, format("key %d", I)) == I); 217 | for (int I = 5000; I < 6000; I++) 218 | assert(hashmapGet(Map, "no such key") == NULL); 219 | for (int I = 6000; I < 7000; I++) 220 | hashmapPut(Map, format("key %d", I), (void *)(size_t)I); 221 | 222 | assert(hashmapGet(Map, "no such key") == NULL); 223 | printf("OK\n"); 224 | } 225 | -------------------------------------------------------------------------------- /include/float.h: -------------------------------------------------------------------------------- 1 | #ifndef __STDFLOAT_H 2 | #define __STDFLOAT_H 3 | 4 | // 浮点数=(+-)精度*基数^指数 5 | 6 | #define DECIMAL_DIG 36 // 浮点类型转换为21位十进制数,而值不变 7 | #define FLT_EVAL_METHOD 0 // 所用类型的范围和精度进行所有运算和常量求值 8 | #define FLT_RADIX 2 // 三种浮点类型指数的基数 9 | #define FLT_ROUNDS 1 // 浮点算术运算向最近的数字进行舍入 10 | 11 | #define FLT_DIG 6 // float有效数字位数 12 | #define FLT_EPSILON 0x1p-23 // float的最小差值 13 | #define FLT_MANT_DIG 24 // 能无精度损失地表示成float的2进制最大位数 14 | #define FLT_MAX 0x1.fffffep+127 // float最大值 15 | #define FLT_MAX_10_EXP 38 // float的10进制指数的最大值 16 | #define FLT_MAX_EXP 128 // float的2进制指数的最大值 17 | #define FLT_MIN 0x1p-126 // float的最小值 18 | #define FLT_MIN_10_EXP -37 // float的10进制指数的最大值 19 | #define FLT_MIN_EXP -125 // float的2进制指数的最小值 20 | #define FLT_TRUE_MIN 0x1p-149 // float的最小正值 21 | 22 | #define DBL_DIG 15 // double有效数字位数 23 | #define DBL_EPSILON 0x1p-52 // 1.0和double的最小差值 24 | #define DBL_MANT_DIG 53 // 能无精度损失地表示成double的2进制最大位数 25 | #define DBL_MAX 0x1.fffffffffffffp+1023 // double最大值 26 | #define DBL_MAX_10_EXP 308 // double的10进制指数的最大值 27 | #define DBL_MAX_EXP 1024 // double的2进制指数的最大值 28 | #define DBL_MIN 0x1p-1022 // double的最小值 29 | #define DBL_MIN_10_EXP -307 // double的10进制指数的最大值 30 | #define DBL_MIN_EXP -1021 // double的2进制指数的最小值 31 | #define DBL_TRUE_MIN 0x0.0000000000001p-1022 // double的最小正值 32 | 33 | #define LDBL_DIG 33 // long double有效数字位数 34 | #define LDBL_EPSILON 0x1p-112 // 1.0和long double的最小差值 35 | #define LDBL_MANT_DIG 113 // 能无精度损失地表示成long double的2进制最大位数 36 | #define LDBL_MAX 0x1.ffffffffffffffffffffffffffffp+16383 // long double最大值 37 | #define LDBL_MAX_10_EXP 4932 // long double的10进制指数的最大值 38 | #define LDBL_MAX_EXP 16384 // long double的2进制指数的最大值 39 | #define LDBL_MIN 0x1p-16382 // long double的最小值 40 | #define LDBL_MIN_10_EXP -4931 // long double的10进制指数的最大值 41 | #define LDBL_MIN_EXP -16381 // long double的2进制指数的最小值 42 | // long double的最小正值 43 | #define LDBL_TRUE_MIN 0x0.0000000000000000000000000001p-16382 44 | 45 | #endif 46 | -------------------------------------------------------------------------------- /include/stdalign.h: -------------------------------------------------------------------------------- 1 | #ifndef __STDALIGN_H 2 | #define __STDALIGN_H 3 | 4 | #define alignas _Alignas 5 | #define alignof _Alignof 6 | #define __alignas_is_defined 1 7 | #define __alignof_is_defined 1 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /include/stdarg.h: -------------------------------------------------------------------------------- 1 | #ifndef __STDARG_H 2 | #define __STDARG_H 3 | 4 | typedef void *va_list; 5 | 6 | #define va_start(ap, last) \ 7 | do { \ 8 | ap = __va_area__; \ 9 | } while (0) 10 | 11 | #define va_end(ap) 12 | 13 | // [196] 支持 va_arg() 14 | #define va_arg(ap, type) \ 15 | ({ \ 16 | type val = *(type *)ap; \ 17 | ap += 8; \ 18 | val; \ 19 | }) 20 | 21 | #define va_copy(dest, src) (dest = src) 22 | 23 | #define __GNUC_VA_LIST 1 24 | typedef va_list __gnuc_va_list; 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /include/stdatomic.h: -------------------------------------------------------------------------------- 1 | #ifndef __STDATOMIC_H 2 | #define __STDATOMIC_H 3 | 4 | #define ATOMIC_BOOL_LOCK_FREE 1 5 | #define ATOMIC_CHAR_LOCK_FREE 1 6 | #define ATOMIC_CHAR16_T_LOCK_FREE 1 7 | #define ATOMIC_CHAR32_T_LOCK_FREE 1 8 | #define ATOMIC_WCHAR_T_LOCK_FREE 1 9 | #define ATOMIC_SHORT_LOCK_FREE 1 10 | #define ATOMIC_INT_LOCK_FREE 1 11 | #define ATOMIC_LONG_LOCK_FREE 1 12 | #define ATOMIC_LLONG_LOCK_FREE 1 13 | #define ATOMIC_POINTER_LOCK_FREE 1 14 | 15 | typedef enum { 16 | memory_order_relaxed, 17 | memory_order_consume, 18 | memory_order_acquire, 19 | memory_order_release, 20 | memory_order_acq_rel, 21 | memory_order_seq_cst, 22 | } memory_order; 23 | 24 | #define ATOMIC_FLAG_INIT(x) (x) 25 | #define atomic_init(addr, val) (*(addr) = (val)) 26 | #define kill_dependency(x) (x) 27 | #define atomic_thread_fence(order) 28 | #define atomic_signal_fence(order) 29 | #define atomic_is_lock_free(x) 1 30 | 31 | #define atomic_load(addr) (*(addr)) 32 | #define atomic_store(addr, val) (*(addr) = (val)) 33 | 34 | #define atomic_load_explicit(addr, order) (*(addr)) 35 | #define atomic_store_explicit(addr, val, order) (*(addr) = (val)) 36 | 37 | #define atomic_fetch_add(obj, val) (*(obj) += (val)) 38 | #define atomic_fetch_sub(obj, val) (*(obj) -= (val)) 39 | #define atomic_fetch_or(obj, val) (*(obj) |= (val)) 40 | #define atomic_fetch_xor(obj, val) (*(obj) ^= (val)) 41 | #define atomic_fetch_and(obj, val) (*(obj) &= (val)) 42 | 43 | #define atomic_fetch_add_explicit(obj, val, order) (*(obj) += (val)) 44 | #define atomic_fetch_sub_explicit(obj, val, order) (*(obj) -= (val)) 45 | #define atomic_fetch_or_explicit(obj, val, order) (*(obj) |= (val)) 46 | #define atomic_fetch_xor_explicit(obj, val, order) (*(obj) ^= (val)) 47 | #define atomic_fetch_and_explicit(obj, val, order) (*(obj) &= (val)) 48 | 49 | #define atomic_compare_exchange_weak(p, old, new) \ 50 | __builtin_compare_and_swap((p), (old), (new)) 51 | 52 | #define atomic_compare_exchange_strong(p, old, new) \ 53 | __builtin_compare_and_swap((p), (old), (new)) 54 | 55 | #define atomic_exchange(obj, val) __builtin_atomic_exchange((obj), (val)) 56 | #define atomic_exchange_explicit(obj, val, order) \ 57 | __builtin_atomic_exchange((obj), (val)) 58 | 59 | #define atomic_flag_test_and_set(obj) atomic_exchange((obj), 1) 60 | #define atomic_flag_test_and_set_explicit(obj, order) atomic_exchange((obj), 1) 61 | #define atomic_flag_clear(obj) (*(obj) = 0) 62 | #define atomic_flag_clear_explicit(obj, order) (*(obj) = 0) 63 | 64 | typedef _Atomic _Bool atomic_flag; 65 | typedef _Atomic _Bool atomic_bool; 66 | typedef _Atomic char atomic_char; 67 | typedef _Atomic signed char atomic_schar; 68 | typedef _Atomic unsigned char atomic_uchar; 69 | typedef _Atomic short atomic_short; 70 | typedef _Atomic unsigned short atomic_ushort; 71 | typedef _Atomic int atomic_int; 72 | typedef _Atomic unsigned int atomic_uint; 73 | typedef _Atomic long atomic_long; 74 | typedef _Atomic unsigned long atomic_ulong; 75 | typedef _Atomic long long atomic_llong; 76 | typedef _Atomic unsigned long long atomic_ullong; 77 | typedef _Atomic unsigned short atomic_char16_t; 78 | typedef _Atomic unsigned atomic_char32_t; 79 | typedef _Atomic unsigned atomic_wchar_t; 80 | typedef _Atomic signed char atomic_int_least8_t; 81 | typedef _Atomic unsigned char atomic_uint_least8_t; 82 | typedef _Atomic short atomic_int_least16_t; 83 | typedef _Atomic unsigned short atomic_uint_least16_t; 84 | typedef _Atomic int atomic_int_least32_t; 85 | typedef _Atomic unsigned int atomic_uint_least32_t; 86 | typedef _Atomic long atomic_int_least64_t; 87 | typedef _Atomic unsigned long atomic_uint_least64_t; 88 | typedef _Atomic signed char atomic_int_fast8_t; 89 | typedef _Atomic unsigned char atomic_uint_fast8_t; 90 | typedef _Atomic short atomic_int_fast16_t; 91 | typedef _Atomic unsigned short atomic_uint_fast16_t; 92 | typedef _Atomic int atomic_int_fast32_t; 93 | typedef _Atomic unsigned int atomic_uint_fast32_t; 94 | typedef _Atomic long atomic_int_fast64_t; 95 | typedef _Atomic unsigned long atomic_uint_fast64_t; 96 | typedef _Atomic long atomic_intptr_t; 97 | typedef _Atomic unsigned long atomic_uintptr_t; 98 | typedef _Atomic unsigned long atomic_size_t; 99 | typedef _Atomic long atomic_ptrdiff_t; 100 | typedef _Atomic long atomic_intmax_t; 101 | typedef _Atomic unsigned long atomic_uintmax_t; 102 | 103 | #endif 104 | -------------------------------------------------------------------------------- /include/stdbool.h: -------------------------------------------------------------------------------- 1 | #ifndef __STDBOOL_H 2 | #define __STDBOOL_H 3 | 4 | #define bool _Bool 5 | #define true 1 6 | #define false 0 7 | #define __bool_true_false_are_defined 1 8 | 9 | #endif 10 | -------------------------------------------------------------------------------- /include/stddef.h: -------------------------------------------------------------------------------- 1 | #ifndef __STDDEF_H 2 | #define __STDDEF_H 3 | 4 | #define NULL ((void *)0) 5 | 6 | typedef unsigned long size_t; 7 | typedef long ptrdiff_t; 8 | typedef unsigned int wchar_t; 9 | typedef long max_align_t; 10 | 11 | #define offsetof(type, member) ((size_t) & (((type *)0)->member)) 12 | 13 | #endif 14 | -------------------------------------------------------------------------------- /include/stdnoreturn.h: -------------------------------------------------------------------------------- 1 | #ifndef __STDNORETURN_H 2 | #define __STDNORETURN_H 3 | 4 | #define noreturn _Noreturn 5 | 6 | #endif 7 | -------------------------------------------------------------------------------- /main.c: -------------------------------------------------------------------------------- 1 | #include "rvcc.h" 2 | 3 | // 【注意】 4 | // 如果是交叉编译,请把这个路径改为$RISCV对应的路径 5 | // 注意 ~ 应替换为具体的 /home/用户名 的路径 6 | static char *RVPath = ""; 7 | 8 | // 文件类型 9 | typedef enum { 10 | FILE_NONE, // 空类型 11 | FILE_C, // C语言源代码类型 12 | FILE_ASM, // 汇编代码类型 13 | FILE_OBJ, // 可重定位文件类型 14 | FILE_AR, // 静态库文件类型 15 | FILE_DSO, // 动态库文件类型 16 | } FileType; 17 | 18 | // 引入路径区 19 | StringArray IncludePaths; 20 | // common块默认生成 21 | bool OptFCommon = true; 22 | // 位置无关代码的标记 23 | bool OptFPIC; 24 | 25 | // -x选项 26 | static FileType OptX; 27 | // -include所引入的文件 28 | static StringArray OptInclude; 29 | // -E选项 30 | static bool OptE; 31 | // -M选项 32 | static bool OptM; 33 | // -MD选项 34 | static bool OptMD; 35 | // -MMD选项 36 | static bool OptMMD; 37 | // -MP选项 38 | static bool OptMP; 39 | // -S选项 40 | static bool OptS; 41 | // -c选项 42 | static bool OptC; 43 | // cc1选项 44 | static bool OptCC1; 45 | // ###选项 46 | static bool OptHashHashHash; 47 | //-static选项 48 | static bool OptStatic; 49 | // -shared选项 50 | static bool OptShared; 51 | // -MF选项 52 | static char *OptMF; 53 | // -MT选项 54 | static char *OptMT; 55 | // 目标文件的路径 56 | static char *OptO; 57 | 58 | // 链接器额外参数 59 | static StringArray LdExtraArgs; 60 | // 标准库所引入的路径,用于-MMD选项 61 | static StringArray StdIncludePaths; 62 | 63 | // 输入文件名 64 | char *BaseFile; 65 | // 输出文件名 66 | static char *OutputFile; 67 | 68 | // 输入文件区 69 | static StringArray InputPaths; 70 | // 临时文件区 71 | static StringArray TmpFiles; 72 | 73 | // 输出程序的使用说明 74 | static void usage(int Status) { 75 | fprintf(stderr, "rvcc [ -o ] \n"); 76 | exit(Status); 77 | } 78 | 79 | // 判断需要一个参数的选项,是否具有一个参数 80 | static bool takeArg(char *Arg) { 81 | char *X[] = {"-o", "-I", "-idirafter", "-include", 82 | "-x", "-MF", "-MT", "-Xlinker"}; 83 | 84 | for (int I = 0; I < sizeof(X) / sizeof(*X); I++) 85 | if (!strcmp(Arg, X[I])) 86 | return true; 87 | return false; 88 | } 89 | 90 | // 增加默认引入路径 91 | static void addDefaultIncludePaths(char *Argv0) { 92 | // rvcc特定的引入文件被安装到了argv[0]的./include位置 93 | strArrayPush(&IncludePaths, format("%s/include", dirname(strdup(Argv0)))); 94 | 95 | // 支持标准的引入路径 96 | strArrayPush(&IncludePaths, "/usr/local/include"); 97 | strArrayPush(&IncludePaths, "/usr/include/riscv64-linux-gnu"); 98 | strArrayPush(&IncludePaths, "/usr/include"); 99 | 100 | // 为-MMD选项,复制一份标准库引入路径 101 | for (int I = 0; I < IncludePaths.Len; I++) 102 | strArrayPush(&StdIncludePaths, IncludePaths.Data[I]); 103 | } 104 | 105 | // 定义宏 106 | static void define(char *Str) { 107 | char *Eq = strchr(Str, '='); 108 | if (Eq) 109 | // 存在赋值,使用该值 110 | defineMacro(strndup(Str, Eq - Str), Eq + 1); 111 | else 112 | // 不存在赋值,则设为1 113 | defineMacro(Str, "1"); 114 | } 115 | 116 | // 解析-x选项 117 | static FileType parseOptX(char *S) { 118 | // -xc,解析为C语言源代码 119 | if (!strcmp(S, "c")) 120 | return FILE_C; 121 | // -xassembler,解析为汇编源代码 122 | if (!strcmp(S, "assembler")) 123 | return FILE_ASM; 124 | // -xnone,解析为空类型 125 | if (!strcmp(S, "none")) 126 | return FILE_NONE; 127 | error(": unknown argument for -x: %s", S); 128 | } 129 | 130 | // 对Make的目标中的特殊字符进行处理 131 | static char *quoteMakefile(char *S) { 132 | // 新字符串,确保即使S的全部字符都处理,加上'\0'也能够存储下 133 | char *Buf = calloc(1, strlen(S) * 2 + 1); 134 | 135 | // 遍历字符串,对特殊字符进行处理 136 | for (int I = 0, J = 0; S[I]; I++) { 137 | switch (S[I]) { 138 | case '$': 139 | Buf[J++] = '$'; 140 | Buf[J++] = '$'; 141 | break; 142 | case '#': 143 | Buf[J++] = '\\'; 144 | Buf[J++] = '#'; 145 | break; 146 | case ' ': 147 | case '\t': 148 | // 反向遍历反斜杠字符 149 | for (int K = I - 1; K >= 0 && S[K] == '\\'; K--) 150 | Buf[J++] = '\\'; 151 | Buf[J++] = '\\'; 152 | Buf[J++] = S[I]; 153 | break; 154 | default: 155 | Buf[J++] = S[I]; 156 | break; 157 | } 158 | } 159 | // 返回新字符串 160 | return Buf; 161 | } 162 | 163 | // 解析传入程序的参数 164 | static void parseArgs(int Argc, char **Argv) { 165 | // 确保需要一个参数的选项,存在一个参数 166 | for (int I = 1; I < Argc; I++) 167 | // 如果需要一个参数 168 | if (takeArg(Argv[I])) 169 | // 如果不存在一个参数,则打印出使用说明 170 | if (!Argv[++I]) 171 | usage(1); 172 | 173 | // 存储-idirafter的路径参数 174 | StringArray Idirafter = {}; 175 | 176 | // 遍历所有传入程序的参数 177 | for (int I = 1; I < Argc; I++) { 178 | // 解析-### 179 | if (!strcmp(Argv[I], "-###")) { 180 | OptHashHashHash = true; 181 | continue; 182 | } 183 | 184 | // 解析-cc1 185 | if (!strcmp(Argv[I], "-cc1")) { 186 | OptCC1 = true; 187 | continue; 188 | } 189 | 190 | // 如果存在help,则直接显示用法说明 191 | if (!strcmp(Argv[I], "--help")) 192 | usage(0); 193 | 194 | // 解析-o XXX的参数 195 | if (!strcmp(Argv[I], "-o")) { 196 | // 目标文件的路径 197 | OptO = Argv[++I]; 198 | continue; 199 | } 200 | 201 | // 解析-oXXX的参数 202 | if (!strncmp(Argv[I], "-o", 2)) { 203 | // 目标文件的路径 204 | OptO = Argv[I] + 2; 205 | continue; 206 | } 207 | 208 | // 解析-S 209 | if (!strcmp(Argv[I], "-S")) { 210 | OptS = true; 211 | continue; 212 | } 213 | 214 | // // 解析-fcommon 215 | if (!strcmp(Argv[I], "-fcommon")) { 216 | OptFCommon = true; 217 | continue; 218 | } 219 | 220 | // 解析-fno-common 221 | if (!strcmp(Argv[I], "-fno-common")) { 222 | OptFCommon = false; 223 | continue; 224 | } 225 | 226 | // 解析-c 227 | if (!strcmp(Argv[I], "-c")) { 228 | OptC = true; 229 | continue; 230 | } 231 | 232 | // 解析-E 233 | if (!strcmp(Argv[I], "-E")) { 234 | OptE = true; 235 | continue; 236 | } 237 | 238 | // 解析-I 239 | if (!strncmp(Argv[I], "-I", 2)) { 240 | strArrayPush(&IncludePaths, Argv[I] + 2); 241 | continue; 242 | } 243 | 244 | // 解析-D 245 | if (!strcmp(Argv[I], "-D")) { 246 | define(Argv[++I]); 247 | continue; 248 | } 249 | 250 | // 解析-D 251 | if (!strncmp(Argv[I], "-D", 2)) { 252 | define(Argv[I] + 2); 253 | continue; 254 | } 255 | 256 | // 解析-U 257 | if (!strcmp(Argv[I], "-U")) { 258 | undefMacro(Argv[++I]); 259 | continue; 260 | } 261 | 262 | // 解析-U 263 | if (!strncmp(Argv[I], "-U", 2)) { 264 | undefMacro(Argv[I] + 2); 265 | continue; 266 | } 267 | 268 | // 解析-include 269 | if (!strcmp(Argv[I], "-include")) { 270 | strArrayPush(&OptInclude, Argv[++I]); 271 | continue; 272 | } 273 | 274 | // 解析-x 275 | if (!strcmp(Argv[I], "-x")) { 276 | OptX = parseOptX(Argv[++I]); 277 | continue; 278 | } 279 | 280 | // 解析-x 281 | if (!strncmp(Argv[I], "-x", 2)) { 282 | OptX = parseOptX(Argv[I] + 2); 283 | continue; 284 | } 285 | 286 | // 解析-l、-Wl, 287 | if (!strncmp(Argv[I], "-l", 2) || !strncmp(Argv[I], "-Wl,", 4)) { 288 | strArrayPush(&InputPaths, Argv[I]); 289 | continue; 290 | } 291 | 292 | // 解析-Xlinker 293 | if (!strcmp(Argv[I], "-Xlinker")) { 294 | strArrayPush(&LdExtraArgs, Argv[++I]); 295 | continue; 296 | } 297 | 298 | // 解析-s 299 | if (!strcmp(Argv[I], "-s")) { 300 | strArrayPush(&LdExtraArgs, "-s"); 301 | continue; 302 | } 303 | 304 | // 解析-M 305 | if (!strcmp(Argv[I], "-M")) { 306 | OptM = true; 307 | continue; 308 | } 309 | 310 | // 解析-MF 311 | if (!strcmp(Argv[I], "-MF")) { 312 | OptMF = Argv[++I]; 313 | continue; 314 | } 315 | 316 | // 解析-MP 317 | if (!strcmp(Argv[I], "-MP")) { 318 | OptMP = true; 319 | continue; 320 | } 321 | 322 | // 解析-MT 323 | // `-MT File`,指定File为依赖规则中的目标 324 | if (!strcmp(Argv[I], "-MT")) { 325 | if (OptMT == NULL) 326 | // 无依赖规则中的目标 327 | OptMT = Argv[++I]; 328 | else 329 | // 合并依赖规则中的目标 330 | OptMT = format("%s %s", OptMT, Argv[++I]); 331 | continue; 332 | } 333 | 334 | // 解析-MD 335 | if (!strcmp(Argv[I], "-MD")) { 336 | OptMD = true; 337 | continue; 338 | } 339 | 340 | // 解析-MQ 341 | if (!strcmp(Argv[I], "-MQ")) { 342 | if (OptMT == NULL) 343 | // 无依赖规则中的目标 344 | OptMT = quoteMakefile(Argv[++I]); 345 | else 346 | // 合并依赖规则中的目标 347 | OptMT = format("%s %s", OptMT, quoteMakefile(Argv[++I])); 348 | continue; 349 | } 350 | 351 | // 解析-MMD 352 | if (!strcmp(Argv[I], "-MMD")) { 353 | // 同时启用-MD选项 354 | OptMD = OptMMD = true; 355 | continue; 356 | } 357 | 358 | // 解析-fpic或-fPIC 359 | if (!strcmp(Argv[I], "-fpic") || !strcmp(Argv[I], "-fPIC")) { 360 | OptFPIC = true; 361 | continue; 362 | } 363 | 364 | // 解析-cc1-input 365 | if (!strcmp(Argv[I], "-cc1-input")) { 366 | BaseFile = Argv[++I]; 367 | continue; 368 | } 369 | 370 | // 解析-cc1-output 371 | if (!strcmp(Argv[I], "-cc1-output")) { 372 | OutputFile = Argv[++I]; 373 | continue; 374 | } 375 | 376 | // 解析-idirafter 377 | // 将参数存入Idirafter 378 | if (!strcmp(Argv[I], "-idirafter")) { 379 | strArrayPush(&Idirafter, Argv[I++]); 380 | continue; 381 | } 382 | 383 | // 解析-static 384 | if (!strcmp(Argv[I], "-static")) { 385 | OptStatic = true; 386 | strArrayPush(&LdExtraArgs, "-static"); 387 | continue; 388 | } 389 | 390 | // 解析-shared 391 | if (!strcmp(Argv[I], "-shared")) { 392 | OptShared = true; 393 | strArrayPush(&LdExtraArgs, "-shared"); 394 | continue; 395 | } 396 | 397 | // 解析-L 398 | if (!strcmp(Argv[I], "-L")) { 399 | strArrayPush(&LdExtraArgs, "-L"); 400 | strArrayPush(&LdExtraArgs, Argv[++I]); 401 | continue; 402 | } 403 | 404 | // 解析-L 405 | if (!strncmp(Argv[I], "-L", 2)) { 406 | strArrayPush(&LdExtraArgs, "-L"); 407 | strArrayPush(&LdExtraArgs, Argv[I] + 2); 408 | continue; 409 | } 410 | 411 | // 哈希表测试 412 | if (!strcmp(Argv[I], "-hashmap-test")) { 413 | hashmapTest(); 414 | exit(0); 415 | } 416 | 417 | // 忽略多个选项 418 | if (!strncmp(Argv[I], "-O", 2) || !strncmp(Argv[I], "-W", 2) || 419 | !strncmp(Argv[I], "-g", 2) || !strncmp(Argv[I], "-std=", 5) || 420 | !strcmp(Argv[I], "-ffreestanding") || 421 | !strcmp(Argv[I], "-fno-builtin") || 422 | !strcmp(Argv[I], "-fno-omit-frame-pointer") || 423 | !strcmp(Argv[I], "-fno-stack-protector") || 424 | !strcmp(Argv[I], "-fno-strict-aliasing") || !strcmp(Argv[I], "-m64") || 425 | !strcmp(Argv[I], "-mno-red-zone") || !strcmp(Argv[I], "-w") || 426 | !strcmp(Argv[I], "-march=native")) 427 | continue; 428 | 429 | // 解析为-的参数 430 | if (Argv[I][0] == '-' && Argv[I][1] != '\0') 431 | error("unknown argument: %s", Argv[I]); 432 | 433 | // 其他情况则匹配为输入文件 434 | strArrayPush(&InputPaths, Argv[I]); 435 | } 436 | 437 | // 将所用Idirafter内的路径,都存入引用路径区中 438 | for (int I = 0; I < Idirafter.Len; I++) 439 | strArrayPush(&IncludePaths, Idirafter.Data[I]); 440 | 441 | // 不存在输入文件时报错 442 | if (InputPaths.Len == 0) 443 | error("no input files"); 444 | 445 | // -E隐式包含输入是C语言的宏 446 | if (OptE) 447 | OptX = FILE_C; 448 | } 449 | 450 | // 打开需要写入的文件 451 | static FILE *openFile(char *Path) { 452 | if (!Path || strcmp(Path, "-") == 0) 453 | return stdout; 454 | 455 | // 以写入模式打开文件 456 | FILE *Out = fopen(Path, "w"); 457 | if (!Out) 458 | error("cannot open output file: %s: %s", Path, strerror(errno)); 459 | return Out; 460 | } 461 | 462 | // 判断字符串P是否以字符串Q结尾 463 | static bool endsWith(char *P, char *Q) { 464 | int len1 = strlen(P); 465 | int len2 = strlen(Q); 466 | // P比Q长且P最后Len2长度的字符和Q相等,则为真 467 | return (len1 >= len2) && !strcmp(P + len1 - len2, Q); 468 | } 469 | 470 | // 替换文件的后缀名 471 | static char *replaceExtn(char *Tmpl, char *Extn) { 472 | // 去除路径,返回基础文件名 473 | char *Filename = basename(strdup(Tmpl)); 474 | // 最后一次字符出现的位置 475 | char *Dot = strrchr(Filename, '.'); 476 | // 如果存在'.',清除此后的内容 477 | if (Dot) 478 | *Dot = '\0'; 479 | // 将新后缀写入文件名中 480 | return format("%s%s", Filename, Extn); 481 | } 482 | 483 | // 清理临时文件区 484 | static void cleanup(void) { 485 | // 遍历删除临时文件 486 | for (int I = 0; I < TmpFiles.Len; I++) 487 | unlink(TmpFiles.Data[I]); 488 | } 489 | 490 | // 创建临时文件 491 | static char *createTmpFile(void) { 492 | // 临时文件的路径格式 493 | char *Path = strdup("/tmp/rvcc-XXXXXX"); 494 | // 创建临时文件 495 | int FD = mkstemp(Path); 496 | // 临时文件创建失败 497 | if (FD == -1) 498 | error("mkstemp failed: %s", strerror(errno)); 499 | // 关闭文件 500 | close(FD); 501 | 502 | // 将文件路径存入临时文件区中 503 | strArrayPush(&TmpFiles, Path); 504 | return Path; 505 | } 506 | 507 | // 开辟子进程 508 | static void runSubprocess(char **Argv) { 509 | // 打印出子进程所有的命令行参数 510 | if (OptHashHashHash) { 511 | // 程序名 512 | fprintf(stderr, "%s", Argv[0]); 513 | // 程序参数 514 | for (int I = 1; Argv[I]; I++) 515 | fprintf(stderr, " %s", Argv[I]); 516 | // 换行 517 | fprintf(stderr, "\n"); 518 | } 519 | 520 | // Fork–exec模型 521 | // 创建当前进程的副本,这里开辟了一个子进程 522 | // 返回-1表示错位,为0表示成功 523 | if (fork() == 0) { 524 | // 执行文件rvcc,没有斜杠时搜索环境变量,此时会替换子进程 525 | execvp(Argv[0], Argv); 526 | // 如果exec函数返回,表明没有正常执行命令 527 | fprintf(stderr, "exec failed: %s: %s\n", Argv[0], strerror(errno)); 528 | _exit(1); 529 | } 530 | 531 | // 父进程, 等待子进程结束 532 | int Status; 533 | while (wait(&Status) > 0) 534 | ; 535 | // 处理子进程返回值 536 | if (Status != 0) 537 | exit(1); 538 | } 539 | 540 | // 执行调用cc1程序 541 | // 因为rvcc自身就是cc1程序 542 | // 所以调用自身,并传入-cc1参数作为子进程 543 | static void runCC1(int Argc, char **Argv, char *Input, char *Output) { 544 | // 多开辟10个字符串的位置,用于传递需要新传入的参数 545 | char **Args = calloc(Argc + 10, sizeof(char *)); 546 | // 将传入程序的参数全部写入Args 547 | memcpy(Args, Argv, Argc * sizeof(char *)); 548 | // 在选项最后新加入"-cc1"选项 549 | Args[Argc++] = "-cc1"; 550 | 551 | // 存入输入文件的参数 552 | if (Input) { 553 | Args[Argc++] = "-cc1-input"; 554 | Args[Argc++] = Input; 555 | } 556 | 557 | // 存入输出文件的参数 558 | if (Output) { 559 | Args[Argc++] = "-cc1-output"; 560 | Args[Argc++] = Output; 561 | } 562 | 563 | // 运行自身作为子进程,同时传入选项 564 | runSubprocess(Args); 565 | } 566 | 567 | // 当指定-E选项时,打印出所有终结符 568 | static void printTokens(Token *Tok) { 569 | // 输出文件,默认为stdout 570 | FILE *Out = openFile(OptO ? OptO : "-"); 571 | 572 | // 记录行数 573 | int Line = 1; 574 | // 遍历读取终结符 575 | for (; Tok->Kind != TK_EOF; Tok = Tok->Next) { 576 | // 位于行首打印出换行符 577 | if (Line > 1 && Tok->AtBOL) 578 | fprintf(Out, "\n"); 579 | // 打印出需要空格的位置 580 | if (Tok->HasSpace && !Tok->AtBOL) 581 | fprintf(Out, " "); 582 | // 打印出终结符 583 | fprintf(Out, "%.*s", Tok->Len, Tok->Loc); 584 | Line++; 585 | } 586 | // 文件以换行符结尾 587 | fprintf(Out, "\n"); 588 | } 589 | 590 | // 判断是否为标准库路径 591 | static bool inStdIncludePath(char *Path) { 592 | for (int I = 0; I < StdIncludePaths.Len; I++) { 593 | char *Dir = StdIncludePaths.Data[I]; 594 | int Len = strlen(Dir); 595 | // 与库路径相同,且以斜杠结尾 596 | if (strncmp(Dir, Path, Len) == 0 && Path[Len] == '/') 597 | return true; 598 | } 599 | return false; 600 | } 601 | 602 | // 输出可用于Make的规则,自动化文件依赖管理 603 | static void printDependencies(void) { 604 | char *Path; 605 | if (OptMF) 606 | // 将Make的规则写入`-MF File`的File中 607 | Path = OptMF; 608 | else if (OptMD) 609 | // 相当于`-M -MF File.d`,将Make的规则写入.d文件 610 | Path = replaceExtn(OptO ? OptO : BaseFile, ".d"); 611 | else if (OptO) 612 | Path = OptO; 613 | else 614 | Path = "-"; 615 | 616 | // 输出文件 617 | FILE *Out = openFile(Path); 618 | // 如果未指定-MT,默认需要目标名中的特殊字符处理 619 | if (OptMT) 620 | fprintf(Out, "%s:", OptMT); 621 | else 622 | // -MF指定依赖规则中的目标,否则替换后缀为.o 623 | fprintf(Out, "%s:", quoteMakefile(replaceExtn(BaseFile, ".o"))); 624 | 625 | // 获取输入文件 626 | File **Files = getInputFiles(); 627 | 628 | // 遍历输入文件,并将格式化的结果写入输出文件 629 | for (int I = 0; Files[I]; I++) { 630 | // 不输出标准库内的文件 631 | if (OptMMD && inStdIncludePath(Files[I]->Name)) 632 | continue; 633 | fprintf(Out, " \\\n %s", Files[I]->Name); 634 | } 635 | 636 | fprintf(Out, "\n\n"); 637 | 638 | // 如果指定了-MP,则为头文件生成伪目标 639 | if (OptMP) { 640 | for (int I = 1; Files[I]; I++) { 641 | // 不输出标准库内的文件 642 | if (OptMMD && inStdIncludePath(Files[I]->Name)) 643 | continue; 644 | // 处理头文件中的特殊字符 645 | fprintf(Out, "%s:\n\n", quoteMakefile(Files[I]->Name)); 646 | } 647 | } 648 | } 649 | 650 | // 解析文件,生成终结符流 651 | static Token *mustTokenizeFile(char *Path) { 652 | Token *Tok = tokenizeFile(Path); 653 | // 终结符流生成失败,对应文件报错 654 | if (!Tok) 655 | error("%s: %s", Path, strerror(errno)); 656 | return Tok; 657 | } 658 | 659 | // 拼接终结符链表 660 | static Token *appendTokens(Token *Tok1, Token *Tok2) { 661 | // Tok1为空时直接返回Tok2 662 | if (!Tok1 || Tok1->Kind == TK_EOF) 663 | return Tok2; 664 | 665 | // 链表指针T 666 | Token *T = Tok1; 667 | // T指向遍历到Tok1链表中最后一个 668 | while (T->Next->Kind != TK_EOF) 669 | T = T->Next; 670 | // T->Next指向Tok2 671 | T->Next = Tok2; 672 | // 返回拼接好的Tok1 673 | return Tok1; 674 | } 675 | 676 | // 编译C文件到汇编文件 677 | static void cc1(void) { 678 | Token *Tok = NULL; 679 | 680 | // 处理-include选项 681 | for (int I = 0; I < OptInclude.Len; I++) { 682 | // 需要引入的文件 683 | char *Incl = OptInclude.Data[I]; 684 | 685 | char *Path; 686 | if (fileExists(Incl)) { 687 | // 如果文件存在,则直接使用路径 688 | Path = Incl; 689 | } else { 690 | // 否则搜索引入路径区 691 | Path = searchIncludePaths(Incl); 692 | if (!Path) 693 | error("-include: %s: %s", Incl, strerror(errno)); 694 | } 695 | 696 | // 解析文件,生成终结符流 697 | Token *Tok2 = mustTokenizeFile(Path); 698 | Tok = appendTokens(Tok, Tok2); 699 | } 700 | 701 | // 解析文件,生成终结符流 702 | Token *Tok2 = mustTokenizeFile(BaseFile); 703 | Tok = appendTokens(Tok, Tok2); 704 | 705 | // 预处理 706 | Tok = preprocess(Tok); 707 | 708 | // 如果指定了-M,打印出文件的依赖关系 709 | if (OptM || OptMD) { 710 | printDependencies(); 711 | if (OptM) 712 | return; 713 | } 714 | 715 | // 如果指定了-E那么打印出预处理过的C代码 716 | if (OptE) { 717 | printTokens(Tok); 718 | return; 719 | } 720 | 721 | // 解析终结符流 722 | Obj *Prog = parse(Tok); 723 | 724 | // 生成代码 725 | 726 | // 防止编译器在编译途中退出,而只生成了部分的文件 727 | // 开启临时输出缓冲区 728 | char *Buf; 729 | size_t BufLen; 730 | FILE *OutputBuf = open_memstream(&Buf, &BufLen); 731 | 732 | // 输出汇编到缓冲区中 733 | codegen(Prog, OutputBuf); 734 | fclose(OutputBuf); 735 | 736 | // 从缓冲区中写入到文件中 737 | FILE *Out = openFile(OutputFile); 738 | fwrite(Buf, BufLen, 1, Out); 739 | fclose(Out); 740 | } 741 | 742 | // 调用汇编器 743 | static void assemble(char *Input, char *Output) { 744 | // 选择对应环境内的汇编器 745 | char *As = strlen(RVPath) 746 | ? format("%s/bin/riscv64-unknown-linux-gnu-as", RVPath) 747 | : "as"; 748 | char *Cmd[] = {As, "-c", Input, "-o", Output, NULL}; 749 | runSubprocess(Cmd); 750 | } 751 | 752 | // 查找文件 753 | static char *findFile(char *Pattern) { 754 | char *Path = NULL; 755 | // Linux文件系统中路径名称的模式匹配 756 | glob_t Buf = {}; 757 | // 参数:用来模式匹配的路径,标记(例如是否排序结果),错误处理函数,结果存放缓冲区 758 | glob(Pattern, 0, NULL, &Buf); 759 | // gl_pathc匹配到的路径计数 760 | // 复制最后的一条匹配结果到Path中 761 | if (Buf.gl_pathc > 0) 762 | Path = strdup(Buf.gl_pathv[Buf.gl_pathc - 1]); 763 | // 释放内存 764 | globfree(&Buf); 765 | return Path; 766 | } 767 | 768 | // 文件存在时,为真 769 | bool fileExists(char *Path) { 770 | struct stat St; 771 | return !stat(Path, &St); 772 | } 773 | 774 | // 查找库路径 775 | static char *findLibPath(void) { 776 | if (fileExists("/usr/lib/riscv64-linux-gnu/crti.o")) 777 | return "/usr/lib/riscv64-linux-gnu"; 778 | if (fileExists("/usr/lib64/crti.o")) 779 | return "/usr/lib64"; 780 | 781 | if (fileExists(format("%s/sysroot/usr/lib/crti.o", RVPath))) 782 | return format("%s/sysroot/usr/lib/", RVPath); 783 | error("library path is not found"); 784 | return NULL; 785 | } 786 | 787 | // 查找gcc库路径 788 | static char *findGCCLibPath(void) { 789 | char *paths[] = { 790 | "/usr/lib/gcc/riscv64-linux-gnu/*/crtbegin.o", 791 | // Gentoo 792 | "/usr/lib/gcc/riscv64-pc-linux-gnu/*/crtbegin.o", 793 | // Fedora 794 | "/usr/lib/gcc/riscv64-redhat-linux/*/crtbegin.o", 795 | // 交叉编译 796 | format("%s/lib/gcc/riscv64-unknown-linux-gnu/*/crtbegin.o", RVPath), 797 | }; 798 | 799 | // 遍历以查找gcc库的路径 800 | for (int I = 0; I < sizeof(paths) / sizeof(*paths); I++) { 801 | char *path = findFile(paths[I]); 802 | if (path) 803 | return dirname(path); 804 | } 805 | 806 | error("gcc library path is not found"); 807 | return NULL; 808 | } 809 | 810 | // 运行链接器ld 811 | static void runLinker(StringArray *Inputs, char *Output) { 812 | // 需要传递ld子进程的参数 813 | StringArray Arr = {}; 814 | 815 | // 链接器 816 | char *Ld = strlen(RVPath) 817 | ? format("%s/bin/riscv64-unknown-linux-gnu-ld", RVPath) 818 | : "ld"; 819 | strArrayPush(&Arr, Ld); 820 | 821 | // 输出文件 822 | strArrayPush(&Arr, "-o"); 823 | strArrayPush(&Arr, Output); 824 | strArrayPush(&Arr, "-m"); 825 | strArrayPush(&Arr, "elf64lriscv"); 826 | if (!OptStatic) { 827 | strArrayPush(&Arr, "-dynamic-linker"); 828 | 829 | char *LP64D = 830 | strlen(RVPath) 831 | ? format("%s/sysroot/lib/ld-linux-riscv64-lp64d.so.1", RVPath) 832 | : "/lib/ld-linux-riscv64-lp64d.so.1"; 833 | strArrayPush(&Arr, LP64D); 834 | } 835 | 836 | char *LibPath = findLibPath(); 837 | char *GccLibPath = findGCCLibPath(); 838 | 839 | if (OptShared) { 840 | strArrayPush(&Arr, format("%s/crti.o", LibPath)); 841 | strArrayPush(&Arr, format("%s/crtbeginS.o", GccLibPath)); 842 | } else { 843 | strArrayPush(&Arr, format("%s/crt1.o", LibPath)); 844 | strArrayPush(&Arr, format("%s/crti.o", LibPath)); 845 | strArrayPush(&Arr, format("%s/crtbegin.o", GccLibPath)); 846 | } 847 | 848 | strArrayPush(&Arr, format("-L%s", GccLibPath)); 849 | 850 | if (strlen(RVPath)) { 851 | strArrayPush(&Arr, format("-L%s/sysroot/usr/lib64", RVPath)); 852 | strArrayPush(&Arr, format("-L%s/sysroot/lib64", RVPath)); 853 | strArrayPush(&Arr, 854 | format("-L%s/sysroot/usr/lib/riscv64-linux-gnu", RVPath)); 855 | strArrayPush(&Arr, 856 | format("-L%s/sysroot/usr/lib/riscv64-pc-linux-gnu", RVPath)); 857 | strArrayPush(&Arr, 858 | format("-L%s/sysroot/usr/lib/riscv64-redhat-linux", RVPath)); 859 | strArrayPush(&Arr, format("-L%s/sysroot/usr/lib", RVPath)); 860 | strArrayPush(&Arr, format("-L%s/sysroot/lib", RVPath)); 861 | } else { 862 | strArrayPush(&Arr, "-L/usr/lib64"); 863 | strArrayPush(&Arr, "-L/lib64"); 864 | strArrayPush(&Arr, "-L/usr/lib/riscv64-linux-gnu"); 865 | strArrayPush(&Arr, "-L/usr/lib/riscv64-pc-linux-gnu"); 866 | strArrayPush(&Arr, "-L/usr/lib/riscv64-redhat-linux"); 867 | strArrayPush(&Arr, "-L/usr/lib"); 868 | strArrayPush(&Arr, "-L/lib"); 869 | } 870 | 871 | // 链接器额外参数存入到链接器参数中 872 | for (int I = 0; I < LdExtraArgs.Len; I++) 873 | strArrayPush(&Arr, LdExtraArgs.Data[I]); 874 | 875 | // 输入文件,存入到链接器参数中 876 | for (int I = 0; I < Inputs->Len; I++) 877 | strArrayPush(&Arr, Inputs->Data[I]); 878 | 879 | if (OptStatic) { 880 | strArrayPush(&Arr, "--start-group"); 881 | strArrayPush(&Arr, "-lgcc"); 882 | strArrayPush(&Arr, "-lgcc_eh"); 883 | strArrayPush(&Arr, "-lc"); 884 | strArrayPush(&Arr, "--end-group"); 885 | } else { 886 | strArrayPush(&Arr, "-lc"); 887 | strArrayPush(&Arr, "-lgcc"); 888 | strArrayPush(&Arr, "--as-needed"); 889 | strArrayPush(&Arr, "-lgcc_s"); 890 | strArrayPush(&Arr, "--no-as-needed"); 891 | } 892 | 893 | if (OptShared) 894 | strArrayPush(&Arr, format("%s/crtendS.o", GccLibPath)); 895 | else 896 | strArrayPush(&Arr, format("%s/crtend.o", GccLibPath)); 897 | strArrayPush(&Arr, format("%s/crtn.o", LibPath)); 898 | strArrayPush(&Arr, NULL); 899 | 900 | // 开辟的链接器子进程 901 | runSubprocess(Arr.Data); 902 | } 903 | 904 | // 获取文件的类型 905 | static FileType getFileType(char *Filename) { 906 | // 若-x指定了不为空的类型,使用该类型 907 | if (OptX != FILE_NONE) 908 | return OptX; 909 | 910 | // 以.a结尾的文件,解析为静态库文件类型 911 | if (endsWith(Filename, ".a")) 912 | return FILE_AR; 913 | // 以.so结尾的文件,解析为动态库文件类型 914 | if (endsWith(Filename, ".so")) 915 | return FILE_DSO; 916 | // 以.o结尾的文件,解析为空重定位文件类型 917 | if (endsWith(Filename, ".o")) 918 | return FILE_OBJ; 919 | // 以.c结尾的文件,解析为C语言源代码类型 920 | if (endsWith(Filename, ".c")) 921 | return FILE_C; 922 | // 以.s结尾的文件,解析为汇编类型 923 | if (endsWith(Filename, ".s")) 924 | return FILE_ASM; 925 | 926 | error(": unknown file extension: %s", Filename); 927 | } 928 | 929 | // 编译器驱动流程 930 | // 931 | // 源文件 932 | // ↓ 933 | // 预处理器预处理后的文件 934 | // ↓ 935 | // cc1编译为汇编文件 936 | // ↓ 937 | // as编译为可重定位文件 938 | // ↓ 939 | // ld链接为可执行文件 940 | 941 | // rvcc的程序入口函数 942 | int main(int Argc, char **Argv) { 943 | // 在程序退出时,执行cleanup函数 944 | atexit(cleanup); 945 | // 初始化预定义的宏 946 | initMacros(); 947 | // 解析传入程序的参数 948 | parseArgs(Argc, Argv); 949 | 950 | // 如果指定了-cc1选项 951 | // 直接编译C文件到汇编文件 952 | if (OptCC1) { 953 | // 增加默认引入路径 954 | addDefaultIncludePaths(Argv[0]); 955 | cc1(); 956 | return 0; 957 | } 958 | 959 | // 当前不能指定-c、-S、-E后,将多个输入文件,输出到一个文件中 960 | if (InputPaths.Len > 1 && OptO && (OptC || OptS || OptE)) 961 | error("cannot specify '-o' with '-c', '-S' or '-E' with multiple files"); 962 | 963 | // 链接器参数 964 | StringArray LdArgs = {}; 965 | 966 | // 遍历每个输入文件 967 | for (int I = 0; I < InputPaths.Len; I++) { 968 | // 读取输入文件 969 | char *Input = InputPaths.Data[I]; 970 | 971 | // 链接时搜索指定的库文件 972 | if (!strncmp(Input, "-l", 2)) { 973 | strArrayPush(&LdArgs, Input); 974 | continue; 975 | } 976 | 977 | // 匹配到 -Wl, 将后续参数存入链接器选项 978 | if (!strncmp(Input, "-Wl,", 4)) { 979 | // 以 , 分割开的参数字符串 980 | char *S = strdup(Input + 4); 981 | // 以 , 分割字符串,并返回一个参数 982 | char *Arg = strtok(S, ","); 983 | // 循环遍历剩余的参数 984 | while (Arg) { 985 | // 加入到链接器参数 986 | strArrayPush(&LdArgs, Arg); 987 | Arg = strtok(NULL, ","); 988 | } 989 | continue; 990 | } 991 | 992 | // 输出文件 993 | char *Output; 994 | // 如果指定了输出文件,则直接使用 995 | if (OptO) 996 | Output = OptO; 997 | // 若未指定输出的汇编文件名,则输出到后缀为.s的同名文件中 998 | else if (OptS) 999 | Output = replaceExtn(Input, ".s"); 1000 | // 若未指定输出的可重定位文件名,则输出到后缀为.o的同名文件中 1001 | else 1002 | Output = replaceExtn(Input, ".o"); 1003 | 1004 | // 获取输入文件的类型 1005 | FileType Ty = getFileType(Input); 1006 | 1007 | // 处理.o或.a或.so文件 1008 | if (Ty == FILE_OBJ || Ty == FILE_AR || Ty == FILE_DSO) { 1009 | // 存入链接器选项中 1010 | strArrayPush(&LdArgs, Input); 1011 | continue; 1012 | } 1013 | 1014 | // 处理.s文件 1015 | if (Ty == FILE_ASM) { 1016 | // 如果没有指定-S,那么需要进行汇编 1017 | if (!OptS) 1018 | assemble(Input, Output); 1019 | continue; 1020 | } 1021 | 1022 | // 处理.c文件 1023 | assert(Ty == FILE_C); 1024 | 1025 | // 只进行解析 1026 | if (OptE || OptM) { 1027 | runCC1(Argc, Argv, Input, NULL); 1028 | continue; 1029 | } 1030 | 1031 | // 如果有-S选项,那么执行调用cc1程序 1032 | if (OptS) { 1033 | runCC1(Argc, Argv, Input, Output); 1034 | continue; 1035 | } 1036 | 1037 | // 编译并汇编 1038 | if (OptC) { 1039 | // 临时文件Tmp作为cc1输出的汇编文件 1040 | char *Tmp = createTmpFile(); 1041 | // cc1,编译C文件为汇编文件 1042 | runCC1(Argc, Argv, Input, Tmp); 1043 | // as,编译汇编文件为可重定位文件 1044 | assemble(Tmp, Output); 1045 | continue; 1046 | } 1047 | 1048 | // 否则运行cc1和as 1049 | // 临时文件Tmp1作为cc1输出的汇编文件 1050 | // 临时文件Tmp2作为as输出的可重定位文件 1051 | char *Tmp1 = createTmpFile(); 1052 | char *Tmp2 = createTmpFile(); 1053 | // cc1,编译C文件为汇编文件 1054 | runCC1(Argc, Argv, Input, Tmp1); 1055 | // as,编译汇编文件为可重定位文件 1056 | assemble(Tmp1, Tmp2); 1057 | // 将Tmp2存入链接器选项 1058 | strArrayPush(&LdArgs, Tmp2); 1059 | continue; 1060 | } 1061 | 1062 | // 需要链接的情况 1063 | // 未指定文件名时,默认为a.out 1064 | if (LdArgs.Len > 0) 1065 | runLinker(&LdArgs, OptO ? OptO : "a.out"); 1066 | 1067 | return 0; 1068 | } 1069 | -------------------------------------------------------------------------------- /rvcc.h: -------------------------------------------------------------------------------- 1 | // 使用POSIX.1标准 2 | // 使用了strndup函数 3 | #define _POSIX_C_SOURCE 200809L 4 | 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | 24 | // 宏展开函数 25 | // 括号是为了保证内部表达式作为整体去求值 26 | #define MAX(x, y) ((x) < (y) ? (y) : (x)) 27 | #define MIN(x, y) ((x) < (y) ? (x) : (y)) 28 | 29 | #ifndef __GNUC__ 30 | #define __attribute__(x) 31 | #endif 32 | 33 | // 34 | // 共用头文件,定义了多个文件间共同使用的函数和数据 35 | // 36 | 37 | typedef struct Type Type; 38 | typedef struct Node Node; 39 | typedef struct Member Member; 40 | typedef struct Relocation Relocation; 41 | typedef struct Hideset Hideset; 42 | 43 | // 44 | // 字符串 45 | // 46 | 47 | // 字符串数组 48 | typedef struct { 49 | char **Data; // 数据内容 50 | int Capacity; // 能容纳字符串的容量 51 | int Len; // 当前字符串的数量,Len ≤ Capacity 52 | } StringArray; 53 | 54 | void strArrayPush(StringArray *Arr, char *S); 55 | char *format(char *Fmt, ...) __attribute__((format(printf, 1, 2))); 56 | 57 | // 58 | // 终结符分析,词法分析 59 | // 60 | 61 | // 为每个终结符都设置种类来表示 62 | typedef enum { 63 | TK_IDENT, // 标记符,可以为变量名、函数名等 64 | TK_PUNCT, // 操作符如: + - 65 | TK_KEYWORD, // 关键字 66 | TK_STR, // 字符串字面量 67 | TK_NUM, // 数字 68 | TK_PP_NUM, // 预处理数值 69 | TK_EOF, // 文件终止符,即文件的最后 70 | } TokenKind; 71 | 72 | // 文件 73 | typedef struct { 74 | char *Name; // 文件名 75 | int FileNo; // 文件编号,从1开始 76 | char *Contents; // 文件内容 77 | 78 | // 用于#line指示 79 | char *DisplayName; // 标记的文件名 80 | int LineDelta; // 标记的行号差值 81 | } File; 82 | 83 | // 终结符结构体 84 | typedef struct Token Token; 85 | struct Token { 86 | TokenKind Kind; // 种类 87 | Token *Next; // 指向下一终结符 88 | int64_t Val; // TK_NUM值 89 | long double FVal; // TK_NUM浮点值 90 | char *Loc; // 在解析的字符串内的位置 91 | int Len; // 长度 92 | Type *Ty; // TK_NUM或TK_STR使用 93 | char *Str; // 字符串字面量,包括'\0' 94 | 95 | File *File; // 源文件位置 96 | char *Filename; // 标记的文件名 97 | int LineNo; // 行号 98 | int LineDelta; // 标记的行号差值 99 | bool AtBOL; // 终结符在行首(begin of line)时为true 100 | bool HasSpace; // 终结符前是否有空格 101 | Hideset *Hideset; // 用于宏展开时的隐藏集 102 | Token *Origin; // 宏展开前的原始终结符 103 | }; 104 | 105 | // 去除了static用以在多个文件间访问 106 | // 报错函数 107 | noreturn void error(char *Fmt, ...) __attribute__((format(printf, 1, 2))); 108 | noreturn void errorAt(char *Loc, char *Fmt, ...) 109 | __attribute__((format(printf, 2, 3))); 110 | noreturn void errorTok(Token *Tok, char *Fmt, ...) 111 | __attribute__((format(printf, 2, 3))); 112 | void warnTok(Token *Tok, char *Fmt, ...) __attribute__((format(printf, 2, 3))); 113 | // 警告函数 114 | void warnTok(Token *Tok, char *Fmt, ...); 115 | // 判断Token与Str的关系 116 | bool equal(Token *Tok, char *Str); 117 | Token *skip(Token *Tok, char *Str); 118 | bool consume(Token **Rest, Token *Tok, char *Str); 119 | // 转换为预处理终结符 120 | void convertPPTokens(Token *tok); 121 | // 转换关键字 122 | void convertKeywords(Token *Tok); 123 | // 获取输入文件 124 | File **getInputFiles(void); 125 | // 新建一个File 126 | File *newFile(char *Name, int FileNo, char *Contents); 127 | // 词法解析字符串字面量 128 | Token *tokenizeStringLiteral(Token *Tok, Type *BaseTy); 129 | // 终结符解析,文件名,文件内容 130 | Token *tokenize(File *FP); 131 | // 词法分析 132 | Token *tokenizeFile(char *Path); 133 | 134 | // 指rvcc源文件的某个文件的某一行出了问题,打印出文件名和行号 135 | #define unreachable() error("internal error at %s:%d", __FILE__, __LINE__) 136 | 137 | // 138 | // 预处理器 139 | // 140 | 141 | // 搜索引入路径区 142 | char *searchIncludePaths(char *Filename); 143 | void initMacros(void); 144 | void defineMacro(char *Name, char *Buf); 145 | void undefMacro(char *Name); 146 | Token *preprocess(Token *Tok); 147 | 148 | // 149 | // 生成AST(抽象语法树),语法解析 150 | // 151 | 152 | // 变量 或 函数 153 | typedef struct Obj Obj; 154 | struct Obj { 155 | Obj *Next; // 指向下一对象 156 | char *Name; // 变量名 157 | Type *Ty; // 变量类型 158 | Token *Tok; // 对应的终结符 159 | bool IsLocal; // 是 局部或全局 变量 160 | int Align; // 对齐量 161 | // 局部变量 162 | int Offset; // fp的偏移量 163 | 164 | // 结构体类型 165 | bool IsHalfByStack; // 一半用寄存器,一半用栈 166 | 167 | // 函数 或 全局变量 168 | bool IsFunction; 169 | bool IsDefinition; // 是否为函数定义 170 | bool IsStatic; // 是否为文件域内的 171 | 172 | // 全局变量 173 | bool IsTentative; // 是否为试探性的变量 174 | bool IsTLS; // 是否为线程局部存储,Thread Local Storage 175 | char *InitData; // 用于初始化的数据 176 | Relocation *Rel; // 指向其他全局变量的指针 177 | 178 | // 函数 179 | bool IsInline; // 内联 180 | Obj *Params; // 形参 181 | Node *Body; // 函数体 182 | Obj *Locals; // 本地变量 183 | Obj *VaArea; // 可变参数区域 184 | Obj *AllocaBottom; // Alloca区域底部 185 | int StackSize; // 栈大小 186 | 187 | // 静态内联函数 188 | bool IsLive; // 函数是否存活 189 | bool IsRoot; // 是否为根函数 190 | StringArray Refs; // 引用的函数记录 191 | }; 192 | 193 | // 全局变量可被 常量表达式 或者 指向其他全局变量的指针 初始化。 194 | // 此结构体用于 指向其他全局变量的指针 的情况。 195 | typedef struct Relocation Relocation; 196 | struct Relocation { 197 | Relocation *Next; // 下一个 198 | int Offset; // 偏移量 199 | char **Label; // 标签名 200 | long Addend; // 加数 201 | }; 202 | 203 | // AST的节点种类 204 | typedef enum { 205 | ND_NULL_EXPR, // 空表达式 206 | ND_ADD, // + 207 | ND_SUB, // - 208 | ND_MUL, // * 209 | ND_DIV, // / 210 | ND_NEG, // 负号- 211 | ND_MOD, // %,取余 212 | ND_BITAND, // &,按位与 213 | ND_BITOR, // |,按位或 214 | ND_BITXOR, // ^,按位异或 215 | ND_SHL, // <<,左移 216 | ND_SHR, // >>,右移 217 | ND_EQ, // == 218 | ND_NE, // != 219 | ND_LT, // < 220 | ND_LE, // <= 221 | ND_ASSIGN, // 赋值 222 | ND_COND, // ?:,条件运算符 223 | ND_COMMA, // , 逗号 224 | ND_MEMBER, // . 结构体成员访问 225 | ND_ADDR, // 取地址 & 226 | ND_DEREF, // 解引用 * 227 | ND_NOT, // !,非 228 | ND_BITNOT, // ~,按位取非 229 | ND_LOGAND, // &&,与 230 | ND_LOGOR, // ||,或 231 | ND_RETURN, // 返回 232 | ND_IF, // "if",条件判断 233 | ND_FOR, // "for" 或 "while",循环 234 | ND_DO, // "do",用于do while语句 235 | ND_SWITCH, // "switch",分支语句 236 | ND_CASE, // "case" 237 | ND_BLOCK, // { ... },代码块 238 | ND_GOTO, // goto,直接跳转语句 239 | ND_GOTO_EXPR, // "goto" 的对应的地址表达式 240 | ND_LABEL, // 标签语句 241 | ND_LABEL_VAL, // "goto" 标签值 242 | ND_FUNCALL, // 函数调用 243 | ND_EXPR_STMT, // 表达式语句 244 | ND_STMT_EXPR, // 语句表达式 245 | ND_VAR, // 变量 246 | ND_VLA_PTR, // VLA指派器 247 | ND_NUM, // 数字 248 | ND_CAST, // 类型转换 249 | ND_MEMZERO, // 栈中变量清零 250 | ND_ASM, // "asm"汇编 251 | ND_CAS, // 原子比较交换 252 | ND_EXCH, // 原子交换 253 | } NodeKind; 254 | 255 | // AST中二叉树节点 256 | struct Node { 257 | NodeKind Kind; // 节点种类 258 | Node *Next; // 下一节点,指代下一语句 259 | Token *Tok; // 节点对应的终结符 260 | Type *Ty; // 节点中数据的类型 261 | 262 | Node *LHS; // 左部,left-hand side 263 | Node *RHS; // 右部,right-hand side 264 | 265 | // "if"语句 或者 "for"语句 266 | Node *Cond; // 条件内的表达式 267 | Node *Then; // 符合条件后的语句 268 | Node *Els; // 不符合条件后的语句 269 | Node *Init; // 初始化语句 270 | Node *Inc; // 递增语句 271 | 272 | // "break" 标签 273 | char *BrkLabel; 274 | // "continue" 标签 275 | char *ContLabel; 276 | 277 | // 代码块 或 语句表达式 278 | Node *Body; 279 | 280 | // 结构体成员访问 281 | Member *Mem; 282 | 283 | // 函数调用 284 | Type *FuncType; // 函数类型 285 | Node *Args; // 函数参数 286 | bool PassByStack; // 通过栈传递 287 | Obj *RetBuffer; // 返回值缓冲区 288 | 289 | // goto和标签语句 290 | char *Label; 291 | char *UniqueLabel; 292 | Node *GotoNext; 293 | 294 | // switch语句 295 | Node *CaseNext; 296 | Node *DefaultCase; 297 | 298 | // Case语句 299 | long Begin; // case后面的数值 300 | long End; // case ...后面的数值 301 | 302 | // "asm" 字符串字面量 303 | char *AsmStr; 304 | 305 | // 原子比较交换 306 | Node *CasAddr; // 地址 307 | Node *CasOld; // 旧值 308 | Node *CasNew; // 新值 309 | 310 | Obj *Var; // 存储ND_VAR种类的变量 311 | int64_t Val; // 存储ND_NUM种类的值 312 | long double FVal; // 存储ND_NUM种类的浮点值 313 | }; 314 | 315 | // 类型转换,将表达式的值转换为另一种类型 316 | Node *newCast(Node *Expr, Type *Ty); 317 | // 解析常量表达式 318 | int64_t constExpr(Token **Rest, Token *Tok); 319 | // 语法解析入口函数 320 | Obj *parse(Token *Tok); 321 | 322 | // 323 | // 类型系统 324 | // 325 | 326 | // 类型种类 327 | typedef enum { 328 | TY_VOID, // void类型 329 | TY_BOOL, // _Bool布尔类型 330 | TY_CHAR, // char字符类型 331 | TY_SHORT, // short短整型 332 | TY_INT, // int整型 333 | TY_LONG, // long长整型 334 | TY_FLOAT, // float类型 335 | TY_DOUBLE, // double类型 336 | TY_LDOUBLE, // long double类型 337 | TY_ENUM, // enum枚举类型 338 | TY_PTR, // 指针 339 | TY_FUNC, // 函数 340 | TY_ARRAY, // 数组 341 | TY_VLA, // 可变长度数组,variable-length array 342 | TY_STRUCT, // 结构体 343 | TY_UNION, // 联合体 344 | } TypeKind; 345 | 346 | struct Type { 347 | TypeKind Kind; // 种类 348 | int Size; // 大小, sizeof返回的值 349 | int Align; // 对齐 350 | bool IsUnsigned; // 是否为无符号的 351 | bool IsAtomic; // 为 _Atomic 则为真 352 | Type *Origin; // 原始类型,用于兼容性检查 353 | 354 | // 指针 355 | Type *Base; // 指向的类型 356 | 357 | // 类型对应名称,如:变量名、函数名 358 | Token *Name; 359 | Token *NamePos; // 名称位置 360 | 361 | // 数组 362 | int ArrayLen; // 数组长度, 元素总个数 363 | 364 | // 可变长度数组 365 | Node *VLALen; // VLA数组长度, 元素总个数 366 | Obj *VLASize; // VLA大小, sizeof返回的值 367 | 368 | // 结构体 369 | Member *Mems; 370 | bool IsFlexible; // 是否为灵活的 371 | bool IsPacked; // 是否是紧凑的(不进行对齐) 372 | Type *FSReg1Ty; // 浮点结构体的对应寄存器 373 | Type *FSReg2Ty; // 浮点结构体的对应寄存器 374 | 375 | // 函数类型 376 | Type *ReturnTy; // 函数返回的类型 377 | Type *Params; // 形参 378 | bool IsVariadic; // 是否为可变参数 379 | Type *Next; // 下一类型 380 | }; 381 | 382 | // 结构体成员 383 | struct Member { 384 | Member *Next; // 下一成员 385 | Type *Ty; // 类型 386 | Token *Tok; // 用于报错信息 387 | Token *Name; // 名称 388 | int Idx; // 索引值 389 | int Align; // 对齐量 390 | int Offset; // 偏移量 391 | 392 | // 位域 393 | bool IsBitfield; // 是否为位域 394 | int BitOffset; // 位偏移量 395 | int BitWidth; // 位宽度 396 | }; 397 | 398 | // 声明全局变量,定义在type.c中。 399 | extern Type *TyVoid; 400 | extern Type *TyBool; 401 | 402 | extern Type *TyChar; 403 | extern Type *TyShort; 404 | extern Type *TyInt; 405 | extern Type *TyLong; 406 | 407 | extern Type *TyUChar; 408 | extern Type *TyUShort; 409 | extern Type *TyUInt; 410 | extern Type *TyULong; 411 | 412 | extern Type *TyFloat; 413 | extern Type *TyDouble; 414 | extern Type *TyLDouble; 415 | 416 | // 判断是否为整型 417 | bool isInteger(Type *TY); 418 | // 判断是否为浮点类型 419 | bool isFloNum(Type *Ty); 420 | // 判断是否为Float或Double类型 421 | bool isSFloNum(Type *Ty); 422 | // 判断是否为数字 423 | bool isNumeric(Type *Ty); 424 | // 判断类型是否兼容 425 | bool isCompatible(Type *T1, Type *T2); 426 | // 复制类型 427 | Type *copyType(Type *Ty); 428 | // 构建一个指针类型,并指向基类 429 | Type *pointerTo(Type *Base); 430 | // 为节点内的所有节点添加类型 431 | void addType(Node *Nd); 432 | // 数组类型 433 | Type *arrayOf(Type *Base, int Size); 434 | // 构造可变长数组类型 435 | Type *VLAOf(Type *Base, Node *Expr); 436 | // 枚举类型 437 | Type *enumType(void); 438 | // 结构体类型 439 | Type *structType(void); 440 | // 函数类型 441 | Type *funcType(Type *ReturnTy); 442 | 443 | // 444 | // 语义分析与代码生成 445 | // 446 | 447 | // 代码生成入口函数 448 | void codegen(Obj *Prog, FILE *Out); 449 | int alignTo(int N, int Align); 450 | bool isIdent1_1(uint32_t C); 451 | bool isIdent2_1(uint32_t C); 452 | 453 | // 454 | // unicode 统一码 455 | // 456 | 457 | // 将unicode字符编码为UTF-8的格式 458 | int encodeUTF8(char *Buf, uint32_t C); 459 | // 将UTF-8的格式解码为unicode字符 460 | uint32_t decodeUTF8(char **NewPos, char *P); 461 | // 返回在固定宽度字体中需要多少列来显示给定字符串 462 | int displayWidth(char *P, int Len); 463 | 464 | // 465 | // 哈希表 466 | // 467 | 468 | // 哈希键值对 469 | typedef struct { 470 | char *Key; // 键 471 | int KeyLen; // 键长 472 | void *Val; // 值 473 | } HashEntry; 474 | 475 | // 哈希表 476 | typedef struct { 477 | HashEntry *Buckets; // 桶,存储键值对 478 | int Capacity; // 哈希表最大键值对数量 479 | int Used; // 被使用的键值对数量 480 | } HashMap; 481 | 482 | void *hashmapGet(HashMap *Map, char *Key); 483 | void *hashmapGet2(HashMap *Map, char *Key, int KeyLen); 484 | void hashmapPut(HashMap *Map, char *Key, void *Val); 485 | void hashmapPut2(HashMap *Map, char *Key, int KeyLen, void *Val); 486 | void hashmapDelete(HashMap *Map, char *Key); 487 | void hashmapDelete2(HashMap *Map, char *Key, int KeyLen); 488 | void hashmapTest(void); 489 | 490 | // 491 | // 主程序,驱动文件 492 | // 493 | 494 | // 判断文件存在 495 | bool fileExists(char *Path); 496 | 497 | // 引入路径区 498 | extern StringArray IncludePaths; 499 | // 位置无关代码的标记 500 | extern bool OptFPIC; 501 | // 标记是否生成common块 502 | extern bool OptFCommon; 503 | extern char *BaseFile; 504 | -------------------------------------------------------------------------------- /string.c: -------------------------------------------------------------------------------- 1 | #include "rvcc.h" 2 | 3 | // 压入字符串数组 4 | void strArrayPush(StringArray *Arr, char *S) { 5 | // 如果为空,没有数据 6 | if (!Arr->Data) { 7 | // 开辟8个字符串的位置 8 | Arr->Data = calloc(8, sizeof(char *)); 9 | // 将容量设为8 10 | Arr->Capacity = 8; 11 | } 12 | 13 | // 如果存满了,开辟一倍的空间 14 | if (Arr->Capacity == Arr->Len) { 15 | // 再开辟当前容量一倍的空间 16 | Arr->Data = realloc(Arr->Data, sizeof(char *) * Arr->Capacity * 2); 17 | // 容量翻倍 18 | Arr->Capacity *= 2; 19 | // 清空新开辟的空间 20 | for (int I = Arr->Len; I < Arr->Capacity; I++) 21 | Arr->Data[I] = NULL; 22 | } 23 | 24 | // 存入字符串 25 | Arr->Data[Arr->Len++] = S; 26 | } 27 | 28 | // 格式化后返回字符串 29 | char *format(char *Fmt, ...) { 30 | char *Buf; 31 | size_t BufLen; 32 | // 将字符串对应的内存作为I/O流 33 | FILE *Out = open_memstream(&Buf, &BufLen); 34 | 35 | va_list VA; 36 | va_start(VA, Fmt); 37 | // 向流中写入数据 38 | vfprintf(Out, Fmt, VA); 39 | va_end(VA); 40 | 41 | fclose(Out); 42 | return Buf; 43 | } 44 | -------------------------------------------------------------------------------- /test/alignof.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | // [118] 支持_Alignof和_Alignas 4 | int _Alignas(512) g1; 5 | int _Alignas(512) g2; 6 | char g3; 7 | int g4; 8 | long g5; 9 | char g6; 10 | 11 | int main() { 12 | // [118] 支持_Alignof和_Alignas 13 | ASSERT(1, _Alignof(char)); 14 | ASSERT(2, _Alignof(short)); 15 | ASSERT(4, _Alignof(int)); 16 | ASSERT(8, _Alignof(long)); 17 | ASSERT(8, _Alignof(long long)); 18 | ASSERT(1, _Alignof(char[3])); 19 | ASSERT(4, _Alignof(int[3])); 20 | ASSERT(1, _Alignof(struct {char a; char b;}[2])); 21 | ASSERT(8, _Alignof(struct {char a; long b;}[2])); 22 | 23 | ASSERT(1, ({ _Alignas(char) char x, y; &y-&x; })); 24 | ASSERT(8, ({ _Alignas(long) char x, y; &y-&x; })); 25 | ASSERT(32, ({ _Alignas(32) char x, y; &y-&x; })); 26 | ASSERT(32, ({ _Alignas(32) int *x, *y; ((char *)&y)-((char *)&x); })); 27 | ASSERT(16, ({ struct { _Alignas(16) char x, y; } a; &a.y-&a.x; })); 28 | ASSERT(8, ({ struct T { _Alignas(8) char a; }; _Alignof(struct T); })); 29 | 30 | ASSERT(0, (long)(char *)&g1 % 512); 31 | ASSERT(0, (long)(char *)&g2 % 512); 32 | ASSERT(0, (long)(char *)&g4 % 4); 33 | ASSERT(0, (long)(char *)&g5 % 8); 34 | 35 | // [119] 支持对变量使用_Alignof 36 | ASSERT(1, ({ char x; _Alignof(x); })); 37 | ASSERT(4, ({ int x; _Alignof(x); })); 38 | ASSERT(1, ({ char x; _Alignof x; })); 39 | ASSERT(4, ({ int x; _Alignof x; })); 40 | 41 | // [133] 在一些表达式中用long或ulong替代int 42 | ASSERT(1, _Alignof(char) << 31 >> 31); 43 | ASSERT(1, _Alignof(char) << 63 >> 63); 44 | ASSERT(1, ({ char x; _Alignof(x) << 63 >> 63; })); 45 | 46 | printf("[218] 数组超过16字节时,对齐值至少为16字节\n"); 47 | ASSERT(0, ({ char x[16]; (unsigned long)&x % 16; })); 48 | ASSERT(0, ({ char x[17]; (unsigned long)&x % 16; })); 49 | ASSERT(0, ({ char x[100]; (unsigned long)&x % 16; })); 50 | ASSERT(0, ({ char x[101]; (unsigned long)&x % 16; })); 51 | 52 | printf("OK\n"); 53 | return 0; 54 | } 55 | -------------------------------------------------------------------------------- /test/alloca.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | void *fn(int x, void *p, int y) { return p; } 4 | 5 | int main() { 6 | printf("[271] 支持alloca函数\n"); 7 | int i = 0; 8 | 9 | char *p1 = alloca(16); 10 | char *p2 = alloca(16); 11 | char *p3 = 1 + (char *)alloca(3) + 1; 12 | p3 -= 2; 13 | char *p4 = fn(1, alloca(16), 3); 14 | 15 | ASSERT(16, p1 - p2); 16 | ASSERT(16, p2 - p3); 17 | ASSERT(16, p3 - p4); 18 | 19 | memcpy(p1, "0123456789abcdef", 16); 20 | memcpy(p2, "ghijklmnopqrstuv", 16); 21 | memcpy(p3, "wxy", 3); 22 | 23 | ASSERT(0, memcmp(p1, "0123456789abcdef", 16)); 24 | ASSERT(0, memcmp(p2, "ghijklmnopqrstuv", 16)); 25 | ASSERT(0, memcmp(p3, "wxy", 3)); 26 | 27 | printf("OK\n"); 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /test/arith.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int main() { 4 | // [1] 返回指定数值 5 | ASSERT(0, 0); 6 | ASSERT(42, 42); 7 | // [2] 支持 + - 运算符 8 | ASSERT(21, 5+20-4); 9 | // [3] 支持空格 10 | ASSERT(41, 12 + 34 - 5 ); 11 | // [5] 支持 * /() 运算符 12 | ASSERT(47, 5+6*7); 13 | ASSERT(15, 5*(9-6)); 14 | ASSERT(4, (3+5)/2); 15 | // [6] 支持一元运算的 + -ASSERT(10, -10 + 20); 16 | ASSERT(10, - -10); 17 | ASSERT(10, - - +10); 18 | 19 | // [7] 支持条件运算符 20 | ASSERT(0, 0==1); 21 | ASSERT(1, 42==42); 22 | ASSERT(1, 0!=1); 23 | ASSERT(0, 42!=42); 24 | 25 | ASSERT(1, 0<1); 26 | ASSERT(0, 1<1); 27 | ASSERT(0, 2<1); 28 | ASSERT(1, 0<=1); 29 | ASSERT(1, 1<=1); 30 | ASSERT(0, 2<=1); 31 | 32 | ASSERT(1, 1>0); 33 | ASSERT(0, 1>1); 34 | ASSERT(0, 1>2); 35 | ASSERT(1, 1>=0); 36 | ASSERT(1, 1>=1); 37 | ASSERT(0, 1>=2); 38 | 39 | // [68] 实现常规算术转换 40 | ASSERT(0, 1073741824 * 100 / 100); 41 | 42 | // [77] 支持+= -= *= /= 43 | ASSERT(7, ({ int i=2; i+=5; i; })); 44 | ASSERT(7, ({ int i=2; i+=5; })); 45 | ASSERT(3, ({ int i=5; i-=2; i; })); 46 | ASSERT(3, ({ int i=5; i-=2; })); 47 | ASSERT(6, ({ int i=3; i*=2; i; })); 48 | ASSERT(6, ({ int i=3; i*=2; })); 49 | ASSERT(3, ({ int i=6; i/=2; i; })); 50 | ASSERT(3, ({ int i=6; i/=2; })); 51 | 52 | // [78] 支持前置++和-- 53 | ASSERT(3, ({ int i=2; ++i; })); 54 | ASSERT(2, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; ++*p; })); 55 | ASSERT(0, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; --*p; })); 56 | 57 | // [79] 支持后置++ 和-- 58 | ASSERT(2, ({ int i=2; i++; })); 59 | ASSERT(2, ({ int i=2; i--; })); 60 | ASSERT(3, ({ int i=2; i++; i; })); 61 | ASSERT(1, ({ int i=2; i--; i; })); 62 | ASSERT(1, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; *p++; })); 63 | ASSERT(1, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; *p--; })); 64 | 65 | ASSERT(0, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; (*p++)--; a[0]; })); 66 | ASSERT(0, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; (*(p--))--; a[1]; })); 67 | ASSERT(2, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; (*p)--; a[2]; })); 68 | ASSERT(2, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; (*p)--; p++; *p; })); 69 | 70 | ASSERT(0, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; (*p++)--; a[0]; })); 71 | ASSERT(0, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; (*p++)--; a[1]; })); 72 | ASSERT(2, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; (*p++)--; a[2]; })); 73 | ASSERT(2, ({ int a[3]; a[0]=0; a[1]=1; a[2]=2; int *p=a+1; (*p++)--; *p; })); 74 | 75 | // [81] 支持 ! 操作符 76 | ASSERT(0, !1); 77 | ASSERT(0, !2); 78 | ASSERT(1, !0); 79 | ASSERT(1, !(char)0); 80 | ASSERT(0, !(long)3); 81 | ASSERT(4, sizeof(!(char)0)); 82 | ASSERT(4, sizeof(!(long)0)); 83 | 84 | // [82] 支持 ~ 操作符 85 | ASSERT(-1, ~0); 86 | ASSERT(0, ~-1); 87 | 88 | // [83] 支持 % 和 %= 89 | ASSERT(5, 17%6); 90 | ASSERT(5, ((long)17)%6); 91 | ASSERT(2, ({ int i=10; i%=4; i; })); 92 | ASSERT(2, ({ long i=10; i%=4; i; })); 93 | 94 | // [84] 支持 & &= | |= ^ ^= 95 | ASSERT(0, 0&1); 96 | ASSERT(1, 3&1); 97 | ASSERT(3, 7&3); 98 | ASSERT(10, -1&10); 99 | 100 | ASSERT(1, 0|1); 101 | ASSERT(0b10011, 0b10000|0b00011); 102 | 103 | ASSERT(0, 0^0); 104 | ASSERT(0, 0b1111^0b1111); 105 | ASSERT(0b110100, 0b111000^0b001100); 106 | 107 | ASSERT(2, ({ int i=6; i&=3; i; })); 108 | ASSERT(7, ({ int i=6; i|=3; i; })); 109 | ASSERT(10, ({ int i=15; i^=5; i; })); 110 | 111 | // [94] 支持<< <<= >> >>= 112 | ASSERT(1, 1<<0); 113 | ASSERT(8, 1<<3); 114 | ASSERT(10, 5<<1); 115 | ASSERT(2, 5>>1); 116 | ASSERT(-1, -1>>1); 117 | ASSERT(1, ({ int i=1; i<<=0; i; })); 118 | ASSERT(8, ({ int i=1; i<<=3; i; })); 119 | ASSERT(10, ({ int i=5; i<<=1; i; })); 120 | ASSERT(2, ({ int i=5; i>>=1; i; })); 121 | ASSERT(-1, -1); 122 | ASSERT(-1, ({ int i=-1; i; })); 123 | ASSERT(-1, ({ int i=-1; i>>=1; i; })); 124 | 125 | // [95] 支持?:操作符 126 | ASSERT(2, 0 ? 1 : 2); 127 | ASSERT(1, 1 ? 1 : 2); 128 | ASSERT(-1, 0 ? -2 : -1); 129 | ASSERT(-2, 1 ? -2 : -1); 130 | ASSERT(4, sizeof(0 ? 1 : 2)); 131 | ASSERT(8, sizeof(0 ? (long)1 : (long)2)); 132 | ASSERT(-1, 0 ? (long)-2 : -1); 133 | ASSERT(-1, 0 ? -2 : (long)-1); 134 | ASSERT(-2, 1 ? (long)-2 : -1); 135 | ASSERT(-2, 1 ? -2 : (long)-1); 136 | 137 | 1 ? -2 : (void)-1; 138 | 139 | // [133] 在一些表达式中用long或ulong替代int 140 | ASSERT(20, ({ int x; int *p=&x; p+20-p; })); 141 | ASSERT(1, ({ int x; int *p=&x; p+20-p>0; })); 142 | ASSERT(-20, ({ int x; int *p=&x; p-20-p; })); 143 | ASSERT(1, ({ int x; int *p=&x; p-20-p<0; })); 144 | 145 | ASSERT(15, (char *)0xffffffffffffffff - (char *)0xfffffffffffffff0); 146 | ASSERT(-15, (char *)0xfffffffffffffff0 - (char *)0xffffffffffffffff); 147 | 148 | // [134] 将指针作为无符号类型进行比较 149 | ASSERT(1, (void *)0xffffffffffffffff > (void *)0); 150 | 151 | printf("[258] [GNU] 支持?:使用操作数\n"); 152 | ASSERT(3, 3?:5); 153 | ASSERT(5, 0?:5); 154 | ASSERT(4, ({ int i = 3; ++i?:10; })); 155 | 156 | printf("[280] 支持long double\n"); 157 | ASSERT(3, (long double)3); 158 | ASSERT(5, (long double)3 + 2); 159 | ASSERT(6, (long double)3 * 2); 160 | ASSERT(5, (long double)3 + 2.0); 161 | ASSERT(6, (long double)3 * 2.0); 162 | ASSERT(4, (long double)64 / 16); 163 | ASSERT(45, (long double)1 + 2 + (char)3 + 4 + 5 + (int)6 + (float)7 + 8 + 9); 164 | ASSERT(2, (long double)8 / 4 + 2 * 4 - 8); 165 | 166 | printf("OK\n"); 167 | return 0; 168 | } 169 | -------------------------------------------------------------------------------- /test/asm.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | // [259] 支持asm语句 4 | char *asm_fn1(void) { asm("li a0, 50"); } 5 | 6 | char *asm_fn2(void) { asm inline volatile("li a0, 55"); } 7 | 8 | int main() { 9 | printf("[259] 支持asm语句\n"); 10 | ASSERT(52, asm_fn1() + 2); 11 | ASSERT(55, asm_fn2()); 12 | 13 | printf("OK\n"); 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /test/atomic.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include 3 | #include 4 | 5 | static int incr(_Atomic int *p) { 6 | int oldval = *p; 7 | int newval; 8 | do { 9 | newval = oldval + 1; 10 | } while (!atomic_compare_exchange_weak(p, &oldval, newval)); 11 | return newval; 12 | } 13 | 14 | static int add1(void *arg) { 15 | _Atomic int *x = arg; 16 | for (int i = 0; i < 1000 * 1000; i++) 17 | incr(x); 18 | return 0; 19 | } 20 | 21 | static int add2(void *arg) { 22 | _Atomic int *x = arg; 23 | for (int i = 0; i < 1000 * 1000; i++) 24 | (*x)++; 25 | return 0; 26 | } 27 | 28 | static int add3(void *arg) { 29 | _Atomic int *x = arg; 30 | for (int i = 0; i < 1000 * 1000; i++) 31 | *x += 5; 32 | return 0; 33 | } 34 | 35 | static int add_millions(void) { 36 | _Atomic int x = 0; 37 | 38 | pthread_t thr1; 39 | pthread_t thr2; 40 | pthread_t thr3; 41 | 42 | pthread_create(&thr1, NULL, add1, &x); 43 | pthread_create(&thr2, NULL, add2, &x); 44 | pthread_create(&thr3, NULL, add3, &x); 45 | 46 | for (int i = 0; i < 1000 * 1000; i++) 47 | x--; 48 | 49 | pthread_join(thr1, NULL); 50 | pthread_join(thr2, NULL); 51 | pthread_join(thr3, NULL); 52 | return x; 53 | } 54 | 55 | int main() { 56 | printf("[309] 支持_Atomic及一些原子操作\n"); 57 | ASSERT(6 * 1000 * 1000, add_millions()); 58 | 59 | printf("[308] 支持原子交换操作\n"); 60 | ASSERT(3, ({ int x=3; atomic_exchange(&x, 5); })); 61 | ASSERT(5, ({ int x=3; atomic_exchange(&x, 5); x; })); 62 | 63 | printf("OK\n"); 64 | return 0; 65 | } 66 | -------------------------------------------------------------------------------- /test/attribute.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include "stddef.h" 3 | 4 | int main() { 5 | printf("[313] 支持__attribute__((packed))"); 6 | ASSERT(5, ({ struct { char a; int b; } __attribute__((packed)) x; sizeof(x); })); 7 | ASSERT(0, offsetof(struct __attribute__((packed)) { char a; int b; }, a)); 8 | ASSERT(1, offsetof(struct __attribute__((packed)) { char a; int b; }, b)); 9 | 10 | ASSERT(5, ({ struct __attribute__((packed)) { char a; int b; } x; sizeof(x); })); 11 | ASSERT(0, offsetof(struct { char a; int b; } __attribute__((packed)), a)); 12 | ASSERT(1, offsetof(struct { char a; int b; } __attribute__((packed)), b)); 13 | 14 | ASSERT(9, ({ typedef struct { char a; int b[2]; } __attribute__((packed)) T; sizeof(T); })); 15 | ASSERT(9, ({ typedef struct __attribute__((packed)) { char a; int b[2]; } T; sizeof(T); })); 16 | 17 | ASSERT(1, offsetof(struct __attribute__((packed)) T { char a; int b[2]; }, b)); 18 | ASSERT(1, _Alignof(struct __attribute__((packed)) { char a; int b[2]; })); 19 | 20 | printf("[314] 支持__attribute__((aligned(N)))\n"); 21 | ASSERT(8, ({ struct __attribute__((aligned(8))) { int a; } x; _Alignof(x); })); 22 | ASSERT(8, ({ struct { int a; } __attribute__((aligned(8))) x; _Alignof(x); })); 23 | 24 | ASSERT(8, ({ struct __attribute__((aligned(8), packed)) { char a; int b; } x; _Alignof(x); })); 25 | ASSERT(8, ({ struct { char a; int b; } __attribute__((aligned(8), packed)) x; _Alignof(x); })); 26 | ASSERT(1, offsetof(struct __attribute__((aligned(8), packed)) { char a; int b; }, b)); 27 | ASSERT(1, offsetof(struct { char a; int b; } __attribute__((aligned(8), packed)), b)); 28 | 29 | ASSERT(8, ({ struct __attribute__((aligned(8))) __attribute__((packed)) { char a; int b; } x; _Alignof(x); })); 30 | ASSERT(8, ({ struct { char a; int b; } __attribute__((aligned(8))) __attribute__((packed)) x; _Alignof(x); })); 31 | ASSERT(1, offsetof(struct __attribute__((aligned(8))) __attribute__((packed)) { char a; int b; }, b)); 32 | ASSERT(1, offsetof(struct { char a; int b; } __attribute__((aligned(8))) __attribute__((packed)), b)); 33 | 34 | ASSERT(8, ({ struct __attribute__((aligned(8))) { char a; int b; } __attribute__((packed)) x; _Alignof(x); })); 35 | ASSERT(1, offsetof(struct __attribute__((aligned(8))) { char a; int b; } __attribute__((packed)), b)); 36 | 37 | ASSERT(16, ({ struct __attribute__((aligned(8+8))) { char a; int b; } x; _Alignof(x); })); 38 | 39 | printf("OK\n"); 40 | return 0; 41 | } 42 | -------------------------------------------------------------------------------- /test/bitfield.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | // [211] 支持全局结构体位域初始化器 4 | struct { 5 | char a; 6 | int b : 5; 7 | int c : 10; 8 | } g45 = {1, 2, 3}, g46={}; 9 | 10 | int main() { 11 | printf("[210] 支持位域\n"); 12 | ASSERT(4, sizeof(struct {int x:1; })); 13 | ASSERT(8, sizeof(struct {long x:1; })); 14 | 15 | struct bit1 { 16 | short a; 17 | char b; 18 | int c : 2; 19 | int d : 3; 20 | int e : 3; 21 | }; 22 | 23 | ASSERT(4, sizeof(struct bit1)); 24 | ASSERT(1, ({ struct bit1 x; x.a=1; x.b=2; x.c=3; x.d=4; x.e=5; x.a; })); 25 | ASSERT(1, ({ struct bit1 x={1,2,3,4,5}; x.a; })); 26 | ASSERT(2, ({ struct bit1 x={1,2,3,4,5}; x.b; })); 27 | ASSERT(-1, ({ struct bit1 x={1,2,3,4,5}; x.c; })); 28 | ASSERT(-4, ({ struct bit1 x={1,2,3,4,5}; x.d; })); 29 | ASSERT(-3, ({ struct bit1 x={1,2,3,4,5}; x.e; })); 30 | 31 | printf("[211] 支持全局结构体位域初始化器\n"); 32 | ASSERT(1, g45.a); 33 | ASSERT(2, g45.b); 34 | ASSERT(3, g45.c); 35 | 36 | ASSERT(0, g46.a); 37 | ASSERT(0, g46.b); 38 | ASSERT(0, g46.c); 39 | 40 | printf("[212] 支持op=风格的位域赋值\n"); 41 | typedef struct { 42 | int a : 10; 43 | int b : 10; 44 | int c : 10; 45 | } T3; 46 | 47 | ASSERT(1, ({ T3 x={1,2,3}; x.a++; })); 48 | ASSERT(2, ({ T3 x={1,2,3}; x.b++; })); 49 | ASSERT(3, ({ T3 x={1,2,3}; x.c++; })); 50 | 51 | ASSERT(2, ({ T3 x={1,2,3}; ++x.a; })); 52 | ASSERT(3, ({ T3 x={1,2,3}; ++x.b; })); 53 | ASSERT(4, ({ T3 x={1,2,3}; ++x.c; })); 54 | 55 | ASSERT(3, ({ T3 x={1,2,3}; x.a+=2; })); 56 | ASSERT(4, ({ T3 x={1,2,3}; x.b*=2; })); 57 | ASSERT(1, ({ T3 x={1,2,3}; x.c/=3; })); 58 | 59 | printf("[213] 处理零宽度位域成员\n"); 60 | ASSERT(4, sizeof(struct {int a:3; int c:1; int c:5;})); 61 | ASSERT(8, sizeof(struct {int a:3; int:0; int c:5;})); 62 | ASSERT(4, sizeof(struct {int a:3; int:0;})); 63 | 64 | printf("OK\n"); 65 | return 0; 66 | } 67 | -------------------------------------------------------------------------------- /test/builtin.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int main() { 4 | printf("[255] [GNU] 支持__builtin_types_compatible_p\n"); 5 | ASSERT(1, __builtin_types_compatible_p(int, int)); 6 | ASSERT(1, __builtin_types_compatible_p(double, double)); 7 | ASSERT(0, __builtin_types_compatible_p(int, long)); 8 | ASSERT(0, __builtin_types_compatible_p(long, float)); 9 | ASSERT(1, __builtin_types_compatible_p(int *, int *)); 10 | ASSERT(0, __builtin_types_compatible_p(short *, int *)); 11 | ASSERT(0, __builtin_types_compatible_p(int **, int *)); 12 | ASSERT(1, __builtin_types_compatible_p(const int, int)); 13 | ASSERT(0, __builtin_types_compatible_p(unsigned, int)); 14 | ASSERT(1, __builtin_types_compatible_p(signed, int)); 15 | ASSERT(0, __builtin_types_compatible_p(struct {int a;}, struct {int a;})); 16 | 17 | ASSERT(1, __builtin_types_compatible_p(int (*)(void), int (*)(void))); 18 | ASSERT(1, __builtin_types_compatible_p(void (*)(int), void (*)(int))); 19 | ASSERT(1, __builtin_types_compatible_p(void (*)(int, double), void (*)(int, double))); 20 | ASSERT(1, __builtin_types_compatible_p(int (*)(float, double), int (*)(float, double))); 21 | ASSERT(0, __builtin_types_compatible_p(int (*)(float, double), int)); 22 | ASSERT(0, __builtin_types_compatible_p(int (*)(float, double), int (*)(float))); 23 | ASSERT(0, __builtin_types_compatible_p(int (*)(float, double), int (*)(float, double, int))); 24 | ASSERT(1, __builtin_types_compatible_p(double (*)(...), double (*)(...))); 25 | ASSERT(0, __builtin_types_compatible_p(double (*)(...), double (*)(void))); 26 | 27 | ASSERT(1, ({ typedef struct {int a;} T; __builtin_types_compatible_p(T, T); })); 28 | ASSERT(1, ({ typedef struct {int a;} T; __builtin_types_compatible_p(T, const T); })); 29 | 30 | ASSERT(1, ({ struct {int a; int b;} x; __builtin_types_compatible_p(typeof(x.a), typeof(x.b)); })); 31 | 32 | printf("OK\n"); 33 | return 0; 34 | } 35 | -------------------------------------------------------------------------------- /test/cast.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int main() { 4 | // [67] 支持类型转换 5 | ASSERT(131585, (int)8590066177); 6 | ASSERT(513, (short)8590066177); 7 | ASSERT(1, (char)8590066177); 8 | ASSERT(1, (long)1); 9 | ASSERT(0, (long)&*(int *)0); 10 | ASSERT(513, ({ int x=512; *(char *)&x=1; x; })); 11 | ASSERT(5, ({ int x=5; long y=(long)&x; *(int*)y; })); 12 | 13 | (void)1; 14 | 15 | printf("[131] 支持无符号整型"); 16 | ASSERT(255, (char)255); 17 | ASSERT(-1, (signed char)255); 18 | ASSERT(255, (unsigned char)255); 19 | ASSERT(-1, (short)65535); 20 | ASSERT(65535, (unsigned short)65535); 21 | ASSERT(-1, (int)0xffffffff); 22 | ASSERT(0xffffffff, (unsigned)0xffffffff); 23 | ASSERT(1, 0 + (unsigned)-1 == -1); 24 | 25 | ASSERT(1, -1<1); 26 | ASSERT(0, -1<(unsigned)1); 27 | ASSERT(254, (char)127+(char)127); 28 | ASSERT(65534, (short)32767+(short)32767); 29 | ASSERT(-1, -1>>1); 30 | ASSERT(1, (unsigned)-1==4294967295); 31 | ASSERT(-1, (unsigned long)-1); 32 | ASSERT(2147483647, ((unsigned)-1)>>1); 33 | ASSERT(-50, (-100)/2); 34 | ASSERT(2147483598, ((unsigned)-100)/2); 35 | ASSERT(9223372036854775758, ((unsigned long)-100)/2); 36 | ASSERT(0, ((long)-1)/(unsigned)100); 37 | ASSERT(-2, (-100)%7); 38 | ASSERT(2, ((unsigned)-100)%7); 39 | ASSERT(6, ((unsigned long)-100)%9); 40 | 41 | ASSERT(65535, (int)(unsigned short)65535); 42 | ASSERT(65535, ({ unsigned short x = 65535; x; })); 43 | ASSERT(65535, ({ unsigned short x = 65535; (int)x; })); 44 | 45 | ASSERT(-1, ({ typedef short T; T x = 65535; (int)x; })); 46 | ASSERT(65535, ({ typedef unsigned short T; T x = 65535; (int)x; })); 47 | ASSERT(0, (unsigned)18446744073709551615UL < (signed char)(-2L)); 48 | ASSERT(1, 115 >= -(unsigned)(4294967286UL)); 49 | 50 | // [140] 支持float和double用于局部变量或类型转换 51 | ASSERT(0, (_Bool)0.0); 52 | ASSERT(1, (_Bool)0.1); 53 | ASSERT(3, (char)3.0); 54 | ASSERT(1000, (short)1000.3); 55 | ASSERT(3, (int)3.99); 56 | ASSERT(2000000000000000, (long)2e15); 57 | ASSERT(3, (float)3.5); 58 | ASSERT(5, (double)(float)5.5); 59 | ASSERT(3, (float)3); 60 | ASSERT(3, (double)3); 61 | ASSERT(3, (float)3L); 62 | ASSERT(3, (double)3L); 63 | 64 | printf("[140] 支持float和double用于局部变量或类型转换\n"); 65 | ASSERT(1, (_Bool)0.1L); 66 | ASSERT(3, (char)3.0L); 67 | ASSERT(3, (int)3.99L); 68 | ASSERT(3, (float)3.5L); 69 | ASSERT(3, (long double)3); 70 | ASSERT(3, (long double)3.0); 71 | ASSERT(3, (long double)3L); 72 | ASSERT(1000, (short)1000.3L); 73 | ASSERT(2000000000000000, (long)2e15L); 74 | ASSERT(5, (long double)(float)5.5L); 75 | 76 | printf("OK\n"); 77 | return 0; 78 | } 79 | -------------------------------------------------------------------------------- /test/common: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void assert(int expected, int actual, char *code) { 6 | if (expected == actual) { 7 | printf("%s => %d\n", code, actual); 8 | } else { 9 | printf("%s => %d expected but got %d\n", code, expected, actual); 10 | exit(1); 11 | } 12 | } 13 | 14 | // [75] 支持文件域内函数 15 | static int static_fn() { return 5; } 16 | 17 | // [116] 支持extern 18 | int ext1 = 5; 19 | int *ext2 = &ext1; 20 | 21 | // [117] 处理块中的extern声明 22 | int ext3 = 7; 23 | int ext_fn1(int x) { return x; } 24 | int ext_fn2(int x) { return x; } 25 | // [265] 支持试探性定义 26 | int common_ext2 = 3; 27 | static int common_local; 28 | 29 | // [126] 支持函数返回短整数 30 | int false_fn() { return 512; } 31 | int true_fn() { return 513; } 32 | int char_fn() { return (2<<8)+3; } 33 | int short_fn() { return (2<<16)+5; } 34 | 35 | // [131] 支持无符号整型 36 | int uchar_fn() { return (2<<10)-1-4; } 37 | int ushort_fn() { return (2<<20)-1-7; } 38 | 39 | int schar_fn() { return (2<<10)-1-4; } 40 | int sshort_fn() { return (2<<20)-1-7; } 41 | 42 | // [127] 允许调用可变参数函数 43 | int add_all(int n, ...) { 44 | va_list ap; 45 | va_start(ap, n); 46 | 47 | int sum = 0; 48 | for (int i = 0; i < n; i++) 49 | sum += va_arg(ap, int); 50 | return sum; 51 | } 52 | 53 | // [144] 允许函数使用浮点数 54 | float add_float(float x, float y) { 55 | return x + y; 56 | } 57 | 58 | double add_double(double x, double y) { 59 | return x + y; 60 | } 61 | 62 | // [198] 支持栈传递实参 63 | int add10_int(int x1, int x2, int x3, int x4, int x5, int x6, int x7, int x8, 64 | int x9, int x10) { 65 | return x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10; 66 | } 67 | 68 | float add10_float(float x1, float x2, float x3, float x4, float x5, float x6, 69 | float x7, float x8, float x9, float x10) { 70 | return x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10; 71 | } 72 | 73 | double add10_double(double x1, double x2, double x3, double x4, double x5, 74 | double x6, double x7, double x8, double x9, double x10) { 75 | return x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10; 76 | } 77 | 78 | double add10_double_int(double x1, double x2, int x3, double x4, int x5, 79 | double x6, int x7, double x8, double x9, 80 | double x10) { 81 | return x1 + x2 + x3 + x4 + x5 + x6 + x7 + x8 + x9 + x10; 82 | } 83 | 84 | double add10_int_double(int a0, int a1, int a2, int a3, int a4, int a5, int a6, 85 | int a7, int s1, int s2, double fa0, double fa1, 86 | double fa2, double fa3, double fa4, double fa5, 87 | double fa6, double fa7, double fs3, double fs4) { 88 | return s2 + fs4; 89 | } 90 | // [200] 支持结构体实参 91 | // 单个成员变量的结构体 92 | typedef struct {_Bool a;} StTy1_1; 93 | typedef struct {short a;} StTy1_2; 94 | typedef struct {unsigned a;} StTy1_3; 95 | typedef struct {long a;} StTy1_4; 96 | 97 | int struct_type_1_1_test(StTy1_1 x) { return x.a; } 98 | int struct_type_1_2_test(StTy1_2 x) { return x.a; } 99 | int struct_type_1_3_test(StTy1_3 x) { return x.a; } 100 | int struct_type_1_4_test(StTy1_4 x) { return x.a; } 101 | 102 | // 使用一个寄存器的结构体 103 | typedef struct {char a;char b;char c;char d;char e;char f;char g;char h;} StTy2_1; 104 | typedef struct {int a;int b;} StTy2_2; 105 | typedef struct {unsigned a;unsigned b;} StTy2_3; 106 | 107 | int struct_type_2_1_test(StTy2_1 x, int n) {switch(n){case 0: return x.a; case 1: return x.b; case 2: return x.c;case 3: return x.d;case 4: return x.e;case 5:return x.f;case 6: return x.g;case 7: return x.h; default: return -1; }} 108 | int struct_type_2_2_test(StTy2_2 x, int n) {switch(n){case 0: return x.a; case 1: return x.b; default: return -1; }} 109 | int struct_type_2_3_test(StTy2_3 x, int n) {switch(n){case 0: return x.a; case 1: return x.b; default: return -1; }} 110 | 111 | typedef struct {char a;char b;char c;char d;int e;} StTy3_1; 112 | typedef struct {char a;char b;char c;int d;} StTy3_2; 113 | typedef struct {char a;short b;char c;short d;} StTy3_3; 114 | 115 | int struct_type_3_1_test(StTy3_1 x, int n) {switch(n){case 0: return x.a; case 1: return x.b; case 2: return x.c;case 3: return x.d;case 4: return x.e;default: return -1; }} 116 | int struct_type_3_2_test(StTy3_2 x, int n) {switch(n){case 0: return x.a; case 1: return x.b; case 2: return x.c;case 3: return x.d;default: return -1; }} 117 | int struct_type_3_3_test(StTy3_3 x, int n) {switch(n){case 0: return x.a; case 1: return x.b; case 2: return x.c;case 3: return x.d;default: return -1; }} 118 | 119 | // 使用两个寄存器的结构体 120 | typedef struct {char a;char b;char c;char d;int e;char f;int g;} StTy4_1; 121 | typedef struct {char a;char b;char c;int d;char e;} StTy4_2; 122 | typedef struct {char a;short b;char c;short d;char e;short f;} StTy4_3; 123 | typedef struct {char a;short b;char c;short d;int e;short f;char g;} StTy4_4; 124 | 125 | int struct_type_4_1_test(StTy4_1 x, int n) {switch(n){case 0: return x.a; case 1: return x.b; case 2: return x.c;case 3: return x.d;case 4: return x.e;case 5: return x.f;case 6: return x.g;default: return -1; }} 126 | int struct_type_4_2_test(StTy4_2 x, int n) {switch(n){case 0: return x.a; case 1: return x.b; case 2: return x.c;case 3: return x.d;case 4: return x.e;default: return -1; }} 127 | int struct_type_4_3_test(StTy4_3 x, int n) {switch(n){case 0: return x.a; case 1: return x.b; case 2: return x.c;case 3: return x.d;case 4: return x.e;case 5: return x.f;default: return -1; }} 128 | int struct_type_4_4_test(StTy4_4 x, int n) {switch(n){case 0: return x.a; case 1: return x.b; case 2: return x.c;case 3: return x.d;case 4: return x.e;case 5: return x.f;case 6: return x.g;default: return -1; }} 129 | 130 | // 使用地址传递的结构体 131 | typedef struct {long a;long b;long c;} StTy5_1; 132 | typedef struct {long a;long b;long c;long d;long e;long f;long g;long h;} StTy5_2; 133 | 134 | int struct_type_5_1_test(StTy5_1 x, int n) {switch(n){case 0: return x.a; case 1: return x.b; case 2: return x.c;default: return -1; }} 135 | int struct_type_5_2_test(StTy5_2 x, int n) {switch(n){case 0: return x.a; case 1: return x.b; case 2: return x.c;case 3: return x.d;case 4: return x.e;case 5:return x.f;case 6: return x.g;case 7: return x.h; default: return -1; }} 136 | int struct_type_5_3_test(StTy5_1 x, StTy5_1 y, int n) {switch(n){case 0: return x.a; case 1: return x.b; case 2: return x.c;case 3: return y.a; case 4: return y.b; case 5: return y.c; default: return -1; }} 137 | int struct_type_5_4_test(int aa, StTy5_1 x, int bb, StTy5_1 y, int n) {int cc = 123; switch(n){case 0: return x.a; case 1: return x.b; case 2: return x.c;case 3: return y.a; case 4: return y.b; case 5: return y.c; default: return -1; int dd=456; }} 138 | 139 | // 掺杂浮点的结构体(成员数>=3) 140 | typedef struct {char a;float b;char c;} StTy6_1; 141 | 142 | int struct_type_6_1_test(StTy6_1 x, int n) {switch(n){case 0: return x.a; case 1: return x.b; case 2: return x.c;default: return -1; }} 143 | 144 | // 掺杂浮点的结构体(成员数==1) 145 | typedef struct {float a;} StTy7_1; 146 | typedef struct {double a;} StTy7_2; 147 | 148 | int struct_type_7_1_test(StTy7_1 x) { return x.a; } 149 | int struct_type_7_2_test(StTy7_2 x) { return x.a; } 150 | 151 | // 掺杂浮点的结构体(成员数==2) 152 | typedef struct {float a;char b;} StTy8_1; 153 | typedef struct {int a;double b;} StTy8_2; 154 | typedef struct {float a;float b;} StTy8_3; 155 | typedef struct {int a;float b;} StTy8_4; 156 | 157 | int struct_type_8_1_test(StTy8_1 x, int n) {switch(n){case 0: return x.a; case 1: return x.b; default: return -1; }} 158 | int struct_type_8_2_test(StTy8_2 x, int n) {switch(n){case 0: return x.a; case 1: return x.b; default: return -1; }} 159 | int struct_type_8_3_test(StTy8_3 x, int n) {switch(n){case 0: return x.a; case 1: return x.b; default: return -1; }} 160 | int struct_type_8_4_test(StTy8_4 x, int n) {switch(n){case 0: return x.a; case 1: return x.b; default: return -1; }} 161 | 162 | // 栈传递两个寄存器的结构体(整体) 163 | typedef struct {long a;char b;} StTy9_1; 164 | int struct_type_9_1_test(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, StTy9_1 x, int n) {switch (n) {case 0:return x.a;case 1:return x.b;default:return -1;}} 165 | 166 | // 栈传递两个寄存器的结构体(一半) 167 | int struct_type_10_1_test(int a0, int a1, int a2, int a3, int a4, int a5, int a6, StTy9_1 x, int n) { switch (n) { case 0: return x.a; case 1: return x.b; default: return -1; } } 168 | // 栈传递两个寄存器的结构体(整体,含浮点) 169 | int struct_type_11_1_test(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, StTy8_4 x, int n) { switch (n) { case 0: return x.a; case 1: return x.b; default: return -1; } } 170 | int struct_type_11_2_test(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, StTy8_2 x, int n) { switch (n) { case 0: return x.a; case 1: return x.b; default: return -1; } } 171 | int struct_type_11_3_test(int a0, int a1, int a2, int a3, int a4, int a5, int a6, int a7, StTy8_1 x, int n) { switch (n) { case 0: return x.a; case 1: return x.b; default: return -1; } } 172 | // 栈传递两个寄存器的结构体(一半,含浮点) 173 | int struct_type_12_1_test(int a0, int a1, int a2, int a3, int a4, int a5, int a6, StTy8_4 x, int n) { switch (n) { case 0: return x.a; case 1: return x.b; default: return -1; } } 174 | 175 | // 结构体包含浮点数组 176 | typedef struct {float a[2];} StTy13_1; 177 | int struct_type_13_1_test(StTy13_1 x, int n) {return x.a[n];} 178 | 179 | // 联合体 180 | typedef union {float a; int b;} UnTy1_1; 181 | typedef union {float a; int b; long c;} UnTy1_2; 182 | int union_type_1_1_test(UnTy1_1 x, int n) {switch (n) { case 0: return x.a; case 1: return x.b; default: return -1;}} 183 | int union_type_1_2_test(UnTy1_2 x, int n) {switch (n) { case 0: return x.a; case 1: return x.b; case 2: return x.c; default: return -1;}} 184 | 185 | // [200] 支持结构体实参 186 | typedef struct { int a,b; short c; char d; } Ty4; 187 | typedef struct { int a; float b; double c; } Ty5; 188 | typedef struct { unsigned char a[3]; } Ty6; 189 | typedef struct { long a, b, c; } Ty7; 190 | 191 | int struct_test4(Ty4 x, int n) {switch (n) {case 0: return x.a;case 1: return x.b;case 2: return x.c;default: return x.d;}} 192 | int struct_test5(Ty5 x, int n) {switch (n) {case 0: return x.a;case 1: return x.b;default: return x.c;}} 193 | int struct_test6(Ty6 x, int n) {return x.a[n];} 194 | int struct_test7(Ty7 x, int n) {switch (n) {case 0: return x.a;case 1: return x.b;default: return x.c;}} 195 | 196 | // [202] 支持调用返回结构体的函数 197 | // 单个成员变量的结构体 198 | StTy1_1 struct_type_1_1_test_3() { return (StTy1_1){10}; } 199 | StTy1_2 struct_type_1_2_test_3() { return (StTy1_2){10}; } 200 | StTy1_3 struct_type_1_3_test_3() { return (StTy1_3){10}; } 201 | StTy1_4 struct_type_1_4_test_3() { return (StTy1_4){10}; } 202 | 203 | // 使用一个寄存器的结构体 204 | StTy2_1 struct_type_2_1_test_3() {return (StTy2_1){10,20,30,40,50,60,70,80}; } 205 | StTy2_2 struct_type_2_2_test_3() {return (StTy2_2){10,20};} 206 | StTy2_3 struct_type_2_3_test_3() {return (StTy2_3){10,20};} 207 | 208 | StTy3_1 struct_type_3_1_test_3() { return (StTy3_1){10, 20, 30, 40, 50}; } 209 | StTy3_2 struct_type_3_2_test_3() { return (StTy3_2){10, 20, 30, 40}; } 210 | StTy3_3 struct_type_3_3_test_3() { return (StTy3_3){10, 20, 30, 40}; } 211 | 212 | // 使用两个寄存器的结构体 213 | StTy4_1 struct_type_4_1_test_3() {return (StTy4_1){10,20,30,40,50,60,70}; } 214 | StTy4_2 struct_type_4_2_test_3() {return (StTy4_2){10,20,30,40,50}; } 215 | StTy4_3 struct_type_4_3_test_3() {return (StTy4_3){10,20,30,40,50,60}; } 216 | StTy4_4 struct_type_4_4_test_3() {return (StTy4_4){10,20,30,40,50,60,70}; } 217 | 218 | // 使用地址传递的结构体 219 | StTy5_1 struct_type_5_1_test_3() {return (StTy5_1){10,20,30}; } 220 | StTy5_2 struct_type_5_2_test_3() {return (StTy5_2){10,20,30,40,50,60,70,80}; } 221 | 222 | // 掺杂浮点的结构体(成员数>=3) 223 | StTy6_1 struct_type_6_1_test_3() { return (StTy6_1){10, 20.8, 30}; } 224 | 225 | // 掺杂浮点的结构体(成员数==1) 226 | StTy7_1 struct_type_7_1_test_3() { return (StTy7_1){10.8}; } 227 | StTy7_2 struct_type_7_2_test_3() { return (StTy7_2){10.8}; } 228 | 229 | // 掺杂浮点的结构体(成员数==2) 230 | StTy8_1 struct_type_8_1_test_3() { return (StTy8_1){10.8,20}; } 231 | StTy8_2 struct_type_8_2_test_3() { return (StTy8_2){10,20.8}; } 232 | 233 | // [202] 支持调用返回结构体的函数 234 | Ty4 struct_test24(void) { 235 | return (Ty4){10, 20, 30, 40}; 236 | } 237 | 238 | Ty5 struct_test25(void) { 239 | return (Ty5){10, 20, 30}; 240 | } 241 | 242 | Ty6 struct_test26(void) { 243 | return (Ty6){10, 20, 30}; 244 | } 245 | 246 | typedef struct { unsigned char a[10]; } Ty20; 247 | typedef struct { unsigned char a[20]; } Ty21; 248 | 249 | Ty20 struct_test27(void) { 250 | return (Ty20){10, 20, 30, 40, 50, 60, 70, 80, 90, 100}; 251 | } 252 | 253 | Ty21 struct_test28(void) { 254 | return (Ty21){1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20}; 255 | } 256 | 257 | typedef struct { 258 | long a; 259 | long b; 260 | float c; 261 | } Ty22; 262 | 263 | Ty22 struct_test29(void) { 264 | return (Ty22){10,20,30}; 265 | } 266 | 267 | // [204] 支持可变参数函数接受任意数量的参数 268 | int sum2_3(float b, int x, ...) { 269 | va_list ap; 270 | va_start(ap, x); 271 | x += b; 272 | 273 | for (;;) { 274 | double y = va_arg(ap, double); 275 | x += y; 276 | 277 | int z = va_arg(ap, int); 278 | if (z == 0) 279 | return x; 280 | x += z; 281 | } 282 | } 283 | 284 | int sum2_5(int a0, float fa0, int a1, int a2, int a3, int a4, float fa1, int a5, 285 | int a6, int a7, int x, ...) { 286 | x += fa0; 287 | x += fa1; 288 | 289 | x += a0; 290 | x += a1; 291 | x += a2; 292 | x += a3; 293 | x += a4; 294 | x += a5; 295 | x += a6; 296 | x += a7; 297 | 298 | va_list ap; 299 | va_start(ap, x); 300 | 301 | for (;;) { 302 | int z = va_arg(ap, int); 303 | if (z == 0) 304 | return x; 305 | x += z; 306 | } 307 | } 308 | // [280] 支持long double 309 | int add_long_double(int a, long double b, float c) { 310 | return a+b+c; 311 | } 312 | 313 | typedef struct {int a; long double b;} LDSt_1; 314 | int ld_struct_test_1(LDSt_1 x, int n) {switch(n){case 0:return x.a;break;case 1:return x.b;break;default:return -1;break;}} 315 | -------------------------------------------------------------------------------- /test/commonsym.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | // [265] 支持试探性定义 4 | int x; 5 | int x = 5; 6 | int y = 7; 7 | int y; 8 | int common_ext1; 9 | int common_ext2; 10 | static int common_local; 11 | 12 | int main() { 13 | printf("[265] 支持试探性定义\n"); 14 | ASSERT(5, x); 15 | ASSERT(7, y); 16 | ASSERT(0, common_ext1); 17 | ASSERT(3, common_ext2); 18 | 19 | printf("OK\n"); 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /test/compat.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | _Noreturn noreturn_fn(int restrict x) { 4 | exit(0); 5 | } 6 | 7 | // [137] 忽略数组维度的static和const 8 | void funcy_type(int arg[restrict static 3]) {} 9 | 10 | int main() { 11 | // [136] 忽略const volatile auto register restrict _Noreturn 12 | { volatile x; } 13 | { int volatile x; } 14 | { volatile int x; } 15 | { volatile int volatile volatile x; } 16 | { int volatile * volatile volatile x; } 17 | { auto ** restrict __restrict __restrict__ const volatile *x; } 18 | 19 | printf("OK\n"); 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /test/complit.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | // [121] 支持复合字面量 4 | typedef struct Tree { 5 | int val; 6 | struct Tree *lhs; 7 | struct Tree *rhs; 8 | } Tree; 9 | 10 | Tree *tree = &(Tree){ 11 | 1, 12 | &(Tree){ 13 | 2, 14 | &(Tree){ 3, 0, 0 }, 15 | &(Tree){ 4, 0, 0 } 16 | }, 17 | 0 18 | }; 19 | 20 | int main() { 21 | // [121] 支持复合字面量 22 | ASSERT(1, (int){1}); 23 | ASSERT(2, ((int[]){0,1,2})[2]); 24 | ASSERT('a', ((struct {char a; int b;}){'a', 3}).a); 25 | ASSERT(3, ({ int x=3; (int){x}; })); 26 | (int){3} = 5; 27 | 28 | ASSERT(1, tree->val); 29 | ASSERT(2, tree->lhs->val); 30 | ASSERT(3, tree->lhs->lhs->val); 31 | ASSERT(4, tree->lhs->rhs->val); 32 | 33 | printf("OK\n"); 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /test/const.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int main() { 4 | // [136] 忽略const volatile auto register restrict _Noreturn 5 | { const x; } 6 | { int const x; } 7 | { const int x; } 8 | { const int const const x; } 9 | ASSERT(5, ({ const x = 5; x; })); 10 | ASSERT(8, ({ const x = 8; int *const y=&x; *y; })); 11 | ASSERT(6, ({ const x = 6; *(const * const)&x; })); 12 | 13 | printf("OK\n"); 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /test/constexpr.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | // [148] 支持浮点数常量表达式 4 | float g40 = 1.5; 5 | double g41 = 0.0 ? 55 : (0, 1 + 1 * 5.0 / 2 * (double)2 * (int)2.0); 6 | 7 | int main() { 8 | // [96] 支持常量表达式 9 | ASSERT(10, ({ enum { ten=1+2+3+4 }; ten; })); 10 | ASSERT(1, ({ int i=0; switch(3) { case 5-2+0*3: i++; } i; })); 11 | ASSERT(8, ({ int x[1+1]; sizeof(x); })); 12 | ASSERT(6, ({ char x[8-2]; sizeof(x); })); 13 | ASSERT(6, ({ char x[2*3]; sizeof(x); })); 14 | ASSERT(3, ({ char x[12/4]; sizeof(x); })); 15 | ASSERT(2, ({ char x[12%10]; sizeof(x); })); 16 | ASSERT(0b100, ({ char x[0b110&0b101]; sizeof(x); })); 17 | ASSERT(0b111, ({ char x[0b110|0b101]; sizeof(x); })); 18 | ASSERT(0b110, ({ char x[0b111^0b001]; sizeof(x); })); 19 | ASSERT(4, ({ char x[1<<2]; sizeof(x); })); 20 | ASSERT(2, ({ char x[4>>1]; sizeof(x); })); 21 | ASSERT(2, ({ char x[(1==1)+1]; sizeof(x); })); 22 | ASSERT(1, ({ char x[(1!=1)+1]; sizeof(x); })); 23 | ASSERT(1, ({ char x[(1<1)+1]; sizeof(x); })); 24 | ASSERT(2, ({ char x[(1<=1)+1]; sizeof(x); })); 25 | ASSERT(2, ({ char x[1?2:3]; sizeof(x); })); 26 | ASSERT(3, ({ char x[0?2:3]; sizeof(x); })); 27 | ASSERT(3, ({ char x[(1,3)]; sizeof(x); })); 28 | ASSERT(2, ({ char x[!0+1]; sizeof(x); })); 29 | ASSERT(1, ({ char x[!1+1]; sizeof(x); })); 30 | ASSERT(2, ({ char x[~-3]; sizeof(x); })); 31 | ASSERT(2, ({ char x[(5||6)+1]; sizeof(x); })); 32 | ASSERT(1, ({ char x[(0||0)+1]; sizeof(x); })); 33 | ASSERT(2, ({ char x[(1&&1)+1]; sizeof(x); })); 34 | ASSERT(1, ({ char x[(1&&0)+1]; sizeof(x); })); 35 | ASSERT(3, ({ char x[(int)3]; sizeof(x); })); 36 | ASSERT(15, ({ char x[(char)0xffffff0f]; sizeof(x); })); 37 | ASSERT(0x10f, ({ char x[(short)0xffff010f]; sizeof(x); })); 38 | ASSERT(4, ({ char x[(int)0xfffffffffff+5]; sizeof(x); })); 39 | ASSERT(8, ({ char x[(int*)0+2]; sizeof(x); })); 40 | ASSERT(12, ({ char x[(int*)16-1]; sizeof(x); })); 41 | ASSERT(3, ({ char x[(int*)16-(int*)4]; sizeof(x); })); 42 | 43 | // [135] 处理常量表达式的无符号类型 44 | ASSERT(4, ({ char x[(-1>>31)+5]; sizeof(x); })); 45 | ASSERT(255, ({ char x[(unsigned char)0xffffffff]; sizeof(x); })); 46 | ASSERT(0x800f, ({ char x[(unsigned short)0xffff800f]; sizeof(x); })); 47 | ASSERT(1, ({ char x[(unsigned int)0xfffffffffff>>31]; sizeof(x); })); 48 | ASSERT(1, ({ char x[(long)-1/((long)1<<62)+1]; sizeof(x); })); 49 | ASSERT(4, ({ char x[(unsigned long)-1/((long)1<<62)+1]; sizeof(x); })); 50 | ASSERT(1, ({ char x[(unsigned)1<-1]; sizeof(x); })); 51 | ASSERT(1, ({ char x[(unsigned)1<=-1]; sizeof(x); })); 52 | 53 | // [148] 支持浮点数常量表达式 54 | ASSERT(1, g40==1.5); 55 | ASSERT(1, g41==11); 56 | 57 | printf("OK\n"); 58 | return 0; 59 | } 60 | -------------------------------------------------------------------------------- /test/control.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | /* 4 | * This is a block comment. 5 | */ 6 | 7 | int main() { 8 | // [15] 支持if语句 9 | ASSERT(3, ({ int x; if (0) x=2; else x=3; x; })); 10 | ASSERT(3, ({ int x; if (1-1) x=2; else x=3; x; })); 11 | ASSERT(2, ({ int x; if (1) x=2; else x=3; x; })); 12 | ASSERT(2, ({ int x; if (2-1) x=2; else x=3; x; })); 13 | 14 | // [16] 支持for语句 15 | ASSERT(55, ({ int i=0; int j=0; for (i=0; i<=10; i=i+1) j=i+j; j; })); 16 | 17 | // [17] 支持while语句 18 | ASSERT(10, ({ int i=0; while(i<10) i=i+1; i; })); 19 | 20 | // [13] 支持{...} 21 | ASSERT(3, ({ 1; {2;} 3; })); 22 | // [14] 支持空语句 23 | ASSERT(5, ({ ;;; 5; })); 24 | 25 | ASSERT(10, ({ int i=0; while(i<10) i=i+1; i; })); 26 | ASSERT(55, ({ int i=0; int j=0; while(i<=10) {j=i+j; i=i+1;} j; })); 27 | 28 | // [48] 支持 , 运算符 29 | ASSERT(3, (1,2,3)); 30 | ASSERT(5, ({ int i=2, j=3; (i=5,j)=6; i; })); 31 | ASSERT(6, ({ int i=2, j=3; (i=5,j)=6; j; })); 32 | 33 | // [76] 支持循环域内定义局部变量 34 | ASSERT(55, ({ int j=0; for (int i=0; i<=10; i=i+1) j=j+i; j; })); 35 | ASSERT(3, ({ int i=3; int j=0; for (int i=0; i<=10; i=i+1) j=j+i; i; })); 36 | 37 | // [85] 支持 &&和 || 38 | ASSERT(1, 0||1); 39 | ASSERT(1, 0||(2-2)||5); 40 | ASSERT(0, 0||0); 41 | ASSERT(0, 0||(2-2)); 42 | 43 | ASSERT(0, 0&&1); 44 | ASSERT(0, (2-2)&&5); 45 | ASSERT(1, 1&&5); 46 | 47 | // [89] 支持goto和标签语句 48 | ASSERT(3, ({ int i=0; goto a; a: i++; b: i++; c: i++; i; })); 49 | ASSERT(2, ({ int i=0; goto e; d: i++; e: i++; f: i++; i; })); 50 | ASSERT(1, ({ int i=0; goto i; g: i++; h: i++; i: i++; i; })); 51 | 52 | // [90] 解决typedef和标签之间的冲突 53 | ASSERT(1, ({ typedef int foo; goto foo; foo:; 1; })); 54 | 55 | // [91] 支持break语句 56 | ASSERT(3, ({ int i=0; for(;i<10;i++) { if (i == 3) break; } i; })); 57 | ASSERT(4, ({ int i=0; while (1) { if (i++ == 3) break; } i; })); 58 | ASSERT(3, ({ int i=0; for(;i<10;i++) { for (;;) break; if (i == 3) break; } i; })); 59 | ASSERT(4, ({ int i=0; while (1) { while(1) break; if (i++ == 3) break; } i; })); 60 | 61 | // [92] 支持continue语句 62 | ASSERT(10, ({ int i=0; int j=0; for (;i<10;i++) { if (i>5) continue; j++; } i; })); 63 | ASSERT(6, ({ int i=0; int j=0; for (;i<10;i++) { if (i>5) continue; j++; } j; })); 64 | ASSERT(10, ({ int i=0; int j=0; for(;!i;) { for (;j!=10;j++) continue; break; } j; })); 65 | ASSERT(11, ({ int i=0; int j=0; while (i++<10) { if (i>5) continue; j++; } i; })); 66 | ASSERT(5, ({ int i=0; int j=0; while (i++<10) { if (i>5) continue; j++; } j; })); 67 | ASSERT(11, ({ int i=0; int j=0; while(!i) { while (j++!=10) continue; break; } j; })); 68 | 69 | // [93] 支持switch和case 70 | ASSERT(5, ({ int i=0; switch(0) { case 0:i=5;break; case 1:i=6;break; case 2:i=7;break; } i; })); 71 | ASSERT(6, ({ int i=0; switch(1) { case 0:i=5;break; case 1:i=6;break; case 2:i=7;break; } i; })); 72 | ASSERT(7, ({ int i=0; switch(2) { case 0:i=5;break; case 1:i=6;break; case 2:i=7;break; } i; })); 73 | ASSERT(0, ({ int i=0; switch(3) { case 0:i=5;break; case 1:i=6;break; case 2:i=7;break; } i; })); 74 | ASSERT(5, ({ int i=0; switch(0) { case 0:i=5;break; default:i=7; } i; })); 75 | ASSERT(7, ({ int i=0; switch(1) { case 0:i=5;break; default:i=7; } i; })); 76 | ASSERT(2, ({ int i=0; switch(1) { case 0: 0; case 1: 0; case 2: 0; i=2; } i; })); 77 | ASSERT(0, ({ int i=0; switch(3) { case 0: 0; case 1: 0; case 2: 0; i=2; } i; })); 78 | 79 | ASSERT(3, ({ int i=0; switch(-1) { case 0xffffffff: i=3; break; } i; })); 80 | 81 | // [124] 支持do while语句 82 | ASSERT(7, ({ int i=0; int j=0; do { j++; } while (i++ < 6); j; })); 83 | ASSERT(4, ({ int i=0; int j=0; int k=0; do { if (++j > 3) break; continue; k++; } while (1); j; })); 84 | 85 | // [143] 支持浮点数的 if while do ! ?: || 和 && 86 | ASSERT(0, 0.0 && 0.0); 87 | ASSERT(0, 0.0 && 0.1); 88 | ASSERT(0, 0.3 && 0.0); 89 | ASSERT(1, 0.3 && 0.5); 90 | ASSERT(0, 0.0 || 0.0); 91 | ASSERT(1, 0.0 || 0.1); 92 | ASSERT(1, 0.3 || 0.0); 93 | ASSERT(1, 0.3 || 0.5); 94 | ASSERT(5, ({ int x; if (0.0) x=3; else x=5; x; })); 95 | ASSERT(3, ({ int x; if (0.1) x=3; else x=5; x; })); 96 | ASSERT(5, ({ int x=5; if (0.0) x=3; x; })); 97 | ASSERT(3, ({ int x=5; if (0.1) x=3; x; })); 98 | ASSERT(10, ({ double i=10.0; int j=0; for (; i; i--, j++); j; })); 99 | ASSERT(10, ({ double i=10.0; int j=0; do j++; while(--i); j; })); 100 | 101 | printf("[281] 支持范围case\n"); 102 | ASSERT(2, ({ int i=0; switch(7) { case 0 ... 5: i=1; break; case 6 ... 20: i=2; break; } i; })); 103 | ASSERT(1, ({ int i=0; switch(7) { case 0 ... 7: i=1; break; case 8 ... 10: i=2; break; } i; })); 104 | ASSERT(1, ({ int i=0; switch(7) { case 0: i=1; break; case 7 ... 7: i=1; break; } i; })); 105 | 106 | printf("[283] [GNU] 支持标签作为值\n"); 107 | ASSERT(3, ({ void *p = &&v11; int i=0; goto *p; v11:i++; v12:i++; v13:i++; i; })); 108 | ASSERT(2, ({ void *p = &&v22; int i=0; goto *p; v21:i++; v22:i++; v23:i++; i; })); 109 | ASSERT(1, ({ void *p = &&v33; int i=0; goto *p; v31:i++; v32:i++; v33:i++; i; })); 110 | 111 | printf("[284] [GNU] 将标签值作为编译时常量\n"); 112 | ASSERT(3, ({ static void *p[]={&&v41,&&v42,&&v43}; int i=0; goto *p[0]; v41:i++; v42:i++; v43:i++; i; })); 113 | ASSERT(2, ({ static void *p[]={&&v52,&&v52,&&v53}; int i=0; goto *p[1]; v51:i++; v52:i++; v53:i++; i; })); 114 | ASSERT(1, ({ static void *p[]={&&v62,&&v62,&&v63}; int i=0; goto *p[2]; v61:i++; v62:i++; v63:i++; i; })); 115 | 116 | printf("OK\n"); 117 | return 0; 118 | } 119 | -------------------------------------------------------------------------------- /test/decl.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int main() { 4 | // [62] 修正解析复杂类型声明 5 | ASSERT(1, ({ char x; sizeof(x); })); 6 | ASSERT(2, ({ short int x; sizeof(x); })); 7 | ASSERT(2, ({ int short x; sizeof(x); })); 8 | ASSERT(4, ({ int x; sizeof(x); })); 9 | ASSERT(8, ({ long int x; sizeof(x); })); 10 | ASSERT(8, ({ int long x; sizeof(x); })); 11 | 12 | // [63] 支持long long 13 | ASSERT(8, ({ long long x; sizeof(x); })); 14 | 15 | // [72] 支持_Bool类型 16 | ASSERT(0, ({ _Bool x=0; x; })); 17 | ASSERT(1, ({ _Bool x=1; x; })); 18 | ASSERT(1, ({ _Bool x=2; x; })); 19 | ASSERT(1, (_Bool)1); 20 | ASSERT(1, (_Bool)2); 21 | ASSERT(0, (_Bool)(char)256); 22 | 23 | printf("OK\n"); 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /test/driver.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | rvcc=$1 3 | 4 | # 创建一个临时文件夹,XXXXXX会被替换为随机字符串 5 | tmp=`mktemp -d /tmp/rvcc-test-XXXXXX` 6 | # 清理工作 7 | # 在接收到 中断(ctrl+c),终止,挂起(ssh掉线,用户退出),退出 信号时 8 | # 执行rm命令,删除掉新建的临时文件夹 9 | trap 'rm -rf $tmp' INT TERM HUP EXIT 10 | # 在临时文件夹内,新建一个空文件,名为empty.c 11 | echo > $tmp/empty.c 12 | 13 | # 判断返回值是否为0来判断程序是否成功执行 14 | check() { 15 | if [ $? -eq 0 ]; then 16 | echo "testing $1 ... passed" 17 | else 18 | echo "testing $1 ... failed" 19 | exit 1 20 | fi 21 | } 22 | 23 | # -o 24 | # 清理掉$tmp中的out文件 25 | rm -f $tmp/out 26 | # 编译生成out文件 27 | $rvcc -c -o $tmp/out $tmp/empty.c 28 | # 条件判断,是否存在out文件 29 | [ -f $tmp/out ] 30 | # 将-o传入check函数 31 | check -o 32 | 33 | # --help 34 | # 将--help的结果传入到grep进行 行过滤 35 | # -q不输出,是否匹配到存在rvcc字符串的行结果 36 | $rvcc --help 2>&1 | grep -q rvcc 37 | # 将--help传入check函数 38 | check --help 39 | 40 | # -S 41 | echo 'int main() {}' | $rvcc -S -o- -xc - | grep -q 'main:' 42 | check -S 43 | 44 | # 默认输出的文件 45 | rm -f $tmp/out.o $tmp/out.s 46 | echo 'int main() {}' > $tmp/out.c 47 | ($rvcc -c $tmp/out.c > $tmp/out.o ) 48 | [ -f $tmp/out.o ] 49 | check 'default output file' 50 | 51 | ($rvcc -c -S $tmp/out.c > $tmp/out.s) 52 | [ -f $tmp/out.s ] 53 | check 'default output file' 54 | 55 | # [156] 接受多个输入文件 56 | rm -f $tmp/foo.o $tmp/bar.o 57 | echo 'int x;' > $tmp/foo.c 58 | echo 'int y;' > $tmp/bar.c 59 | (cd $tmp; $OLDPWD/$rvcc -c $tmp/foo.c $tmp/bar.c) 60 | [ -f $tmp/foo.o ] && [ -f $tmp/bar.o ] 61 | check 'multiple input files' 62 | 63 | rm -f $tmp/foo.s $tmp/bar.s 64 | echo 'int x;' > $tmp/foo.c 65 | echo 'int y;' > $tmp/bar.c 66 | (cd $tmp; $OLDPWD/$rvcc -c -S $tmp/foo.c $tmp/bar.c) 67 | [ -f $tmp/foo.s ] && [ -f $tmp/bar.s ] 68 | check 'multiple input files' 69 | 70 | # [157] 无-c时调用ld 71 | # 调用链接器 72 | rm -f $tmp/foo 73 | echo 'int main() { return 0; }' | $rvcc -o $tmp/foo -xc - 74 | if [ "$RISCV" = "" ];then 75 | $tmp/foo 76 | else 77 | $RISCV/bin/qemu-riscv64 -L $RISCV/sysroot $tmp/foo 78 | fi 79 | check linker 80 | 81 | rm -f $tmp/foo 82 | echo 'int bar(); int main() { return bar(); }' > $tmp/foo.c 83 | echo 'int bar() { return 42; }' > $tmp/bar.c 84 | $rvcc -o $tmp/foo $tmp/foo.c $tmp/bar.c 85 | if [ "$RISCV" = "" ];then 86 | $tmp/foo 87 | else 88 | $RISCV/bin/qemu-riscv64 -L $RISCV/sysroot $tmp/foo 89 | fi 90 | [ "$?" = 42 ] 91 | check linker 92 | 93 | # 生成a.out 94 | rm -f $tmp/a.out 95 | echo 'int main() {}' > $tmp/foo.c 96 | (cd $tmp; $OLDPWD/$rvcc foo.c) 97 | [ -f $tmp/a.out ] 98 | check a.out 99 | 100 | # -E 101 | # [162] 支持-E选项 102 | echo foo > $tmp/out 103 | echo "#include \"$tmp/out\"" | $rvcc -E -xc - | grep -q foo 104 | check -E 105 | 106 | echo foo > $tmp/out1 107 | echo "#include \"$tmp/out1\"" | $rvcc -E -o $tmp/out2 -xc - 108 | cat $tmp/out2 | grep -q foo 109 | check '-E and -o' 110 | 111 | # [185] 支持 -I 选项 112 | # -I 113 | mkdir $tmp/dir 114 | echo foo > $tmp/dir/i-option-test 115 | echo "#include \"i-option-test\"" | $rvcc -I$tmp/dir -E -xc - | grep -q foo 116 | check -I 117 | 118 | # [208] 支持-D选项 119 | # -D 120 | echo foo | $rvcc -Dfoo -E -xc - | grep -q 1 121 | check -D 122 | 123 | # -D 124 | echo foo | $rvcc -Dfoo=bar -E -xc - | grep -q bar 125 | check -D 126 | 127 | # [209] 支持-U选项 128 | # -U 129 | echo foo | $rvcc -Dfoo=bar -Ufoo -E -xc - | grep -q foo 130 | check -U 131 | 132 | # [216] 忽略多个链接器选项 133 | $rvcc -c -O -Wall -g -std=c11 -ffreestanding -fno-builtin \ 134 | -fno-omit-frame-pointer -fno-stack-protector -fno-strict-aliasing \ 135 | -m64 -mno-red-zone -w -o /dev/null $tmp/empty.c 136 | check 'ignored options' 137 | 138 | # [238] 跳过UTF-8 BOM标记 139 | printf '\xef\xbb\xbfxyz\n' | $rvcc -E -o- -xc - | grep -q '^xyz' 140 | check 'BOM marker' 141 | 142 | # Inline functions 143 | # [260] 将inline函数作为static函数 144 | echo 'inline void foo() {}' > $tmp/inline1.c 145 | echo 'inline void foo() {}' > $tmp/inline2.c 146 | echo 'int main() { return 0; }' > $tmp/inline3.c 147 | $rvcc -o /dev/null $tmp/inline1.c $tmp/inline2.c $tmp/inline3.c 148 | check inline 149 | 150 | echo 'extern inline void foo() {}' > $tmp/inline1.c 151 | echo 'int foo(); int main() { foo(); }' > $tmp/inline2.c 152 | $rvcc -o /dev/null $tmp/inline1.c $tmp/inline2.c 153 | check inline 154 | 155 | # [261] 如果没被引用不生成静态内联函数 156 | echo 'static inline void f1() {}' | $rvcc -o- -S -xc - | grep -v -q f1: 157 | check inline 158 | 159 | echo 'static inline void f1() {} void foo() { f1(); }' | $rvcc -o- -S -xc - | grep -q f1: 160 | check inline 161 | 162 | echo 'static inline void f1() {} static inline void f2() { f1(); } void foo() { f1(); }' | $rvcc -o- -S -xc - | grep -q f1: 163 | check inline 164 | 165 | echo 'static inline void f1() {} static inline void f2() { f1(); } void foo() { f1(); }' | $rvcc -o- -S -xc - | grep -v -q f2: 166 | check inline 167 | 168 | echo 'static inline void f1() {} static inline void f2() { f1(); } void foo() { f2(); }' | $rvcc -o- -S -xc - | grep -q f1: 169 | check inline 170 | 171 | echo 'static inline void f1() {} static inline void f2() { f1(); } void foo() { f2(); }' | $rvcc -o- -S -xc - | grep -q f2: 172 | check inline 173 | 174 | echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() {}' | $rvcc -o- -S -xc - | grep -v -q f1: 175 | check inline 176 | 177 | echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() {}' | $rvcc -o- -S -xc - | grep -v -q f2: 178 | check inline 179 | 180 | echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() { f1(); }' | $rvcc -o- -S -xc - | grep -q f1: 181 | check inline 182 | 183 | echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() { f1(); }' | $rvcc -o- -S -xc - | grep -q f2: 184 | check inline 185 | 186 | echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() { f2(); }' | $rvcc -o- -S -xc - | grep -q f1: 187 | check inline 188 | 189 | echo 'static inline void f2(); static inline void f1() { f2(); } static inline void f2() { f1(); } void foo() { f2(); }' | $rvcc -o- -S -xc - | grep -q f2: 190 | check inline 191 | 192 | # -idirafter 193 | # [263] 支持-idirafter选项 194 | mkdir -p $tmp/dir1 $tmp/dir2 195 | echo foo > $tmp/dir1/idirafter 196 | echo bar > $tmp/dir2/idirafter 197 | echo "#include \"idirafter\"" | $rvcc -I$tmp/dir1 -I$tmp/dir2 -E -xc - | grep -q foo 198 | check -idirafter 199 | echo "#include \"idirafter\"" | $rvcc -idirafter $tmp/dir1 -I$tmp/dir2 -E -xc - | grep -q bar 200 | check -idirafter 201 | 202 | # [266] 支持-fcommon和-fno-common选项 203 | # -fcommon 204 | echo 'int foo;' | $rvcc -S -o- -xc - | grep -q '\.comm foo' 205 | check '-fcommon (default)' 206 | 207 | echo 'int foo;' | $rvcc -fcommon -S -o- -xc - | grep -q '\.comm foo' 208 | check '-fcommon' 209 | 210 | # -fno-common 211 | echo 'int foo;' | $rvcc -fno-common -S -o- -xc - | grep -q '^foo:' 212 | check '-fno-common' 213 | 214 | # [268] 支持-include选项 215 | # -include 216 | echo foo > $tmp/out.h 217 | echo bar | $rvcc -I$RISCV/sysroot/usr/include/ -include $tmp/out.h -E -o- -xc - | grep -q -z 'foo.*bar' 218 | check -include 219 | echo NULL | $rvcc -I$RISCV/sysroot/usr/include/ -Iinclude -include stdio.h -E -o- -xc - | grep -q 0 220 | check -include 221 | 222 | # [269] 支持-x选项 223 | # -x 224 | echo 'int x;' | $rvcc -c -xc -o $tmp/foo.o - 225 | check -xc 226 | echo 'x:' | $rvcc -c -x assembler -o $tmp/foo.o - 227 | check '-x assembler' 228 | 229 | echo 'int x;' > $tmp/foo.c 230 | $rvcc -c -x assembler -x none -o $tmp/foo.o $tmp/foo.c 231 | check '-x none' 232 | 233 | # [270] 使-E包含-xc 234 | echo foo | $rvcc -E - | grep -q foo 235 | check -E 236 | 237 | # [279] 识别.a和.so文件 238 | # .a file 239 | echo 'void foo() {}' | $rvcc -c -xc -o $tmp/foo.o - 240 | echo 'void bar() {}' | $rvcc -c -xc -o $tmp/bar.o - 241 | if [ "$RISCV" = "" ];then 242 | ar rcs $tmp/foo.a $tmp/foo.o $tmp/bar.o 243 | else 244 | $RISCV/bin/riscv64-unknown-linux-gnu-ar rcs $tmp/foo.a $tmp/foo.o $tmp/bar.o 245 | fi 246 | echo 'void foo(); void bar(); int main() { foo(); bar(); }' > $tmp/main.c 247 | $rvcc -o $tmp/foo $tmp/main.c $tmp/foo.a 248 | check '.a' 249 | 250 | # .so file 251 | if [ "$RISCV" = "" ];then 252 | echo 'void foo() {}' | cc -fPIC -c -xc -o $tmp/foo.o - 253 | echo 'void bar() {}' | cc -fPIC -c -xc -o $tmp/bar.o - 254 | cc -shared -o $tmp/foo.so $tmp/foo.o $tmp/bar.o 255 | else 256 | echo 'void foo() {}' | $RISCV/bin/riscv64-unknown-linux-gnu-gcc -fPIC -c -xc -o $tmp/foo.o - 257 | echo 'void bar() {}' | $RISCV/bin/riscv64-unknown-linux-gnu-gcc -fPIC -c -xc -o $tmp/bar.o - 258 | $RISCV/bin/riscv64-unknown-linux-gnu-gcc -shared -o $tmp/foo.so $tmp/foo.o $tmp/bar.o 259 | fi 260 | echo 'void foo(); void bar(); int main() { foo(); bar(); }' > $tmp/main.c 261 | $rvcc -o $tmp/foo $tmp/main.c $tmp/foo.so 262 | check '.so' 263 | 264 | # [285] 支持字符串哈希表 265 | $rvcc -hashmap-test 266 | check 'hashmap' 267 | 268 | # [289] 支持-M选项 269 | # -M 270 | echo '#include "out2.h"' > $tmp/out.c 271 | echo '#include "out3.h"' >> $tmp/out.c 272 | touch $tmp/out2.h $tmp/out3.h 273 | $rvcc -M -I$tmp $tmp/out.c | grep -q -z '^out.o: .*/out\.c .*/out2\.h .*/out3\.h' 274 | check -M 275 | 276 | # [290] 支持-MF选项 277 | # -MF 278 | $rvcc -MF $tmp/mf -M -I$tmp $tmp/out.c 279 | grep -q -z '^out.o: .*/out\.c .*/out2\.h .*/out3\.h' $tmp/mf 280 | check -MF 281 | 282 | # [291] 支持-MP选项 283 | # -MP 284 | $rvcc -MF $tmp/mp -MP -M -I$tmp $tmp/out.c 285 | grep -q '^.*/out2.h:' $tmp/mp 286 | check -MP 287 | grep -q '^.*/out3.h:' $tmp/mp 288 | check -MP 289 | 290 | # [292] 支持-MT选项 291 | # -MT 292 | $rvcc -MT foo -M -I$tmp $tmp/out.c | grep -q '^foo:' 293 | check -MT 294 | $rvcc -MT foo -MT bar -M -I$tmp $tmp/out.c | grep -q '^foo bar:' 295 | check -MT 296 | 297 | # [293] 支持-MD选项 298 | # -MD 299 | echo '#include "out2.h"' > $tmp/md2.c 300 | echo '#include "out3.h"' > $tmp/md3.c 301 | (cd $tmp; $OLDPWD/$rvcc -c -MD -I. md2.c md3.c) 302 | grep -q -z '^md2.o:.* md2\.c .* ./out2\.h' $tmp/md2.d 303 | check -MD 304 | grep -q -z '^md3.o:.* md3\.c .* ./out3\.h' $tmp/md3.d 305 | check -MD 306 | 307 | $rvcc -c -MD -MF $tmp/md-mf.d -I. $tmp/md2.c 308 | grep -q -z '^md2.o:.*md2\.c .*/out2\.h' $tmp/md-mf.d 309 | check -MD 310 | 311 | # [294] 支持-MQ选项 312 | # -MQ 313 | $rvcc -MQ '$foo' -M -I$tmp $tmp/out.c | grep -q '^$$foo:' 314 | check -MQ 315 | $rvcc -MQ '$foo' -MQ bar -M -I$tmp $tmp/out.c | grep -q '^$$foo bar:' 316 | check -MQ 317 | 318 | # [296] 支持-fpic和-fPIC选项 319 | echo 'extern int bar; int foo() { return bar; }' | $rvcc -fPIC -xc -c -o $tmp/foo.o - 320 | if [ "$RISCV" = "" ];then 321 | cc -shared -o $tmp/foo.so $tmp/foo.o 322 | else 323 | $RISCV/bin/riscv64-unknown-linux-gnu-gcc -shared -o $tmp/foo.so $tmp/foo.o 324 | fi 325 | 326 | echo 'int foo(); int bar=3; int main() { foo(); }' > $tmp/main.c 327 | $rvcc -o $tmp/foo $tmp/main.c $tmp/foo.so 328 | check -fPIC 329 | 330 | # [300] [GNU] 支持#include_next 331 | # #include_next 332 | mkdir -p $tmp/next1 $tmp/next2 $tmp/next3 333 | echo '#include "file1.h"' > $tmp/file.c 334 | echo '#include_next "file1.h"' > $tmp/next1/file1.h 335 | echo '#include_next "file2.h"' > $tmp/next2/file1.h 336 | echo 'foo' > $tmp/next3/file2.h 337 | $rvcc -I$tmp/next1 -I$tmp/next2 -I$tmp/next3 -E $tmp/file.c | grep -q foo 338 | check '#include_next' 339 | 340 | # [301] 支持-static选项 341 | # -static 342 | echo 'extern int bar; int foo() { return bar; }' > $tmp/foo.c 343 | echo 'int foo(); int bar=3; int main() { foo(); }' > $tmp/bar.c 344 | $rvcc -static -o $tmp/foo $tmp/foo.c $tmp/bar.c 345 | check -static 346 | file $tmp/foo | grep -q 'statically linked' 347 | check -static 348 | 349 | # [302] 支持-shared选项 350 | # -shared 351 | echo 'extern int bar; int foo() { return bar; }' > $tmp/foo.c 352 | echo 'int foo(); int bar=3; int main() { foo(); }' > $tmp/bar.c 353 | $rvcc -fPIC -shared -o $tmp/foo.so $tmp/foo.c $tmp/bar.c 354 | check -shared 355 | 356 | # [303] 支持-L选项 357 | # -L 358 | echo 'extern int bar; int foo() { return bar; }' > $tmp/foo.c 359 | $rvcc -fPIC -shared -o $tmp/libfoobar.so $tmp/foo.c 360 | echo 'int foo(); int bar=3; int main() { foo(); }' > $tmp/bar.c 361 | $rvcc -o $tmp/foo $tmp/bar.c -L$tmp -lfoobar 362 | check -L 363 | 364 | # [304] 支持-Wl,选项 365 | # -Wl, 366 | echo 'int foo() {}' | $rvcc -c -o $tmp/foo.o -xc - 367 | echo 'int foo() {}' | $rvcc -c -o $tmp/bar.o -xc - 368 | echo 'int main() {}' | $rvcc -c -o $tmp/baz.o -xc - 369 | if [ "$RISCV" = "" ];then 370 | cc -Wl,-z,muldefs,--gc-sections -o $tmp/foo $tmp/foo.o $tmp/bar.o $tmp/baz.o 371 | else 372 | $RISCV/bin/riscv64-unknown-linux-gnu-gcc -Wl,-z,muldefs,--gc-sections -o $tmp/foo $tmp/foo.o $tmp/bar.o $tmp/baz.o 373 | fi 374 | check -Wl 375 | 376 | # [305] 支持-Xlinker选项 377 | # -Xlinker 378 | echo 'int foo() {}' | $rvcc -c -o $tmp/foo.o -xc - 379 | echo 'int foo() {}' | $rvcc -c -o $tmp/bar.o -xc - 380 | echo 'int main() {}' | $rvcc -c -o $tmp/baz.o -xc - 381 | if [ "$RISCV" = "" ];then 382 | cc -Xlinker -z -Xlinker muldefs -Xlinker --gc-sections -o $tmp/foo $tmp/foo.o $tmp/bar.o $tmp/baz.o 383 | else 384 | $RISCV/bin/riscv64-unknown-linux-gnu-gcc -Xlinker -z -Xlinker muldefs -Xlinker --gc-sections -o $tmp/foo $tmp/foo.o $tmp/bar.o $tmp/baz.o 385 | fi 386 | check -Xlinker 387 | 388 | echo OK 389 | -------------------------------------------------------------------------------- /test/enum.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int main() { 4 | // [74] 支持enum 5 | ASSERT(0, ({ enum { zero, one, two }; zero; })); 6 | ASSERT(1, ({ enum { zero, one, two }; one; })); 7 | ASSERT(2, ({ enum { zero, one, two }; two; })); 8 | ASSERT(5, ({ enum { five=5, six, seven }; five; })); 9 | ASSERT(6, ({ enum { five=5, six, seven }; six; })); 10 | ASSERT(0, ({ enum { zero, five=5, three=3, four }; zero; })); 11 | ASSERT(5, ({ enum { zero, five=5, three=3, four }; five; })); 12 | ASSERT(3, ({ enum { zero, five=5, three=3, four }; three; })); 13 | ASSERT(4, ({ enum { zero, five=5, three=3, four }; four; })); 14 | ASSERT(4, ({ enum { zero, one, two } x; sizeof(x); })); 15 | ASSERT(4, ({ enum t { zero, one, two }; enum t y; sizeof(y); })); 16 | 17 | printf("OK\n"); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /test/extern.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | // [116] 支持extern 4 | extern int ext1; 5 | extern int *ext2; 6 | 7 | // [260] 将inline函数作为static函数 8 | inline int inline_fn(void) { 9 | return 3; 10 | } 11 | 12 | int main() { 13 | // [116] 支持extern 14 | ASSERT(5, ext1); 15 | ASSERT(5, *ext2); 16 | 17 | // [117] 处理块中的extern声明 18 | extern int ext3; 19 | ASSERT(7, ext3); 20 | 21 | int ext_fn1(int x); 22 | ASSERT(5, ext_fn1(5)); 23 | 24 | extern int ext_fn2(int x); 25 | ASSERT(8, ext_fn2(8)); 26 | 27 | printf("OK\n"); 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /test/float.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int main() { 4 | // [140] 支持float和double用于局部变量或类型转换 5 | ASSERT(35, (float)(char)35); 6 | ASSERT(35, (float)(short)35); 7 | ASSERT(35, (float)(int)35); 8 | ASSERT(35, (float)(long)35); 9 | ASSERT(35, (float)(unsigned char)35); 10 | ASSERT(35, (float)(unsigned short)35); 11 | ASSERT(35, (float)(unsigned int)35); 12 | ASSERT(35, (float)(unsigned long)35); 13 | 14 | ASSERT(35, (double)(char)35); 15 | ASSERT(35, (double)(short)35); 16 | ASSERT(35, (double)(int)35); 17 | ASSERT(35, (double)(long)35); 18 | ASSERT(35, (double)(unsigned char)35); 19 | ASSERT(35, (double)(unsigned short)35); 20 | ASSERT(35, (double)(unsigned int)35); 21 | ASSERT(35, (double)(unsigned long)35); 22 | 23 | ASSERT(35, (char)(float)35); 24 | ASSERT(35, (short)(float)35); 25 | ASSERT(35, (int)(float)35); 26 | ASSERT(35, (long)(float)35); 27 | ASSERT(35, (unsigned char)(float)35); 28 | ASSERT(35, (unsigned short)(float)35); 29 | ASSERT(35, (unsigned int)(float)35); 30 | ASSERT(35, (unsigned long)(float)35); 31 | 32 | ASSERT(35, (char)(double)35); 33 | ASSERT(35, (short)(double)35); 34 | ASSERT(35, (int)(double)35); 35 | ASSERT(35, (long)(double)35); 36 | ASSERT(35, (unsigned char)(double)35); 37 | ASSERT(35, (unsigned short)(double)35); 38 | ASSERT(35, (unsigned int)(double)35); 39 | ASSERT(35, (unsigned long)(double)35); 40 | 41 | ASSERT(2147483647, (double)(unsigned long)(long)-1); 42 | 43 | // [141] 支持浮点数的 == != <和<= 44 | ASSERT(1, 2e3==2e3); 45 | ASSERT(0, 2e3==2e5); 46 | ASSERT(1, 2.0==2); 47 | ASSERT(0, 5.1<5); 48 | ASSERT(0, 5.0<5); 49 | ASSERT(1, 4.9<5); 50 | ASSERT(0, 5.1<=5); 51 | ASSERT(1, 5.0<=5); 52 | ASSERT(1, 4.9<=5); 53 | 54 | ASSERT(1, 2e3f==2e3); 55 | ASSERT(0, 2e3f==2e5); 56 | ASSERT(1, 2.0f==2); 57 | ASSERT(0, 5.1f<5); 58 | ASSERT(0, 5.0f<5); 59 | ASSERT(1, 4.9f<5); 60 | ASSERT(0, 5.1f<=5); 61 | ASSERT(1, 5.0f<=5); 62 | ASSERT(1, 4.9f<=5); 63 | 64 | // [142] 支持浮点数的 + - *和/ 65 | ASSERT(6, 2.3+3.8); 66 | ASSERT(-1, 2.3-3.8); 67 | ASSERT(-3, -3.8); 68 | ASSERT(13, 3.3*4); 69 | ASSERT(2, 5.0/2); 70 | 71 | ASSERT(6, 2.3f+3.8f); 72 | ASSERT(6, 2.3f+3.8); 73 | ASSERT(-1, 2.3f-3.8); 74 | ASSERT(-3, -3.8f); 75 | ASSERT(13, 3.3f*4); 76 | ASSERT(2, 5.0f/2); 77 | 78 | ASSERT(0, 0.0/0.0 == 0.0/0.0); 79 | ASSERT(1, 0.0/0.0 != 0.0/0.0); 80 | 81 | ASSERT(0, 0.0/0.0 < 0); 82 | ASSERT(0, 0.0/0.0 <= 0); 83 | ASSERT(0, 0.0/0.0 > 0); 84 | ASSERT(0, 0.0/0.0 >= 0); 85 | 86 | // [143] 支持浮点数的 if while do ! ?: || 和 && 87 | ASSERT(0, !3.); 88 | ASSERT(1, !0.); 89 | ASSERT(0, !3.f); 90 | ASSERT(1, !0.f); 91 | 92 | ASSERT(5, 0.0 ? 3 : 5); 93 | ASSERT(3, 1.2 ? 3 : 5); 94 | 95 | printf("OK\n"); 96 | return 0; 97 | } 98 | -------------------------------------------------------------------------------- /test/generic.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int main() { 4 | printf("[256] 支持_Generic\n"); 5 | ASSERT(1, _Generic(100.0, double: 1, int *: 2, int: 3, float: 4)); 6 | ASSERT(2, _Generic((int *)0, double: 1, int *: 2, int: 3, float: 4)); 7 | ASSERT(2, _Generic((int[3]){}, double: 1, int *: 2, int: 3, float: 4)); 8 | ASSERT(3, _Generic(100, double: 1, int *: 2, int: 3, float: 4)); 9 | ASSERT(4, _Generic(100f, double: 1, int *: 2, int: 3, float: 4)); 10 | ASSERT(5, _Generic(100f, double : 1, int * : 2, int : 3, default : 5)); 11 | 12 | printf("OK\n"); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /test/include1.h: -------------------------------------------------------------------------------- 1 | #include "include2.h" 2 | 3 | // [189] 支持 __FILE__ 和 __LINE__ 4 | char *include1_filename = __FILE__; 5 | int include1_line = __LINE__; 6 | 7 | // [160] 支持 #include "..." 8 | int include1 = 5; 9 | -------------------------------------------------------------------------------- /test/include2.h: -------------------------------------------------------------------------------- 1 | // [160] 支持 #include "..." 2 | int include2 = 7; 3 | -------------------------------------------------------------------------------- /test/include3.h: -------------------------------------------------------------------------------- 1 | // [184] 支持 #include <...> 2 | #define foo 3 3 | -------------------------------------------------------------------------------- /test/include4.h: -------------------------------------------------------------------------------- 1 | // [184] 支持 #include <...> 2 | #define foo 4 3 | -------------------------------------------------------------------------------- /test/initializer.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | // [105] 支持全局变量初始化器 4 | char g3 = 3; 5 | short g4 = 4; 6 | int g5 = 5; 7 | long g6 = 6; 8 | 9 | // [106] 为结构体支持全局变量初始化器 10 | int g9[3] = {0, 1, 2}; 11 | struct {char a; int b;} g11[2] = {{1, 2}, {3, 4}}; 12 | struct {int a[2];} g12[2] = {{{1, 2}}}; 13 | 14 | // [107] 为全局变量处理联合体初始化 15 | union { int a; char b[8]; } g13[2] = {{0x01020304}, {0x05060708}}; 16 | char g17[] = "foobar"; 17 | char g18[10] = "foobar"; 18 | char g19[3] = "foobar"; 19 | char *g20 = g17+0; 20 | char *g21 = g17+3; 21 | char *g22 = &g17-3; 22 | char *g23[] = {g17+0, g17+3, g17-3}; 23 | int g24=3; 24 | int *g25=&g24; 25 | int g26[3] = {1, 2, 3}; 26 | int *g27 = g26 + 1; 27 | int *g28 = &g11[1].a; 28 | long g29 = (long)(long)g26; 29 | struct { struct { int a[3]; } a; } g30 = {{{1,2,3}}}; 30 | int *g31=g30.a.a; 31 | 32 | // [108] 允许省略初始化器内的括号 33 | union { int a; char b[8]; } g13_2[2] = {0x01020304, 0x05060708}; 34 | struct {int a[2];} g40[2] = {{1, 2}, 3, 4}; 35 | struct {int a[2];} g41[2] = {1, 2, 3, 4}; 36 | char g43[][4] = {'f', 'o', 'o', 0, 'b', 'a', 'r', 0}; 37 | 38 | // [109] 允许标量初始化时有多余的大括号 39 | char *g44 = {"foo"}; 40 | // [243] 支持联合体指派初始化器 41 | union { int a; char b[4]; } g50 = {.b[2]=0x12}; 42 | union { int a; } g51[2] = {}; 43 | 44 | // [113] 支持初始化结构体灵活数组成员 45 | typedef char T60[]; 46 | T60 g60 = {1, 2, 3}; 47 | T60 g61 = {1, 2, 3, 4, 5, 6}; 48 | 49 | typedef struct {char a, b[];} T65; 50 | T65 g65 = {'f', 'o', 'o', 0}; 51 | T65 g66 = {'f', 'o', 'o', 'b', 'a', 'r', 0}; 52 | 53 | int main() { 54 | // [97] 支持局部变量初始化器 55 | ASSERT(1, ({ int x[3]={1,2,3}; x[0]; })); 56 | ASSERT(2, ({ int x[3]={1,2,3}; x[1]; })); 57 | ASSERT(3, ({ int x[3]={1,2,3}; x[2]; })); 58 | 59 | ASSERT(2, ({ int x[2][3]={{1,2,3},{4,5,6}}; x[0][1]; })); 60 | ASSERT(4, ({ int x[2][3]={{1,2,3},{4,5,6}}; x[1][0]; })); 61 | ASSERT(6, ({ int x[2][3]={{1,2,3},{4,5,6}}; x[1][2]; })); 62 | 63 | // [98] 为多余的数组元素赋0 64 | ASSERT(0, ({ int x[3]={}; x[0]; })); 65 | ASSERT(0, ({ int x[3]={}; x[1]; })); 66 | ASSERT(0, ({ int x[3]={}; x[2]; })); 67 | 68 | ASSERT(2, ({ int x[2][3]={{1,2}}; x[0][1]; })); 69 | ASSERT(0, ({ int x[2][3]={{1,2}}; x[1][0]; })); 70 | ASSERT(0, ({ int x[2][3]={{1,2}}; x[1][2]; })); 71 | 72 | // [99] 跳过多余的初始化元素 73 | ASSERT(4, ({ int x[2][3]={{1,2,3,4},{4,5,6}}; x[1][0]; })); 74 | 75 | // [100] 支持字符串字面量的初始化 76 | ASSERT('a', ({ char x[4]="abc"; x[0]; })); 77 | ASSERT('c', ({ char x[4]="abc"; x[2]; })); 78 | ASSERT(0, ({ char x[4]="abc"; x[3]; })); 79 | ASSERT('a', ({ char x[2][4]={"abc","def"}; x[0][0]; })); 80 | ASSERT(0, ({ char x[2][4]={"abc","def"}; x[0][3]; })); 81 | ASSERT('d', ({ char x[2][4]={"abc","def"}; x[1][0]; })); 82 | ASSERT('f', ({ char x[2][4]={"abc","def"}; x[1][2]; })); 83 | 84 | // [101] 支持存在初始化器时省略数组长度 85 | ASSERT(4, ({ int x[]={1,2,3,4}; x[3]; })); 86 | ASSERT(16, ({ int x[]={1,2,3,4}; sizeof(x); })); 87 | ASSERT(4, ({ char x[]="foo"; sizeof(x); })); 88 | 89 | ASSERT(4, ({ typedef char T[]; T x="foo"; T y="x"; sizeof(x); })); 90 | ASSERT(2, ({ typedef char T[]; T x="foo"; T y="x"; sizeof(y); })); 91 | ASSERT(2, ({ typedef char T[]; T x="x"; T y="foo"; sizeof(x); })); 92 | ASSERT(4, ({ typedef char T[]; T x="x"; T y="foo"; sizeof(y); })); 93 | 94 | // [102] 为局部变量处理结构体初始化 95 | ASSERT(1, ({ struct {int a; int b; int c;} x={1,2,3}; x.a; })); 96 | ASSERT(2, ({ struct {int a; int b; int c;} x={1,2,3}; x.b; })); 97 | ASSERT(3, ({ struct {int a; int b; int c;} x={1,2,3}; x.c; })); 98 | ASSERT(1, ({ struct {int a; int b; int c;} x={1}; x.a; })); 99 | ASSERT(0, ({ struct {int a; int b; int c;} x={1}; x.b; })); 100 | ASSERT(0, ({ struct {int a; int b; int c;} x={1}; x.c; })); 101 | 102 | ASSERT(1, ({ struct {int a; int b;} x[2]={{1,2},{3,4}}; x[0].a; })); 103 | ASSERT(2, ({ struct {int a; int b;} x[2]={{1,2},{3,4}}; x[0].b; })); 104 | ASSERT(3, ({ struct {int a; int b;} x[2]={{1,2},{3,4}}; x[1].a; })); 105 | ASSERT(4, ({ struct {int a; int b;} x[2]={{1,2},{3,4}}; x[1].b; })); 106 | 107 | ASSERT(0, ({ struct {int a; int b;} x[2]={{1,2}}; x[1].b; })); 108 | 109 | ASSERT(0, ({ struct {int a; int b;} x={}; x.a; })); 110 | ASSERT(0, ({ struct {int a; int b;} x={}; x.b; })); 111 | 112 | ASSERT(5, ({ typedef struct {int a,b,c,d,e,f;} T; T x={1,2,3,4,5,6}; T y; y=x; y.e; })); 113 | ASSERT(2, ({ typedef struct {int a,b;} T; T x={1,2}; T y, z; z=y=x; z.b; })); 114 | 115 | // [103] 初始化结构体时可使用其他结构体 116 | ASSERT(1, ({ typedef struct {int a,b;} T; T x={1,2}; T y=x; y.a; })); 117 | 118 | // [104] 为局部变量处理联合体初始化 119 | ASSERT(4, ({ union { int a; char b[4]; } x={0x01020304}; x.b[0]; })); 120 | ASSERT(3, ({ union { int a; char b[4]; } x={0x01020304}; x.b[1]; })); 121 | 122 | ASSERT(0x01020304, ({ union { struct { char a,b,c,d; } e; int f; } x={{4,3,2,1}}; x.f; })); 123 | 124 | // [105] 支持全局变量初始化器 125 | ASSERT(3, g3); 126 | ASSERT(4, g4); 127 | ASSERT(5, g5); 128 | ASSERT(6, g6); 129 | 130 | // [106] 为结构体支持全局变量初始化器 131 | ASSERT(0, g9[0]); 132 | ASSERT(1, g9[1]); 133 | ASSERT(2, g9[2]); 134 | 135 | ASSERT(1, g11[0].a); 136 | ASSERT(2, g11[0].b); 137 | ASSERT(3, g11[1].a); 138 | ASSERT(4, g11[1].b); 139 | 140 | ASSERT(1, g12[0].a[0]); 141 | ASSERT(2, g12[0].a[1]); 142 | ASSERT(0, g12[1].a[0]); 143 | ASSERT(0, g12[1].a[1]); 144 | 145 | // [107] 为全局变量处理联合体初始化 146 | ASSERT(4, g13[0].b[0]); 147 | ASSERT(3, g13[0].b[1]); 148 | ASSERT(8, g13[1].b[0]); 149 | ASSERT(7, g13[1].b[1]); 150 | 151 | ASSERT(7, sizeof(g17)); 152 | ASSERT(10, sizeof(g18)); 153 | ASSERT(3, sizeof(g19)); 154 | 155 | ASSERT(0, memcmp(g17, "foobar", 7)); 156 | ASSERT(0, memcmp(g18, "foobar\0\0\0", 10)); 157 | ASSERT(0, memcmp(g19, "foo", 3)); 158 | 159 | ASSERT(0, strcmp(g20, "foobar")); 160 | ASSERT(0, strcmp(g21, "bar")); 161 | ASSERT(0, strcmp(g22 + 3, "foobar")); 162 | 163 | ASSERT(0, strcmp(g23[0], "foobar")); 164 | ASSERT(0, strcmp(g23[1], "bar")); 165 | ASSERT(0, strcmp(g23[2] + 3, "foobar")); 166 | 167 | ASSERT(3, g24); 168 | ASSERT(3, *g25); 169 | ASSERT(2, *g27); 170 | ASSERT(3, *g28); 171 | ASSERT(1, *(int *)g29); 172 | 173 | ASSERT(1, g31[0]); 174 | ASSERT(2, g31[1]); 175 | ASSERT(3, g31[2]); 176 | 177 | // [108] 允许省略初始化器内的括号 178 | ASSERT(4, g13_2[0].b[0]); 179 | ASSERT(3, g13_2[0].b[1]); 180 | ASSERT(8, g13_2[1].b[0]); 181 | ASSERT(7, g13_2[1].b[1]); 182 | 183 | ASSERT(1, g40[0].a[0]); 184 | ASSERT(2, g40[0].a[1]); 185 | ASSERT(3, g40[1].a[0]); 186 | ASSERT(4, g40[1].a[1]); 187 | 188 | ASSERT(1, g41[0].a[0]); 189 | ASSERT(2, g41[0].a[1]); 190 | ASSERT(3, g41[1].a[0]); 191 | ASSERT(4, g41[1].a[1]); 192 | 193 | ASSERT(0, ({ int x[2][3]={0,1,2,3,4,5}; x[0][0]; })); 194 | ASSERT(3, ({ int x[2][3]={0,1,2,3,4,5}; x[1][0]; })); 195 | 196 | ASSERT(0, ({ struct {int a; int b;} x[2]={0,1,2,3}; x[0].a; })); 197 | ASSERT(2, ({ struct {int a; int b;} x[2]={0,1,2,3}; x[1].a; })); 198 | 199 | ASSERT(0, strcmp(g43[0], "foo")); 200 | ASSERT(0, strcmp(g43[1], "bar")); 201 | 202 | // [109] 允许标量初始化时有多余的大括号 203 | ASSERT(0, strcmp(g44, "foo")); 204 | 205 | // [110] 允许枚举类型或初始化器有无关的逗号 206 | ASSERT(3, ({ int a[]={1,2,3,}; a[2]; })); 207 | ASSERT(1, ({ struct {int a,b,c;} x={1,2,3,}; x.a; })); 208 | ASSERT(1, ({ union {int a; char b;} x={1,}; x.a; })); 209 | ASSERT(2, ({ enum {x,y,z,}; z; })); 210 | 211 | // [113] 支持初始化结构体灵活数组成员 212 | ASSERT(3, sizeof(g60)); 213 | ASSERT(6, sizeof(g61)); 214 | 215 | ASSERT(4, sizeof(g65)); 216 | ASSERT(7, sizeof(g66)); 217 | ASSERT('f', g65.a); 218 | ASSERT(0, strcmp(g65.b, "oo")); 219 | ASSERT(0, strcmp(g66.b, "oobar")); 220 | 221 | printf("[239] 支持数组指派初始化器\n"); 222 | ASSERT(4, ({ int x[3]={1, 2, 3, [0]=4, 5}; x[0]; })); 223 | ASSERT(5, ({ int x[3]={1, 2, 3, [0]=4, 5}; x[1]; })); 224 | ASSERT(3, ({ int x[3]={1, 2, 3, [0]=4, 5}; x[2]; })); 225 | 226 | ASSERT(10, ({ int x[2][3]={1,2,3,4,5,6,[0][1]=7,8,[0]=9,[0]=10,11,[1][0]=12}; x[0][0]; })); 227 | ASSERT(11, ({ int x[2][3]={1,2,3,4,5,6,[0][1]=7,8,[0]=9,[0]=10,11,[1][0]=12}; x[0][1]; })); 228 | ASSERT(8, ({ int x[2][3]={1,2,3,4,5,6,[0][1]=7,8,[0]=9,[0]=10,11,[1][0]=12}; x[0][2]; })); 229 | ASSERT(12, ({ int x[2][3]={1,2,3,4,5,6,[0][1]=7,8,[0]=9,[0]=10,11,[1][0]=12}; x[1][0]; })); 230 | ASSERT(5, ({ int x[2][3]={1,2,3,4,5,6,[0][1]=7,8,[0]=9,[0]=10,11,[1][0]=12}; x[1][1]; })); 231 | ASSERT(6, ({ int x[2][3]={1,2,3,4,5,6,[0][1]=7,8,[0]=9,[0]=10,11,[1][0]=12}; x[1][2]; })); 232 | 233 | ASSERT(7, ({ int x[2][3]={1,2,3,4,5,6,[0]={7,8},9,10}; x[0][0]; })); 234 | ASSERT(8, ({ int x[2][3]={1,2,3,4,5,6,[0]={7,8},9,10}; x[0][1]; })); 235 | ASSERT(3, ({ int x[2][3]={1,2,3,4,5,6,[0]={7,8},9,10}; x[0][2]; })); 236 | ASSERT(9, ({ int x[2][3]={1,2,3,4,5,6,[0]={7,8},9,10}; x[1][0]; })); 237 | ASSERT(10, ({ int x[2][3]={1,2,3,4,5,6,[0]={7,8},9,10}; x[1][1]; })); 238 | ASSERT(6, ({ int x[2][3]={1,2,3,4,5,6,[0]={7,8},9,10}; x[1][2]; })); 239 | 240 | ASSERT(7, ((int[10]){ [3]=7 })[3]); 241 | ASSERT(0, ((int[10]){ [3]=7 })[4]); 242 | 243 | printf("[240] 支持指派初始化不完整数组类型\n"); 244 | ASSERT(10, ({ char x[]={[10-3]=1,2,3}; sizeof(x); })); 245 | ASSERT(20, ({ char x[][2]={[8][1]=1,2}; sizeof(x); })); 246 | 247 | ASSERT(3, sizeof(g60)); 248 | ASSERT(6, sizeof(g61)); 249 | 250 | ASSERT(4, sizeof(g65)); 251 | ASSERT(7, sizeof(g66)); 252 | ASSERT(0, strcmp(g65.b, "oo")); 253 | ASSERT(0, strcmp(g66.b, "oobar")); 254 | 255 | printf("[241] [GNU] 指派初始化器允许省略=\n"); 256 | ASSERT(7, ((int[10]){ [3] 7 })[3]); 257 | ASSERT(0, ((int[10]){ [3] 7 })[4]); 258 | 259 | printf("[242] 支持结构体指派初始化器\n"); 260 | ASSERT(4, ({ struct { int a,b; } x={1,2,.b=3,.a=4}; x.a; })); 261 | ASSERT(3, ({ struct { int a,b; } x={1,2,.b=3,.a=4}; x.b; })); 262 | 263 | ASSERT(1, ({ struct { struct { int a,b; } c; } x={.c=1,2}; x.c.a; })); 264 | ASSERT(2, ({ struct { struct { int a,b; } c; } x={.c=1,2}; x.c.b; })); 265 | 266 | ASSERT(0, ({ struct { struct { int a,b; } c; } x={.c.b=1}; x.c.a; })); 267 | ASSERT(1, ({ struct { struct { int a,b; } c; } x={.c.b=1}; x.c.b; })); 268 | 269 | ASSERT(1, ({ struct { int a[2]; } x={.a=1,2}; x.a[0]; })); 270 | ASSERT(2, ({ struct { int a[2]; } x={.a=1,2}; x.a[1]; })); 271 | 272 | ASSERT(0, ({ struct { int a[2]; } x={.a[1]=1}; x.a[0]; })); 273 | ASSERT(1, ({ struct { int a[2]; } x={.a[1]=1}; x.a[1]; })); 274 | 275 | ASSERT(3, ({ struct { int a,b; } x[]={[1].b=1,2,[0]=3,4,}; x[0].a; })); 276 | ASSERT(4, ({ struct { int a,b; } x[]={[1].b=1,2,[0]=3,4,}; x[0].b; })); 277 | ASSERT(0, ({ struct { int a,b; } x[]={[1].b=1,2,[0]=3,4,}; x[1].a; })); 278 | ASSERT(1, ({ struct { int a,b; } x[]={[1].b=1,2,[0]=3,4,}; x[1].b; })); 279 | ASSERT(2, ({ struct { int a,b; } x[]={[1].b=1,2,[0]=3,4,}; x[2].a; })); 280 | ASSERT(0, ({ struct { int a,b; } x[]={[1].b=1,2,[0]=3,4,}; x[2].b; })); 281 | 282 | ASSERT(1, ({ typedef struct { int a,b; } T; T x={1,2}; T y[]={x}; y[0].a; })); 283 | ASSERT(2, ({ typedef struct { int a,b; } T; T x={1,2}; T y[]={x}; y[0].b; })); 284 | ASSERT(0, ({ typedef struct { int a,b; } T; T x={1,2}; T y[]={x, [0].b=3}; y[0].a; })); 285 | ASSERT(3, ({ typedef struct { int a,b; } T; T x={1,2}; T y[]={x, [0].b=3}; y[0].b; })); 286 | 287 | ASSERT(5, ((struct { int a,b,c; }){ .c=5 }).c); 288 | ASSERT(0, ((struct { int a,b,c; }){ .c=5 }).a); 289 | 290 | printf("[243] 支持联合体指派初始化器\n"); 291 | ASSERT(0x00ff, ({ union { unsigned short a; char b[2]; } x={.b[0]=0xff}; x.a; })); 292 | ASSERT(0xff00, ({ union { unsigned short a; char b[2]; } x={.b[1]=0xff}; x.a; })); 293 | 294 | ASSERT(0x00120000, g50.a); 295 | ASSERT(0, g51[0].a); 296 | ASSERT(0, g51[1].a); 297 | 298 | printf("[244] 为匿名结构体成员处理结构体指派器\n"); 299 | ASSERT(1, ({ struct { struct { int a; struct { int b; }; }; int c; } x={1,2,3,.b=4,5}; x.a; })); 300 | ASSERT(4, ({ struct { struct { int a; struct { int b; }; }; int c; } x={1,2,3,.b=4,5}; x.b; })); 301 | ASSERT(5, ({ struct { struct { int a; struct { int b; }; }; int c; } x={1,2,3,.b=4,5}; x.c; })); 302 | 303 | printf("[282] 支持数组范围指派器\n"); 304 | ASSERT(16, ({ char x[]={[2 ... 10]='a', [7]='b', [15 ... 15]='c', [3 ... 5]='d'}; sizeof(x); })); 305 | ASSERT(0, ({ char x[]={[2 ... 10]='a', [7]='b', [15 ... 15]='c', [3 ... 5]='d'}; memcmp(x, "\0\0adddabaaa\0\0\0\0c", 16); })); 306 | 307 | printf("OK\n"); 308 | return 0; 309 | } 310 | -------------------------------------------------------------------------------- /test/line.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int main() { 4 | 5 | printf("[246] 支持#line\n"); 6 | #line 500 "foo" 7 | ASSERT(501, __LINE__); 8 | ASSERT(0, strcmp(__FILE__, "foo")); 9 | 10 | #line 800 "bar" 11 | ASSERT(801, __LINE__); 12 | ASSERT(0, strcmp(__FILE__, "bar")); 13 | 14 | #line 1 15 | ASSERT(2, __LINE__); 16 | 17 | printf("[247] [GNU] 支持行标记指示\n"); 18 | # 200 "xyz" 2 3 19 | ASSERT(201, __LINE__); 20 | ASSERT(0, strcmp(__FILE__, "xyz")); 21 | 22 | printf("OK\n"); 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /test/literal.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int main() { 4 | // [73] 支持字符字面量 5 | ASSERT(97, 'a'); 6 | ASSERT(10, '\n'); 7 | ASSERT(127, '\x7f'); 8 | 9 | // [80] 支持16,8,2进制的数字字面量 10 | ASSERT(511, 0777); 11 | ASSERT(0, 0x0); 12 | ASSERT(10, 0xa); 13 | ASSERT(10, 0XA); 14 | ASSERT(48879, 0xbeef); 15 | ASSERT(48879, 0xBEEF); 16 | ASSERT(48879, 0XBEEF); 17 | ASSERT(0, 0b0); 18 | ASSERT(1, 0b1); 19 | ASSERT(47, 0b101111); 20 | ASSERT(47, 0B101111); 21 | 22 | // [132] 支持U L LL后缀 23 | ASSERT(4, sizeof(0)); 24 | ASSERT(8, sizeof(0L)); 25 | ASSERT(8, sizeof(0LU)); 26 | ASSERT(8, sizeof(0UL)); 27 | ASSERT(8, sizeof(0LL)); 28 | ASSERT(8, sizeof(0LLU)); 29 | ASSERT(8, sizeof(0Ull)); 30 | ASSERT(8, sizeof(0l)); 31 | ASSERT(8, sizeof(0ll)); 32 | ASSERT(8, sizeof(0x0L)); 33 | ASSERT(8, sizeof(0b0L)); 34 | ASSERT(4, sizeof(2147483647)); 35 | ASSERT(8, sizeof(2147483648)); 36 | ASSERT(-1, 0xffffffffffffffff); 37 | ASSERT(8, sizeof(0xffffffffffffffff)); 38 | ASSERT(4, sizeof(4294967295U)); 39 | ASSERT(8, sizeof(4294967296U)); 40 | 41 | ASSERT(3, -1U>>30); 42 | ASSERT(3, -1Ul>>62); 43 | ASSERT(3, -1ull>>62); 44 | 45 | ASSERT(1, 0xffffffffffffffffl>>63); 46 | ASSERT(1, 0xffffffffffffffffll>>63); 47 | 48 | ASSERT(-1, 18446744073709551615); 49 | ASSERT(8, sizeof(18446744073709551615)); 50 | ASSERT(-1, 18446744073709551615>>63); 51 | 52 | ASSERT(-1, 0xffffffffffffffff); 53 | ASSERT(8, sizeof(0xffffffffffffffff)); 54 | ASSERT(1, 0xffffffffffffffff>>63); 55 | 56 | ASSERT(-1, 01777777777777777777777); 57 | ASSERT(8, sizeof(01777777777777777777777)); 58 | ASSERT(1, 01777777777777777777777>>63); 59 | 60 | ASSERT(-1, 0b1111111111111111111111111111111111111111111111111111111111111111); 61 | ASSERT(8, sizeof(0b1111111111111111111111111111111111111111111111111111111111111111)); 62 | ASSERT(1, 0b1111111111111111111111111111111111111111111111111111111111111111>>63); 63 | 64 | ASSERT(8, sizeof(2147483648)); 65 | ASSERT(4, sizeof(2147483647)); 66 | 67 | ASSERT(8, sizeof(0x1ffffffff)); 68 | ASSERT(4, sizeof(0xffffffff)); 69 | ASSERT(1, 0xffffffff>>31); 70 | 71 | ASSERT(8, sizeof(040000000000)); 72 | ASSERT(4, sizeof(037777777777)); 73 | ASSERT(1, 037777777777>>31); 74 | 75 | ASSERT(8, sizeof(0b111111111111111111111111111111111)); 76 | ASSERT(4, sizeof(0b11111111111111111111111111111111)); 77 | ASSERT(1, 0b11111111111111111111111111111111>>31); 78 | 79 | ASSERT(-1, 1 << 31 >> 31); 80 | ASSERT(-1, 01 << 31 >> 31); 81 | ASSERT(-1, 0x1 << 31 >> 31); 82 | ASSERT(-1, 0b1 << 31 >> 31); 83 | 84 | // [139] 支持浮点常量 85 | 0.0; 86 | 1.0; 87 | 3e+8; 88 | 0x10.1p0; 89 | .1E4f; 90 | 91 | ASSERT(4, sizeof(8f)); 92 | ASSERT(4, sizeof(0.3F)); 93 | ASSERT(8, sizeof(0.)); 94 | ASSERT(8, sizeof(.0)); 95 | // [280] 支持long double 96 | ASSERT(16, sizeof(5.l)); 97 | ASSERT(16, sizeof(2.0L)); 98 | 99 | printf("[183] 支持续行\n"); 100 | assert(1, size\ 101 | of(char), \ 102 | "sizeof(char)"); 103 | 104 | printf("[194] 识别宽字符字面量\n"); 105 | ASSERT(4, sizeof(L'\0')); 106 | ASSERT(97, L'a'); 107 | 108 | printf("OK\n"); 109 | return 0; 110 | } 111 | -------------------------------------------------------------------------------- /test/macro.c: -------------------------------------------------------------------------------- 1 | // [179] 使用内建的预处理器用于所有测试 2 | #include "test.h" 3 | 4 | // [160] 支持 #include "..." 5 | #include "include1.h" 6 | 7 | // [189] 支持 __FILE__ 和 __LINE__ 8 | char *main_filename1 = __FILE__; 9 | int main_line1 = __LINE__; 10 | #define LINE() __LINE__ 11 | int main_line2 = LINE(); 12 | 13 | // [159] 支持空指示 14 | # 15 | 16 | /* */ # 17 | 18 | // [172] 支持 #define 零参宏函数 19 | int ret3(void) { return 3; } 20 | 21 | // [176] 宏函数中只展开一次 22 | int dbl(int x) { return x * x; } 23 | 24 | // [190] 支持 __VA_ARGS__ 25 | int add2(int x, int y) { 26 | return x + y; 27 | } 28 | 29 | int add6(int a, int b, int c, int d, int e, int f) { 30 | return a + b + c + d + e + f; 31 | } 32 | 33 | int main() { 34 | printf("[160] 支持 #include \"...\"\n"); 35 | ASSERT(5, include1); 36 | ASSERT(7, include2); 37 | 38 | printf("[163] 支持 #if 和 #endif\n"); 39 | #if 0 40 | #include "/no/such/file" 41 | ASSERT(0, 1); 42 | 43 | // [164] 在值为假的#if语句中,跳过嵌套的 #if 语句 44 | #if nested 45 | #endif 46 | #endif 47 | 48 | int m = 0; 49 | 50 | #if 1 51 | m = 5; 52 | #endif 53 | ASSERT(5, m); 54 | 55 | printf("[165] 支持 #else"); 56 | #if 1 57 | # if 0 58 | # if 1 59 | foo bar 60 | # endif 61 | # endif 62 | m = 3; 63 | #endif 64 | ASSERT(3, m); 65 | 66 | #if 1-1 67 | # if 1 68 | # endif 69 | # if 1 70 | # else 71 | # endif 72 | # if 0 73 | # else 74 | # endif 75 | m = 2; 76 | #else 77 | # if 1 78 | m = 3; 79 | # endif 80 | #endif 81 | ASSERT(3, m); 82 | 83 | #if 1 84 | m = 2; 85 | #else 86 | m = 3; 87 | #endif 88 | ASSERT(2, m); 89 | 90 | printf("[166] 支持 #elif\n"); 91 | #if 1 92 | m = 2; 93 | #else 94 | m = 3; 95 | #endif 96 | ASSERT(2, m); 97 | 98 | #if 0 99 | m = 1; 100 | #elif 0 101 | m = 2; 102 | #elif 3 + 5 103 | m = 3; 104 | #elif 1 * 5 105 | m = 4; 106 | #endif 107 | ASSERT(3, m); 108 | 109 | #if 1 + 5 110 | m = 1; 111 | #elif 1 112 | m = 2; 113 | #elif 3 114 | m = 2; 115 | #endif 116 | ASSERT(1, m); 117 | 118 | #if 0 119 | m = 1; 120 | #elif 1 121 | #if 1 122 | m = 2; 123 | #else 124 | m = 3; 125 | #endif 126 | #else 127 | m = 5; 128 | #endif 129 | ASSERT(2, m); 130 | 131 | printf("[167] 支持 #define\n"); 132 | int M1 = 5; 133 | 134 | #define M1 3 135 | ASSERT(3, M1); 136 | #define M1 4 137 | ASSERT(4, M1); 138 | 139 | #define M1 3+4+ 140 | ASSERT(12, M1 5); 141 | 142 | #define M1 3+4 143 | ASSERT(23, M1*5); 144 | 145 | #define ASSERT_ assert( 146 | #define if 5 147 | #define five "5" 148 | #define END ) 149 | ASSERT_ 5, if, five END; 150 | 151 | printf(" [168] 支持 #undef\n"); 152 | #undef ASSERT_ 153 | #undef if 154 | #undef five 155 | #undef END 156 | 157 | if (0); 158 | 159 | printf("[169] 展开 #if 和 #elif 中的参数\n"); 160 | #define M 5 161 | #if M 162 | m = 5; 163 | #else 164 | m = 6; 165 | #endif 166 | ASSERT(5, m); 167 | 168 | #define M 5 169 | #if M-5 170 | m = 6; 171 | #elif M 172 | m = 5; 173 | #endif 174 | ASSERT(5, m); 175 | 176 | printf("[170] 宏中只展开一次\n"); 177 | int M2 = 6; 178 | #define M2 M2 + 3 179 | ASSERT(9, M2); 180 | 181 | #define M3 M2 + 3 182 | ASSERT(12, M3); 183 | 184 | int M4 = 3; 185 | #define M4 M5 * 5 186 | #define M5 M4 + 2 187 | ASSERT(13, M4); 188 | 189 | printf("[171] 支持 #ifdef 和 #ifndef\n"); 190 | #ifdef M6 191 | m = 5; 192 | #else 193 | m = 3; 194 | #endif 195 | ASSERT(3, m); 196 | 197 | #define M6 198 | #ifdef M6 199 | m = 5; 200 | #else 201 | m = 3; 202 | #endif 203 | ASSERT(5, m); 204 | 205 | #ifndef M7 206 | m = 3; 207 | #else 208 | m = 5; 209 | #endif 210 | ASSERT(3, m); 211 | 212 | #define M7 213 | #ifndef M7 214 | m = 3; 215 | #else 216 | m = 5; 217 | #endif 218 | ASSERT(5, m); 219 | 220 | #if 0 221 | #ifdef NO_SUCH_MACRO 222 | #endif 223 | #ifndef NO_SUCH_MACRO 224 | #endif 225 | #else 226 | #endif 227 | 228 | printf("[172] 支持 #define 零参宏函数\n"); 229 | #define M7() 1 230 | int M7 = 5; 231 | ASSERT(1, M7()); 232 | ASSERT(5, M7); 233 | 234 | #define M7 () 235 | ASSERT(3, ret3 M7); 236 | 237 | printf("[173] 支持 #define 多参宏函数\n"); 238 | #define M8(x, y) x + y 239 | ASSERT(7, M8(3, 4)); 240 | 241 | #define M8(x, y) x *y 242 | ASSERT(24, M8(3 + 4, 4 + 5)); 243 | 244 | #define M8(x, y) (x) * (y) 245 | ASSERT(63, M8(3 + 4, 4 + 5)); 246 | 247 | printf("[174] 支持空的宏参数\n"); 248 | #define M8(x, y) x y 249 | ASSERT(9, M8(, 4 + 5)); 250 | 251 | printf("[175] 允许括号内的表达式作为宏参数\n"); 252 | #define M8(x, y) x *y 253 | ASSERT(20, M8((2 + 3), 4)); 254 | 255 | #define M8(x, y) x *y 256 | ASSERT(12, M8((2, 3), 4)); 257 | 258 | printf("[176] 宏函数中只展开一次\n"); 259 | #define dbl(x) M10(x) * x 260 | #define M10(x) dbl(x) + 3 261 | ASSERT(10, dbl(2)); 262 | 263 | printf("[177] 支持宏字符化操作符#\n"); 264 | #define M11(x) #x 265 | ASSERT('a', M11( a!b `""c)[0]); 266 | ASSERT('!', M11( a!b `""c)[1]); 267 | ASSERT('b', M11( a!b `""c)[2]); 268 | ASSERT(' ', M11( a!b `""c)[3]); 269 | ASSERT('`', M11( a!b `""c)[4]); 270 | ASSERT('"', M11( a!b `""c)[5]); 271 | ASSERT('"', M11( a!b `""c)[6]); 272 | ASSERT('c', M11( a!b `""c)[7]); 273 | ASSERT(0, M11( a!b `""c)[8]); 274 | 275 | printf("[178] 支持宏 ## 操作符\n"); 276 | #define paste(x,y) x##y 277 | ASSERT(15, paste(1,5)); 278 | ASSERT(255, paste(0,xff)); 279 | ASSERT(3, ({ int foobar=3; paste(foo,bar); })); 280 | ASSERT(5, paste(5,)); 281 | ASSERT(5, paste(,5)); 282 | 283 | #define i 5 284 | ASSERT(101, ({ int i3=100; paste(1+i,3); })); 285 | #undef i 286 | 287 | #define paste2(x) x##5 288 | ASSERT(26, paste2(1+2)); 289 | 290 | #define paste3(x) 2##x 291 | ASSERT(23, paste3(1+2)); 292 | 293 | #define paste4(x, y, z) x##y##z 294 | ASSERT(123, paste4(1,2,3)); 295 | 296 | printf("[180] 支持 defined() 宏操作符\n"); 297 | #define M12 298 | #if defined(M12) 299 | m = 3; 300 | #else 301 | m = 4; 302 | #endif 303 | ASSERT(3, m); 304 | 305 | #define M12 306 | #if defined M12 307 | m = 3; 308 | #else 309 | m = 4; 310 | #endif 311 | ASSERT(3, m); 312 | 313 | #if defined(M12) - 1 314 | m = 3; 315 | #else 316 | m = 4; 317 | #endif 318 | ASSERT(4, m); 319 | 320 | #if defined(NO_SUCH_MACRO) 321 | m = 3; 322 | #else 323 | m = 4; 324 | #endif 325 | ASSERT(4, m); 326 | 327 | printf("[181] 在常量表达式中替代遗留的标志符为0\n"); 328 | #if no_such_symbol == 0 329 | m = 5; 330 | #else 331 | m = 6; 332 | #endif 333 | ASSERT(5, m); 334 | 335 | printf("[182] 宏展开时保留新行和空格\n"); 336 | #define STR(x) #x 337 | #define M12(x) STR(x) 338 | #define M13(x) M12(foo.x) 339 | ASSERT(0, strcmp(M13(bar), "foo.bar")); 340 | 341 | #define M13(x) M12(foo. x) 342 | ASSERT(0, strcmp(M13(bar), "foo. bar")); 343 | 344 | #define M12 foo 345 | #define M13(x) STR(x) 346 | #define M14(x) M13(x.M12) 347 | ASSERT(0, strcmp(M14(bar), "bar.foo")); 348 | 349 | #define M14(x) M13(x. M12) 350 | ASSERT(0, strcmp(M14(bar), "bar. foo")); 351 | 352 | printf("[184] 支持 #include <...>\n"); 353 | #include "include3.h" 354 | ASSERT(3, foo); 355 | 356 | #include "include4.h" 357 | ASSERT(4, foo); 358 | 359 | #define M13 "include3.h" 360 | #include M13 361 | ASSERT(3, foo); 362 | 363 | #define M13 < include4.h 364 | #include M13 > 365 | ASSERT(4, foo); 366 | 367 | #undef foo 368 | 369 | printf("[189] 支持 __FILE__ 和 __LINE__\n"); 370 | ASSERT(0, strcmp(main_filename1, "test/macro.c")); 371 | ASSERT(9, main_line1); 372 | ASSERT(11, main_line2); 373 | ASSERT(0, strcmp(include1_filename, "test/include1.h")); 374 | ASSERT(5, include1_line); 375 | 376 | // [190] 支持 __VA_ARGS__ 377 | #define M14(...) 3 378 | ASSERT(3, M14()); 379 | 380 | #define M14(...) __VA_ARGS__ 381 | ASSERT(2, M14() 2); 382 | ASSERT(5, M14(5)); 383 | 384 | #define M14(...) add2(__VA_ARGS__) 385 | ASSERT(8, M14(2, 6)); 386 | 387 | #define M14(...) add6(1,2,__VA_ARGS__,6) 388 | ASSERT(21, M14(3,4,5)); 389 | 390 | #define M14(x, ...) add6(1,2,x,__VA_ARGS__,6) 391 | ASSERT(21, M14(3,4,5)); 392 | 393 | printf("[253] [GNU] 支持GCC风格的可变参数宏\n"); 394 | #define M14(args...) 3 395 | ASSERT(3, M14()); 396 | 397 | #define M14(x, ...) x 398 | ASSERT(5, M14(5)); 399 | 400 | printf("[253] [GNU] 支持GCC风格的可变参数宏\n"); 401 | #define M14(args...) args 402 | ASSERT(2, M14() 2); 403 | ASSERT(5, M14(5)); 404 | 405 | #define M14(args...) add2(args) 406 | ASSERT(8, M14(2, 6)); 407 | 408 | #define M14(args...) add6(1,2,args,6) 409 | ASSERT(21, M14(3,4,5)); 410 | 411 | #define M14(x, args...) add6(1,2,x,args,6) 412 | ASSERT(21, M14(3,4,5)); 413 | 414 | #define M14(x, args...) x 415 | ASSERT(5, M14(5)); 416 | 417 | // [207] 解析数值终结符为pp-number 418 | #define CONCAT(x,y) x##y 419 | ASSERT(5, ({ int f0zz=5; CONCAT(f,0zz); })); 420 | ASSERT(5, ({ CONCAT(4,.57) + 0.5; })); 421 | 422 | printf("[221] 支持__DATE__和__TIME__宏\n"); 423 | ASSERT(11, strlen(__DATE__)); 424 | ASSERT(8, strlen(__TIME__)); 425 | 426 | printf("[222] [GNU] 支持__COUNTER__宏\n"); 427 | ASSERT(0, __COUNTER__); 428 | ASSERT(1, __COUNTER__); 429 | ASSERT(2, __COUNTER__); 430 | 431 | printf("[248] [GNU] 支持__TIMESTAMP__宏\n"); 432 | ASSERT(24, strlen(__TIMESTAMP__)); 433 | 434 | printf("[249] [GNU] 支持__BASE_FILE__宏\n"); 435 | ASSERT(0, strcmp(__BASE_FILE__, "test/macro.c")); 436 | 437 | printf("[250] 支持__VA_OPT__\n"); 438 | #define M30(buf, fmt, ...) sprintf(buf, fmt __VA_OPT__(, ) __VA_ARGS__) 439 | ASSERT(0, ({ char buf[100]; M30(buf, "foo"); strcmp(buf, "foo"); })); 440 | ASSERT(0, ({ char buf[100]; M30(buf, "foo%d", 3); strcmp(buf, "foo3"); })); 441 | ASSERT(0, ({ char buf[100]; M30(buf, "foo%d%d", 3, 5); strcmp(buf, "foo35"); })); 442 | 443 | printf("[251] [GNU] 处理 ## __VA_ARGS__\n"); 444 | #define M31(buf, fmt, ...) sprintf(buf, fmt, ##__VA_ARGS__) 445 | ASSERT(0, ({ char buf[100]; M31(buf, "foo"); strcmp(buf, "foo"); })); 446 | ASSERT(0, ({ char buf[100]; M31(buf, "foo%d", 3); strcmp(buf, "foo3"); })); 447 | ASSERT(0, ({ char buf[100]; M31(buf, "foo%d%d", 3, 5); strcmp(buf, "foo35"); })); 448 | 449 | #define M31(x, y) (1, ##x y) 450 | ASSERT(3, M31(, 3)); 451 | 452 | printf("OK\n"); 453 | return 0; 454 | } 455 | -------------------------------------------------------------------------------- /test/offsetof.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include 3 | 4 | // [264] 支持offsetof 5 | typedef struct { 6 | int a; 7 | char b; 8 | int c; 9 | double d; 10 | } T; 11 | 12 | int main() { 13 | printf("[264] 支持offsetof\n"); 14 | ASSERT(0, offsetof(T, a)); 15 | ASSERT(4, offsetof(T, b)); 16 | ASSERT(8, offsetof(T, c)); 17 | ASSERT(16, offsetof(T, d)); 18 | 19 | printf("OK\n"); 20 | return 0; 21 | } 22 | -------------------------------------------------------------------------------- /test/pointer.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int main() { 4 | // [20] 支持一元& *运算符 5 | ASSERT(3, ({ int x=3; *&x; })); 6 | ASSERT(3, ({ int x=3; int *y=&x; int **z=&y; **z; })); 7 | ASSERT(5, ({ int x=3; int y=5; *(&x+1); })); 8 | ASSERT(3, ({ int x=3; int y=5; *(&y-1); })); 9 | ASSERT(5, ({ int x=3; int y=5; *(&x-(-1)); })); 10 | ASSERT(5, ({ int x=3; int *y=&x; *y=5; x; })); 11 | ASSERT(7, ({ int x=3; int y=5; *(&x+1)=7; y; })); 12 | ASSERT(7, ({ int x=3; int y=5; *(&y-2+1)=7; x; })); 13 | ASSERT(5, ({ int x=3; (&x+2)-&x+3; })); 14 | ASSERT(8, ({ int x, y; x=3; y=5; x+y; })); 15 | ASSERT(8, ({ int x=3, y=5; x+y; })); 16 | 17 | // [27] 支持一维数组 18 | ASSERT(3, ({ int x[2]; int *y=&x; *y=3; *x; })); 19 | 20 | ASSERT(3, ({ int x[3]; *x=3; *(x+1)=4; *(x+2)=5; *x; })); 21 | ASSERT(4, ({ int x[3]; *x=3; *(x+1)=4; *(x+2)=5; *(x+1); })); 22 | ASSERT(5, ({ int x[3]; *x=3; *(x+1)=4; *(x+2)=5; *(x+2); })); 23 | 24 | // [28] 支持多维数组 25 | ASSERT(0, ({ int x[2][3]; int *y=x; *y=0; **x; })); 26 | ASSERT(1, ({ int x[2][3]; int *y=x; *(y+1)=1; *(*x+1); })); 27 | ASSERT(2, ({ int x[2][3]; int *y=x; *(y+2)=2; *(*x+2); })); 28 | ASSERT(3, ({ int x[2][3]; int *y=x; *(y+3)=3; **(x+1); })); 29 | ASSERT(4, ({ int x[2][3]; int *y=x; *(y+4)=4; *(*(x+1)+1); })); 30 | ASSERT(5, ({ int x[2][3]; int *y=x; *(y+5)=5; *(*(x+1)+2); })); 31 | 32 | ASSERT(3, ({ int x[3]; *x=3; x[1]=4; x[2]=5; *x; })); 33 | ASSERT(4, ({ int x[3]; *x=3; x[1]=4; x[2]=5; *(x+1); })); 34 | ASSERT(5, ({ int x[3]; *x=3; x[1]=4; x[2]=5; *(x+2); })); 35 | ASSERT(5, ({ int x[3]; *x=3; x[1]=4; x[2]=5; *(x+2); })); 36 | ASSERT(5, ({ int x[3]; *x=3; x[1]=4; 2[x]=5; *(x+2); })); 37 | 38 | // [29] 支持 [] 操作符 39 | ASSERT(0, ({ int x[2][3]; int *y=x; y[0]=0; x[0][0]; })); 40 | ASSERT(1, ({ int x[2][3]; int *y=x; y[1]=1; x[0][1]; })); 41 | ASSERT(2, ({ int x[2][3]; int *y=x; y[2]=2; x[0][2]; })); 42 | ASSERT(3, ({ int x[2][3]; int *y=x; y[3]=3; x[1][0]; })); 43 | ASSERT(4, ({ int x[2][3]; int *y=x; y[4]=4; x[1][1]; })); 44 | ASSERT(5, ({ int x[2][3]; int *y=x; y[5]=5; x[1][2]; })); 45 | 46 | printf("OK\n"); 47 | return 0; 48 | } 49 | -------------------------------------------------------------------------------- /test/pragma-once.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | // [299] [GNU] 支持#pragma once 4 | #pragma once 5 | 6 | #include "test/pragma-once.c" 7 | 8 | int main() { 9 | printf("OK\n"); 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /test/sizeof.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int main() { 4 | // [65] 支持对类型进行sizeof 5 | ASSERT(1, sizeof(char)); 6 | ASSERT(2, sizeof(short)); 7 | ASSERT(2, sizeof(short int)); 8 | ASSERT(2, sizeof(int short)); 9 | ASSERT(4, sizeof(int)); 10 | ASSERT(8, sizeof(long)); 11 | ASSERT(8, sizeof(long int)); 12 | ASSERT(8, sizeof(long int)); 13 | ASSERT(8, sizeof(char *)); 14 | ASSERT(8, sizeof(int *)); 15 | ASSERT(8, sizeof(long *)); 16 | ASSERT(8, sizeof(int **)); 17 | ASSERT(8, sizeof(int(*)[4])); 18 | ASSERT(32, sizeof(int*[4])); 19 | ASSERT(16, sizeof(int[4])); 20 | ASSERT(48, sizeof(int[3][4])); 21 | ASSERT(8, sizeof(struct {int a; int b;})); 22 | 23 | // [68] 实现常规算术转换 24 | ASSERT(8, sizeof(-10 + (long)5)); 25 | ASSERT(8, sizeof(-10 - (long)5)); 26 | ASSERT(8, sizeof(-10 * (long)5)); 27 | ASSERT(8, sizeof(-10 / (long)5)); 28 | ASSERT(8, sizeof((long)-10 + 5)); 29 | ASSERT(8, sizeof((long)-10 - 5)); 30 | ASSERT(8, sizeof((long)-10 * 5)); 31 | ASSERT(8, sizeof((long)-10 / 5)); 32 | 33 | // [78] 支持前置++和-- 34 | ASSERT(1, ({ char i; sizeof(++i); })); 35 | // [79] 支持后置++和-- 36 | ASSERT(1, ({ char i; sizeof(i++); })); 37 | 38 | // [86] 增加不完整数组类型的概念 39 | ASSERT(8, sizeof(int(*)[10])); 40 | ASSERT(8, sizeof(int(*)[][10])); 41 | 42 | // [112] 支持灵活数组成员 43 | ASSERT(4, sizeof(struct { int x, y[]; })); 44 | 45 | // [130] 支持signed关键字 46 | ASSERT(1, sizeof(char)); 47 | ASSERT(1, sizeof(signed char)); 48 | ASSERT(1, sizeof(signed char signed)); 49 | // [131] 支持无符号整型 50 | ASSERT(1, sizeof(unsigned char)); 51 | ASSERT(1, sizeof(unsigned char unsigned)); 52 | 53 | // [130] 支持signed关键字 54 | ASSERT(2, sizeof(short)); 55 | ASSERT(2, sizeof(int short)); 56 | ASSERT(2, sizeof(short int)); 57 | ASSERT(2, sizeof(signed short)); 58 | ASSERT(2, sizeof(int short signed)); 59 | // [131] 支持无符号整型 60 | ASSERT(2, sizeof(unsigned short)); 61 | ASSERT(2, sizeof(int short unsigned)); 62 | 63 | // [130] 支持signed关键字 64 | ASSERT(4, sizeof(int)); 65 | ASSERT(4, sizeof(signed int)); 66 | ASSERT(4, sizeof(signed)); 67 | ASSERT(4, sizeof(signed signed)); 68 | // [131] 支持无符号整型 69 | ASSERT(4, sizeof(unsigned int)); 70 | ASSERT(4, sizeof(unsigned)); 71 | ASSERT(4, sizeof(unsigned unsigned)); 72 | 73 | // [130] 支持signed关键字 74 | ASSERT(8, sizeof(long)); 75 | ASSERT(8, sizeof(signed long)); 76 | ASSERT(8, sizeof(signed long int)); 77 | // [131] 支持无符号整型 78 | ASSERT(8, sizeof(unsigned long)); 79 | ASSERT(8, sizeof(unsigned long int)); 80 | 81 | // [130] 支持signed关键字 82 | ASSERT(8, sizeof(long long)); 83 | ASSERT(8, sizeof(signed long long)); 84 | ASSERT(8, sizeof(signed long long int)); 85 | // [131] 支持无符号整型 86 | ASSERT(8, sizeof(unsigned long long)); 87 | ASSERT(8, sizeof(unsigned long long int)); 88 | 89 | ASSERT(1, sizeof((char)1)); 90 | ASSERT(2, sizeof((short)1)); 91 | ASSERT(4, sizeof((int)1)); 92 | ASSERT(8, sizeof((long)1)); 93 | 94 | ASSERT(4, sizeof((char)1 + (char)1)); 95 | ASSERT(4, sizeof((short)1 + (short)1)); 96 | ASSERT(4, sizeof(1?2:3)); 97 | ASSERT(4, sizeof(1?(short)2:(char)3)); 98 | ASSERT(8, sizeof(1?(long)2:(char)3)); 99 | 100 | // [133] 在一些表达式中用long或ulong替代int 101 | ASSERT(1, sizeof(char) << 31 >> 31); 102 | ASSERT(1, sizeof(char) << 63 >> 63); 103 | 104 | // [140] 支持float和double用于局部变量或类型转换 105 | ASSERT(4, sizeof(float)); 106 | ASSERT(8, sizeof(double)); 107 | 108 | // [142] 支持浮点数的 + - *和/ 109 | ASSERT(4, sizeof(1f + 2)); 110 | ASSERT(8, sizeof(1.0+2)); 111 | ASSERT(4, sizeof(1f-2)); 112 | ASSERT(8, sizeof(1.0-2)); 113 | ASSERT(4, sizeof(1f*2)); 114 | ASSERT(8, sizeof(1.0*2)); 115 | ASSERT(4, sizeof(1f/2)); 116 | ASSERT(8, sizeof(1.0/2)); 117 | 118 | printf("[280] 支持long double\n"); 119 | ASSERT(16, sizeof(long double)); 120 | 121 | printf("[257] [GNU] 支持sizeof函数类型\n"); 122 | ASSERT(1, sizeof(main)); 123 | 124 | printf("OK\n"); 125 | return 0; 126 | } 127 | -------------------------------------------------------------------------------- /test/stdhdr.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | int main() { 10 | // [195] 支持多个头文件 11 | printf("OK\n"); 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /test/string.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int main() { 4 | // [34] 支持字符串字面量 5 | ASSERT(0, ""[0]); 6 | ASSERT(1, sizeof("")); 7 | 8 | ASSERT(97, "abc"[0]); 9 | ASSERT(98, "abc"[1]); 10 | ASSERT(99, "abc"[2]); 11 | ASSERT(0, "abc"[3]); 12 | ASSERT(4, sizeof("abc")); 13 | 14 | // [36] 支持转义字符 15 | ASSERT(7, "\a"[0]); 16 | ASSERT(8, "\b"[0]); 17 | ASSERT(9, "\t"[0]); 18 | ASSERT(10, "\n"[0]); 19 | ASSERT(11, "\v"[0]); 20 | ASSERT(12, "\f"[0]); 21 | ASSERT(13, "\r"[0]); 22 | ASSERT(27, "\e"[0]); 23 | 24 | ASSERT(106, "\j"[0]); 25 | ASSERT(107, "\k"[0]); 26 | ASSERT(108, "\l"[0]); 27 | 28 | ASSERT(7, "\ax\ny"[0]); 29 | ASSERT(120, "\ax\ny"[1]); 30 | ASSERT(10, "\ax\ny"[2]); 31 | ASSERT(121, "\ax\ny"[3]); 32 | 33 | // [37] 支持八进制转义字符 34 | ASSERT(0, "\0"[0]); 35 | ASSERT(16, "\20"[0]); 36 | ASSERT(65, "\101"[0]); 37 | ASSERT(104, "\1500"[0]); 38 | // [38] 支持十六进制转义字符 39 | ASSERT(0, "\x00"[0]); 40 | ASSERT(119, "\x77"[0]); 41 | 42 | printf("[193] 连接相邻的字符串\n"); 43 | ASSERT(7, sizeof("abc" "def")); 44 | ASSERT(9, sizeof("abc" "d" "efgh")); 45 | ASSERT(0, strcmp("abc" "d" "\nefgh", "abcd\nefgh")); 46 | ASSERT(0, !strcmp("abc" "d", "abcd\nefgh")); 47 | ASSERT(0, strcmp("\x9" "0", "\t0")); 48 | 49 | printf("[237] 支持拼接常规字符串字面量和L u U字符串字面量\n"); 50 | ASSERT(16, sizeof(L"abc" "")); 51 | 52 | ASSERT(28, sizeof(L"abc" "def")); 53 | ASSERT(28, sizeof(L"abc" L"def")); 54 | ASSERT(14, sizeof(u"abc" "def")); 55 | ASSERT(14, sizeof(u"abc" u"def")); 56 | 57 | ASSERT(L'a', (L"abc" "def")[0]); 58 | ASSERT(L'd', (L"abc" "def")[3]); 59 | ASSERT(L'\0', (L"abc" "def")[6]); 60 | 61 | ASSERT(u'a', (u"abc" "def")[0]); 62 | ASSERT(u'd', (u"abc" "def")[3]); 63 | ASSERT(u'\0', (u"abc" "def")[6]); 64 | 65 | ASSERT(L'あ', ("あ" L"")[0]); 66 | ASSERT(0343, ("\343\201\202" L"")[0]); 67 | ASSERT(0201, ("\343\201\202" L"")[1]); 68 | ASSERT(0202, ("\343\201\202" L"")[2]); 69 | ASSERT(0, ("\343\201\202" L"")[3]); 70 | 71 | ASSERT(L'a', ("a" "b" L"c")[0]); 72 | ASSERT(L'b', ("a" "b" L"c")[1]); 73 | ASSERT(L'c', ("a" "b" L"c")[2]); 74 | ASSERT(0, ("a" "b" L"c")[3]); 75 | 76 | printf("OK\n"); 77 | return 0; 78 | } 79 | -------------------------------------------------------------------------------- /test/struct.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int main() { 4 | // [49] 支持struct 5 | ASSERT(1, ({ struct {int a; int b;} x; x.a=1; x.b=2; x.a; })); 6 | ASSERT(2, ({ struct {int a; int b;} x; x.a=1; x.b=2; x.b; })); 7 | ASSERT(1, ({ struct {char a; int b; char c;} x; x.a=1; x.b=2; x.c=3; x.a; })); 8 | ASSERT(2, ({ struct {char a; int b; char c;} x; x.b=1; x.b=2; x.c=3; x.b; })); 9 | ASSERT(3, ({ struct {char a; int b; char c;} x; x.a=1; x.b=2; x.c=3; x.c; })); 10 | 11 | ASSERT(0, ({ struct {char a; char b;} x[3]; char *p=x; p[0]=0; x[0].a; })); 12 | ASSERT(1, ({ struct {char a; char b;} x[3]; char *p=x; p[1]=1; x[0].b; })); 13 | ASSERT(2, ({ struct {char a; char b;} x[3]; char *p=x; p[2]=2; x[1].a; })); 14 | ASSERT(3, ({ struct {char a; char b;} x[3]; char *p=x; p[3]=3; x[1].b; })); 15 | 16 | ASSERT(6, ({ struct {char a[3]; char b[5];} x; char *p=&x; x.a[0]=6; p[0]; })); 17 | ASSERT(7, ({ struct {char a[3]; char b[5];} x; char *p=&x; x.b[0]=7; p[3]; })); 18 | 19 | ASSERT(6, ({ struct { struct { char b; } a; } x; x.a.b=6; x.a.b; })); 20 | 21 | ASSERT(4, ({ struct {int a;} x; sizeof(x); })); 22 | ASSERT(8, ({ struct {int a; int b;} x; sizeof(x); })); 23 | ASSERT(8, ({ struct {int a, b;} x; sizeof(x); })); 24 | ASSERT(12, ({ struct {int a[3];} x; sizeof(x); })); 25 | ASSERT(16, ({ struct {int a;} x[4]; sizeof(x); })); 26 | ASSERT(24, ({ struct {int a[3];} x[2]; sizeof(x); })); 27 | ASSERT(2, ({ struct {char a; char b;} x; sizeof(x); })); 28 | ASSERT(0, ({ struct {} x; sizeof(x); })); 29 | 30 | // [50] 对齐结构体成员变量 31 | ASSERT(8, ({ struct {char a; int b;} x; sizeof(x); })); 32 | ASSERT(8, ({ struct {int a; char b;} x; sizeof(x); })); 33 | 34 | // [52] 支持结构体标签 35 | ASSERT(8, ({ struct t {int a; int b;} x; struct t y; sizeof(y); })); 36 | ASSERT(8, ({ struct t {int a; int b;}; struct t y; sizeof(y); })); 37 | ASSERT(2, ({ struct t {char a[2];}; { struct t {char a[4];}; } struct t y; sizeof(y); })); 38 | ASSERT(3, ({ struct t {int x;}; int t=1; struct t y; y.x=2; t+y.x; })); 39 | 40 | // [53] 支持->操作符 41 | ASSERT(3, ({ struct t {char a;} x; struct t *y = &x; x.a=3; y->a; })); 42 | ASSERT(3, ({ struct t {char a;} x; struct t *y = &x; y->a=3; x.a; })); 43 | 44 | // [55] 支持结构体赋值 45 | ASSERT(3, ({ struct {int a,b;} x,y; x.a=3; y=x; y.a; })); 46 | ASSERT(7, ({ struct t {int a,b;}; struct t x; x.a=7; struct t y; struct t *z=&y; *z=x; y.a; })); 47 | ASSERT(7, ({ struct t {int a,b;}; struct t x; x.a=7; struct t y, *p=&x, *q=&y; *q=*p; y.a; })); 48 | ASSERT(5, ({ struct t {char a, b;} x, y; x.a=5; y=x; y.a; })); 49 | 50 | // [56] 将int的大小由8改为4 51 | ASSERT(3, ({ struct {int a,b;} x,y; x.a=3; y=x; y.a; })); 52 | ASSERT(7, ({ struct t {int a,b;}; struct t x; x.a=7; struct t y; struct t *z=&y; *z=x; y.a; })); 53 | ASSERT(7, ({ struct t {int a,b;}; struct t x; x.a=7; struct t y, *p=&x, *q=&y; *q=*p; y.a; })); 54 | ASSERT(5, ({ struct t {char a, b;} x, y; x.a=5; y=x; y.a; })); 55 | 56 | ASSERT(8, ({ struct t {int a; int b;} x; struct t y; sizeof(y); })); 57 | ASSERT(8, ({ struct t {int a; int b;}; struct t y; sizeof(y); })); 58 | 59 | // [57] 支持long类型 60 | ASSERT(16, ({ struct {char a; long b;} x; sizeof(x); })); 61 | 62 | // [58] 支持short类型 63 | ASSERT(4, ({ struct {char a; short b;} x; sizeof(x); })); 64 | 65 | // [88] 增加不完整结构体的概念 66 | ASSERT(8, ({ struct foo *bar; sizeof(bar); })); 67 | ASSERT(4, ({ struct T *foo; struct T {int x;}; sizeof(struct T); })); 68 | ASSERT(1, ({ struct T { struct T *next; int x; } a; struct T b; b.x=1; a.next=&b; a.next->x; })); 69 | ASSERT(4, ({ typedef struct T T; struct T { int x; }; sizeof(T); })); 70 | 71 | printf("[316] 使结构体成员可以通过=或?:访问"); 72 | ASSERT(2, ({ struct {int a;} x={1}, y={2}; (x=y).a; })); 73 | ASSERT(1, ({ struct {int a;} x={1}, y={2}; (1?x:y).a; })); 74 | ASSERT(2, ({ struct {int a;} x={1}, y={2}; (0?x:y).a; })); 75 | 76 | 77 | printf("OK\n"); 78 | return 0; 79 | } 80 | -------------------------------------------------------------------------------- /test/test.h: -------------------------------------------------------------------------------- 1 | #define ASSERT(x, y) assert(x, y, #y) 2 | 3 | // [69] 对未定义或未声明的函数报错 4 | void assert(int expected, int actual, char *code); 5 | 6 | // [60] 支持函数声明 7 | int printf(char *fmt, ...); 8 | 9 | // [107] 为全局变量处理联合体初始化 10 | int strcmp(char *p, char *q); 11 | int memcmp(char *p, char *q, long n); 12 | // [193] 连接相邻的字符串 13 | int strncmp(char *p, char *q, long n); 14 | 15 | // [127] 允许调用可变参数函数 16 | int sprintf(char *buf, char *fmt, ...); 17 | 18 | // [136] 忽略const volatile auto register restrict _Noreturn 19 | void exit(int n); 20 | 21 | // [204] 支持可变参数函数接受任意数量的参数 22 | int vsprintf(char *buf, char *fmt, void *ap); 23 | 24 | // [221] 支持__DATE__和__TIME__宏 25 | long strlen(char *s); 26 | 27 | // [271] 支持alloca函数 28 | void *memcpy(void *dest, void *src, long n); 29 | 30 | // [273] 为VLA支持指针算术运算 31 | void *memset(void *s, int c, long n); 32 | -------------------------------------------------------------------------------- /test/thirdparty/common: -------------------------------------------------------------------------------- 1 | make="make -j$(nproc)" 2 | rvcc=`pwd`/rvcc 3 | 4 | dir=$(basename -s .git $repo) 5 | 6 | set -e -x 7 | 8 | mkdir -p thirdparty 9 | cd thirdparty 10 | [ -d $dir ] || git clone $repo 11 | cd $dir 12 | -------------------------------------------------------------------------------- /test/thirdparty/cpython.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | repo='git@github.com:python/cpython.git' 3 | . test/thirdparty/common 4 | git reset --hard c75330605d4795850ec74fdc4d69aa5d92f76c00 5 | 6 | # 在Python的 ./configure' 会错将rvcc识别为icc(其功能是rvcc的子集) 7 | sed -i -e 1996,2011d configure.ac 8 | autoreconf 9 | 10 | CC=$rvcc ./configure 11 | $make clean 12 | $make 13 | $make test 14 | -------------------------------------------------------------------------------- /test/thirdparty/git.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | repo='https://github.com/git/git.git' 3 | . test/thirdparty/common 4 | git reset --hard 54e85e7af1ac9e9a92888060d6811ae767fea1bc 5 | 6 | $make clean 7 | $make V=1 CC=$rvcc test 8 | -------------------------------------------------------------------------------- /test/thirdparty/libpng.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | repo='https://github.com/glennrp/libpng.git' 3 | . test/thirdparty/common 4 | git reset --hard dbe3e0c43e549a1602286144d94b0666549b18e6 5 | 6 | CC=$rvcc ./configure 7 | sed -i 's/^wl=.*/wl=-Wl,/; s/^pic_flag=.*/pic_flag=-fPIC/' libtool 8 | $make clean 9 | $make 10 | $make test 11 | -------------------------------------------------------------------------------- /test/thirdparty/lua.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | repo='https://github.com/lua/lua.git' 3 | . test/thirdparty/common 4 | git reset --hard be908a7d4d8130264ad67c5789169769f824c5d1 5 | 6 | sed -i 's/CC= gcc/CC?= gcc/' makefile 7 | CC=$rvcc $make all 8 | ./all 9 | -------------------------------------------------------------------------------- /test/thirdparty/sqlite.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | repo='https://github.com/sqlite/sqlite.git' 3 | . test/thirdparty/common 4 | git reset --hard 86f477edaa17767b39c7bae5b67cac8580f7a8c1 5 | 6 | CC=$rvcc CFLAGS=-D_GNU_SOURCE ./configure 7 | sed -i 's/^wl=.*/wl=-Wl,/; s/^pic_flag=.*/pic_flag=-fPIC/' libtool 8 | $make clean 9 | $make 10 | # 最后测试结果:sessionfuzz-data1.db: 339 cases, 0 crashes 11 | # 存在已知错误,最后返回值应为 2 12 | $make test 13 | -------------------------------------------------------------------------------- /test/thirdparty/tinycc.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | repo='https://github.com/TinyCC/tinycc.git' 3 | . test/thirdparty/common 4 | git reset --hard aea2b53123b987a14d99126be22947ebda455082 5 | 6 | ./configure --cc=$rvcc 7 | $make clean 8 | $make 9 | $make CC=cc test 10 | -------------------------------------------------------------------------------- /test/tls.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include 3 | #include 4 | 5 | // [267] 支持线程局部变量 6 | _Thread_local int v1; 7 | _Thread_local int v2 = 5; 8 | int v3 = 7; 9 | 10 | int thread_main(void *unused) { 11 | ASSERT(0, v1); 12 | ASSERT(5, v2); 13 | ASSERT(7, v3); 14 | 15 | v1 = 1; 16 | v2 = 2; 17 | v3 = 3; 18 | 19 | ASSERT(1, v1); 20 | ASSERT(2, v2); 21 | ASSERT(3, v3); 22 | 23 | return 0; 24 | } 25 | 26 | int main() { 27 | printf("[267] 支持线程局部变量\n"); 28 | pthread_t thr; 29 | 30 | ASSERT(0, v1); 31 | ASSERT(5, v2); 32 | ASSERT(7, v3); 33 | 34 | ASSERT(0, pthread_create(&thr, NULL, thread_main, NULL)); 35 | ASSERT(0, pthread_join(thr, NULL)); 36 | 37 | ASSERT(0, v1); 38 | ASSERT(5, v2); 39 | ASSERT(3, v3); 40 | 41 | printf("OK\n"); 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /test/typedef.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | typedef int MyInt, MyInt2[4]; 4 | typedef int; 5 | 6 | int main() { 7 | // [64] 支持typedef 8 | ASSERT(1, ({ typedef int t; t x=1; x; })); 9 | ASSERT(1, ({ typedef struct {int a;} t; t x; x.a=1; x.a; })); 10 | ASSERT(1, ({ typedef int t; t t=1; t; })); 11 | ASSERT(2, ({ typedef struct {int a;} t; { typedef int t; } t x; x.a=2; x.a; })); 12 | ASSERT(4, ({ typedef t; t x; sizeof(x); })); 13 | ASSERT(3, ({ MyInt x=3; x; })); 14 | ASSERT(16, ({ MyInt2 x; sizeof(x); })); 15 | 16 | printf("OK\n"); 17 | return 0; 18 | } 19 | -------------------------------------------------------------------------------- /test/typeof.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int main() { 4 | printf("[254] 支持typeof\n"); 5 | ASSERT(3, ({ typeof(int) x=3; x; })); 6 | ASSERT(3, ({ typeof(1) x=3; x; })); 7 | ASSERT(4, ({ int x; typeof(x) y; sizeof(y); })); 8 | ASSERT(8, ({ int x; typeof(&x) y; sizeof(y); })); 9 | ASSERT(4, ({ typeof("foo") x; sizeof(x); })); 10 | ASSERT(12, sizeof(typeof(struct { int a,b,c; }))); 11 | 12 | printf("OK\n"); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /test/unicode.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | // [226] 支持UTF-16字符字面量 4 | #define STR(x) #x 5 | 6 | // [232] 支持UTF-16字符串字面量初始化器 7 | typedef unsigned short char16_t; 8 | // [233] 支持UTF-32字符串字面量初始化器 9 | typedef unsigned int char32_t; 10 | typedef int wchar_t; 11 | 12 | // [235] 支持标识符使用多字节UTF-8字符 13 | int π = 3; 14 | 15 | int main() { 16 | printf("[224] 支持\\u和\\U转义序列\n"); 17 | ASSERT(4, sizeof(L'\0')); 18 | ASSERT(97, L'a'); 19 | 20 | ASSERT(0, strcmp("αβγ", "\u03B1\u03B2\u03B3")); 21 | ASSERT(0, strcmp("日本語", "\u65E5\u672C\u8A9E")); 22 | ASSERT(0, strcmp("日本語", "\U000065E5\U0000672C\U00008A9E")); 23 | ASSERT(0, strcmp("中文", "\u4E2D\u6587")); 24 | ASSERT(0, strcmp("中文", "\U00004E2D\U00006587")); 25 | ASSERT(0, strcmp("🌮", "\U0001F32E")); 26 | 27 | printf("[225] 支持多字节字符作为宽字符字面量\n"); 28 | ASSERT(-1, L'\xffffffff' >> 31); 29 | ASSERT(946, L'β'); 30 | ASSERT(12354, L'あ'); 31 | ASSERT(127843, L'🍣'); 32 | 33 | printf("[226] 支持UTF-16字符字面量\n"); 34 | ASSERT(2, sizeof(u'\0')); 35 | ASSERT(1, u'\xffff'>>15); 36 | ASSERT(97, u'a'); 37 | ASSERT(946, u'β'); 38 | ASSERT(12354, u'あ'); 39 | ASSERT(62307, u'🍣'); 40 | 41 | ASSERT(0, strcmp(STR(u'a'), "u'a'")); 42 | 43 | printf("[227] 支持UTF-32字符字面量\n"); 44 | ASSERT(4, sizeof(U'\0')); 45 | ASSERT(1, U'\xffffffff' >> 31); 46 | ASSERT(97, U'a'); 47 | ASSERT(946, U'β'); 48 | ASSERT(12354, U'あ'); 49 | ASSERT(127843, U'🍣'); 50 | 51 | ASSERT(0, strcmp(STR(U'a'), "U'a'")); 52 | 53 | printf("[228] 支持UTF-8字符串字面量\n"); 54 | ASSERT(4, sizeof(u8"abc")); 55 | ASSERT(5, sizeof(u8"😀")); 56 | ASSERT(7, sizeof(u8"汉语")); 57 | ASSERT(0, strcmp(u8"abc", "abc")); 58 | 59 | ASSERT(0, strcmp(STR(u8"a"), "u8\"a\"")); 60 | 61 | printf("[229] 支持UTF-16字符串字面量\n"); 62 | ASSERT(2, sizeof(u"")); 63 | ASSERT(10, sizeof(u"\xffzzz")); 64 | ASSERT(0, memcmp(u"", "\0\0", 2)); 65 | ASSERT(0, memcmp(u"abc", "a\0b\0c\0\0\0", 8)); 66 | ASSERT(0, memcmp(u"日本語", "\345e,g\236\212\0\0", 8)); 67 | ASSERT(0, memcmp(u"🍣", "<\330c\337\0\0", 6)); 68 | ASSERT(u'β', u"βb"[0]); 69 | ASSERT(u'b', u"βb"[1]); 70 | ASSERT(0, u"βb"[2]); 71 | 72 | ASSERT(0, strcmp(STR(u"a"), "u\"a\"")); 73 | 74 | printf("[230] 支持UTF-32字符串字面量\n"); 75 | ASSERT(4, sizeof(U"")); 76 | ASSERT(20, sizeof(U"\xffzzz")); 77 | ASSERT(0, memcmp(U"", "\0\0\0\0", 4)); 78 | ASSERT(0, memcmp(U"abc", "a\0\0\0b\0\0\0c\0\0\0\0\0\0\0", 16)); 79 | ASSERT(0, memcmp(U"日本語", "\345e\0\0,g\0\0\236\212\0\0\0\0\0\0", 16)); 80 | ASSERT(0, memcmp(U"🍣", "c\363\001\0\0\0\0\0", 8)); 81 | ASSERT(u'β', U"βb"[0]); 82 | ASSERT(u'b', U"βb"[1]); 83 | ASSERT(0, U"βb"[2]); 84 | ASSERT(1, U"\xffffffff"[0] >> 31); 85 | 86 | ASSERT(0, strcmp(STR(U"a"), "U\"a\"")); 87 | 88 | printf("[231] 支持宽字符串字面量\n"); 89 | ASSERT(4, sizeof(L"")); 90 | ASSERT(20, sizeof(L"\xffzzz")); 91 | ASSERT(0, memcmp(L"", "\0\0\0\0", 4)); 92 | ASSERT(0, memcmp(L"abc", "a\0\0\0b\0\0\0c\0\0\0\0\0\0\0", 16)); 93 | ASSERT(0, memcmp(L"日本語", "\345e\0\0,g\0\0\236\212\0\0\0\0\0\0", 16)); 94 | ASSERT(0, memcmp(L"🍣", "c\363\001\0\0\0\0\0", 8)); 95 | ASSERT(u'β', L"βb"[0]); 96 | ASSERT(u'b', L"βb"[1]); 97 | ASSERT(0, L"βb"[2]); 98 | ASSERT(-1, L"\xffffffff"[0] >> 31); 99 | 100 | ASSERT(0, strcmp(STR(L"a"), "L\"a\"")); 101 | 102 | printf("[232] 支持UTF-16字符串字面量初始化器\n"); 103 | ASSERT(u'α', ({ char16_t x[] = u"αβ"; x[0]; })); 104 | ASSERT(u'β', ({ char16_t x[] = u"αβ"; x[1]; })); 105 | ASSERT(6, ({ char16_t x[] = u"αβ"; sizeof(x); })); 106 | 107 | printf("[233] 支持UTF-32字符串字面量初始化器\n"); 108 | ASSERT(U'🤔', ({ char32_t x[] = U"🤔x"; x[0]; })); 109 | ASSERT(U'x', ({ char32_t x[] = U"🤔x"; x[1]; })); 110 | ASSERT(12, ({ char32_t x[] = U"🤔x"; sizeof(x); })); 111 | 112 | ASSERT(L'🤔', ({ wchar_t x[] = L"🤔x"; x[0]; })); 113 | ASSERT(L'x', ({ wchar_t x[] = L"🤔x"; x[1]; })); 114 | ASSERT(12, ({ wchar_t x[] = L"🤔x"; sizeof(x); })); 115 | 116 | printf("[235] 支持标识符使用多字节UTF-8字符\n"); 117 | ASSERT(3, π); 118 | ASSERT(3, ({ int あβ0¾=3; あβ0¾; })); 119 | 120 | printf("[236] [GNU] 支持使用$作为标志符字符\n"); 121 | ASSERT(5, ({ int $$$=5; $$$; })); 122 | 123 | printf("OK\n"); 124 | return 0; 125 | } 126 | -------------------------------------------------------------------------------- /test/union.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | struct foo_1 {float f;union {int x;};}; 4 | int test_1(struct foo_1 in) { return in.f; } 5 | int test_2(struct foo_1 in) { return in.x; } 6 | 7 | int main() { 8 | // [54] 支持union 9 | ASSERT(8, ({ union { int a; char b[6]; } x; sizeof(x); })); 10 | ASSERT(3, ({ union { int a; char b[4]; } x; x.a = 515; x.b[0]; })); 11 | ASSERT(2, ({ union { int a; char b[4]; } x; x.a = 515; x.b[1]; })); 12 | ASSERT(0, ({ union { int a; char b[4]; } x; x.a = 515; x.b[2]; })); 13 | ASSERT(0, ({ union { int a; char b[4]; } x; x.a = 515; x.b[3]; })); 14 | 15 | // [55] 支持结构体赋值 16 | ASSERT(3, ({ union {int a,b;} x,y; x.a=3; y.a=5; y=x; y.a; })); 17 | ASSERT(3, ({ union {struct {int a,b;} c;} x,y; x.c.b=3; y.c.b=5; y=x; y.c.b; })); 18 | 19 | printf("[220] 支持匿名结构体和联合体\n"); 20 | ASSERT(0xef, ({ union { struct { unsigned char a,b,c,d; }; long e; } x; x.e=0xdeadbeef; x.a; })); 21 | ASSERT(0xbe, ({ union { struct { unsigned char a,b,c,d; }; long e; } x; x.e=0xdeadbeef; x.b; })); 22 | ASSERT(0xad, ({ union { struct { unsigned char a,b,c,d; }; long e; } x; x.e=0xdeadbeef; x.c; })); 23 | ASSERT(0xde, ({ union { struct { unsigned char a,b,c,d; }; long e; } x; x.e=0xdeadbeef; x.d; })); 24 | 25 | ASSERT(3, ({struct { union { int a,b; }; union { int c,d; }; } x; x.a=3; x.b; })); 26 | ASSERT(5, ({struct { union { int a,b; }; union { int c,d; }; } x; x.d=5; x.c; })); 27 | 28 | ASSERT(1, ({ struct foo_1 in;in.f=1.0; in.x=2; test_1(in);})); 29 | ASSERT(2, ({ struct foo_1 in;in.f=1.0; in.x=2; test_2(in);})); 30 | 31 | printf("OK\n"); 32 | return 0; 33 | } 34 | -------------------------------------------------------------------------------- /test/usualconv.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | // [153] 支持为函数指针进行常规算术转换 4 | static int ret10(void) { return 10; } 5 | 6 | int main() { 7 | // [68] 实现常规算术转换 8 | ASSERT((long)-5, -10 + (long)5); 9 | ASSERT((long)-15, -10 - (long)5); 10 | ASSERT((long)-50, -10 * (long)5); 11 | ASSERT((long)-2, -10 / (long)5); 12 | 13 | ASSERT(1, -2 < (long)-1); 14 | ASSERT(1, -2 <= (long)-1); 15 | ASSERT(0, -2 > (long)-1); 16 | ASSERT(0, -2 >= (long)-1); 17 | 18 | ASSERT(1, (long)-2 < -1); 19 | ASSERT(1, (long)-2 <= -1); 20 | ASSERT(0, (long)-2 > -1); 21 | ASSERT(0, (long)-2 >= -1); 22 | 23 | ASSERT(0, 2147483647 + 2147483647 + 2); 24 | ASSERT((long)-1, ({ long x; x=-1; x; })); 25 | 26 | ASSERT(1, ({ char x[3]; x[0]=0; x[1]=1; x[2]=2; char *y=x+1; y[0]; })); 27 | ASSERT(0, ({ char x[3]; x[0]=0; x[1]=1; x[2]=2; char *y=x+1; y[-1]; })); 28 | ASSERT(5, ({ struct t {char a;} x, y; x.a=5; y=x; y.a; })); 29 | 30 | // [153] 支持为函数指针进行常规算术转换 31 | ASSERT(10, (1 ? ret10 : (void *)0)()); 32 | 33 | printf("OK\n"); 34 | return 0; 35 | } 36 | -------------------------------------------------------------------------------- /test/varargs.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | #include 3 | 4 | // [196] 支持 va_arg() 5 | int sum1(int x, ...) { 6 | va_list ap; 7 | va_start(ap, x); 8 | 9 | for (;;) { 10 | int y = va_arg(ap, int); 11 | if (y == 0) 12 | return x; 13 | x += y; 14 | } 15 | } 16 | 17 | int sum2(int x, ...) { 18 | va_list ap; 19 | va_start(ap, x); 20 | 21 | for (;;) { 22 | double y = va_arg(ap, double); 23 | x += y; 24 | 25 | int z = va_arg(ap, int); 26 | if (z == 0) 27 | return x; 28 | x += z; 29 | } 30 | } 31 | 32 | int sum2_2(int a, int x, ...) { 33 | va_list ap; 34 | va_start(ap, x); 35 | x += a; 36 | 37 | for (;;) { 38 | double y = va_arg(ap, double); 39 | x += y; 40 | 41 | int z = va_arg(ap, int); 42 | if (z == 0) 43 | return x; 44 | x += z; 45 | } 46 | return x; 47 | } 48 | 49 | int sum2_3(float b, int x, ...); 50 | 51 | int sum2_4(float b, int x, ...) { 52 | va_list ap; 53 | va_start(ap, x); 54 | x += b; 55 | 56 | for (;;) { 57 | double y = va_arg(ap, double); 58 | x += y; 59 | 60 | int z = va_arg(ap, int); 61 | if (z == 0) 62 | return x; 63 | x += z; 64 | } 65 | } 66 | 67 | int sum2_5(int a0, float fa0, int a1, int a2, int a3, int a4, float fa1, int a5, 68 | int a6, int x, ...); 69 | 70 | int sum2_6(int a0, float fa0, int a1, int a2, int a3, int a4, float fa1, int a5, 71 | int a6, int a7, int x, ...) { 72 | x += fa0; 73 | x += fa1; 74 | 75 | x += a0; 76 | x += a1; 77 | x += a2; 78 | x += a3; 79 | x += a4; 80 | x += a5; 81 | x += a6; 82 | x += a7; 83 | 84 | va_list ap; 85 | va_start(ap, x); 86 | 87 | for (;;) { 88 | int z = va_arg(ap, int); 89 | if (z == 0) 90 | return x; 91 | x += z; 92 | } 93 | } 94 | 95 | // [205] 支持va_copy() 96 | void fmt(char *buf, char *fmt, ...) { 97 | va_list ap; 98 | va_start(ap, fmt); 99 | 100 | va_list ap2; 101 | va_copy(ap2, ap); 102 | vsprintf(buf, fmt, ap2); 103 | va_end(buf); 104 | } 105 | 106 | int main() { 107 | // [196] 支持 va_arg() 108 | ASSERT(6, sum1(1, 2, 3, 0)); 109 | ASSERT(21, sum2(1, 2.0, 3, 4.0, 5, 6.0, 0)); 110 | 111 | printf("[204] 支持可变参数函数接受任意数量的参数\n"); 112 | ASSERT(55, sum1(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 0)); 113 | ASSERT(81, sum1(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 114 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 115 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 116 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0)); 117 | ASSERT(210, sum2(1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9, 10.0, 11, 12.0, 13, 14.0, 118 | 15, 16.0, 17, 18.0, 19, 20.0, 0)); 119 | ASSERT(211, sum2_2(1, 1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9, 10.0, 11, 12.0, 13, 120 | 14.0, 15, 16.0, 17, 18.0, 19, 20.0, 0)); 121 | ASSERT(211, sum2_3(1.0, 1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9, 10.0, 11, 12.0, 13, 122 | 14.0, 15, 16.0, 17, 18.0, 19, 20.0, 0)); 123 | ASSERT(211, sum2_4(1.0, 1, 2.0, 3, 4.0, 5, 6.0, 7, 8.0, 9, 10.0, 11, 12.0, 13, 124 | 14.0, 15, 16.0, 17, 18.0, 19, 20.0, 0)); 125 | ASSERT(302, sum2_5(11.0, 12, 13, 14.0, 15, 16.0, 17, 18.0, 19, 1, 1, 10, 11, 126 | 12, 13, 14, 15, 16, 17, 18, 19, 20, 0)); 127 | ASSERT(302, sum2_6(11.0, 12, 13, 14.0, 15, 16.0, 17, 18.0, 19, 1, 1, 10, 11, 128 | 12, 13, 14, 15, 16, 17, 18, 19, 20, 0)); 129 | 130 | printf("[205] 支持va_copy()\n"); 131 | ASSERT(0, ({ char buf[100]; fmt(buf, "%d %d", 2, 3); strcmp(buf, "2 3"); })); 132 | 133 | printf("OK\n"); 134 | return 0; 135 | } 136 | -------------------------------------------------------------------------------- /test/variable.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int g1, g2[4]; 4 | 5 | // [123] 支持静态全局变量 6 | static int g3 = 3; 7 | 8 | int main() { 9 | // [10] 支持单字母变量 10 | ASSERT(3, ({ int a; a=3; a; })); 11 | ASSERT(3, ({ int a=3; a; })); 12 | ASSERT(8, ({ int a=3; int z=5; a+z; })); 13 | 14 | // [11] 支持多字母变量 15 | ASSERT(3, ({ int a=3; a; })); 16 | ASSERT(8, ({ int a=3; int z=5; a+z; })); 17 | ASSERT(6, ({ int a; int b; a=b=3; a+b; })); 18 | ASSERT(3, ({ int foo=3; foo; })); 19 | ASSERT(8, ({ int foo123=3; int bar=5; foo123+bar; })); 20 | 21 | // [56] 将int的大小由8改为4 22 | ASSERT(4, ({ int x; sizeof(x); })); 23 | ASSERT(4, ({ int x; sizeof x; })); 24 | // [30] 支持 sizeof 25 | ASSERT(8, ({ int *x; sizeof(x); })); 26 | ASSERT(16, ({ int x[4]; sizeof(x); })); 27 | ASSERT(48, ({ int x[3][4]; sizeof(x); })); 28 | ASSERT(16, ({ int x[3][4]; sizeof(*x); })); 29 | ASSERT(4, ({ int x[3][4]; sizeof(**x); })); 30 | ASSERT(5, ({ int x[3][4]; sizeof(**x) + 1; })); 31 | ASSERT(5, ({ int x[3][4]; sizeof **x + 1; })); 32 | ASSERT(4, ({ int x[3][4]; sizeof(**x + 1); })); 33 | ASSERT(4, ({ int x=1; sizeof(x=2); })); 34 | ASSERT(1, ({ int x=1; sizeof(x=2); x; })); 35 | 36 | ASSERT(0, g1); 37 | ASSERT(3, ({ g1=3; g1; })); 38 | ASSERT(0, ({ g2[0]=0; g2[1]=1; g2[2]=2; g2[3]=3; g2[0]; })); 39 | ASSERT(1, ({ g2[0]=0; g2[1]=1; g2[2]=2; g2[3]=3; g2[1]; })); 40 | ASSERT(2, ({ g2[0]=0; g2[1]=1; g2[2]=2; g2[3]=3; g2[2]; })); 41 | ASSERT(3, ({ g2[0]=0; g2[1]=1; g2[2]=2; g2[3]=3; g2[3]; })); 42 | 43 | ASSERT(4, sizeof(g1)); 44 | ASSERT(16, sizeof(g2)); 45 | 46 | // [33] 支持char类型 47 | ASSERT(1, ({ char x=1; x; })); 48 | ASSERT(1, ({ char x=1; char y=2; x; })); 49 | ASSERT(2, ({ char x=1; char y=2; y; })); 50 | 51 | ASSERT(1, ({ char x; sizeof(x); })); 52 | ASSERT(10, ({ char x[10]; sizeof(x); })); 53 | 54 | // [44] 处理域 55 | ASSERT(2, ({ int x=2; { int x=3; } x; })); 56 | ASSERT(2, ({ int x=2; { int x=3; } int y=4; x; })); 57 | ASSERT(3, ({ int x=2; { x=3; } x; })); 58 | 59 | // [51] 对齐局部变量 60 | ASSERT(7, ({ int x; int y; char z; char *a=&y; char *b=&z; b-a; })); 61 | ASSERT(1, ({ int x; char y; int z; char *a=&y; char *b=&z; b-a; })); 62 | 63 | // [57] 支持long类型 64 | ASSERT(8, ({ long x; sizeof(x); })); 65 | 66 | // [58] 支持short类型 67 | ASSERT(2, ({ short x; sizeof(x); })); 68 | 69 | // [59] 支持嵌套类型声明符 70 | ASSERT(24, ({ char *x[3]; sizeof(x); })); 71 | ASSERT(8, ({ char (*x)[3]; sizeof(x); })); 72 | ASSERT(1, ({ char (x); sizeof(x); })); 73 | ASSERT(3, ({ char (x)[3]; sizeof(x); })); 74 | ASSERT(12, ({ char (x[3])[4]; sizeof(x); })); 75 | ASSERT(4, ({ char (x[3])[4]; sizeof(x[0]); })); 76 | ASSERT(3, ({ char *x[3]; char y; x[0]=&y; y=3; x[0][0]; })); 77 | ASSERT(4, ({ char x[3]; char (*y)[3]=x; y[0][0]=4; y[0][0]; })); 78 | 79 | // [61] 支持void类型 80 | { void *x; } 81 | 82 | // [123] 支持静态全局变量 83 | ASSERT(3, g3); 84 | 85 | printf("OK\n"); 86 | return 0; 87 | } 88 | -------------------------------------------------------------------------------- /test/vla.c: -------------------------------------------------------------------------------- 1 | #include "test.h" 2 | 3 | int main() { 4 | printf("[272] 支持对VLA进行sizeof\n"); 5 | ASSERT(20, ({ int n=5; int x[n]; sizeof(x); })); 6 | ASSERT((5+1)*(8*2)*4, ({ int m=5, n=8; int x[m+1][n*2]; sizeof(x); })); 7 | 8 | ASSERT(8, ({ char n=10; int (*x)[n][n+2]; sizeof(x); })); 9 | ASSERT(480, ({ char n=10; int (*x)[n][n+2]; sizeof(*x); })); 10 | ASSERT(48, ({ char n=10; int (*x)[n][n+2]; sizeof(**x); })); 11 | ASSERT(4, ({ char n=10; int (*x)[n][n+2]; sizeof(***x); })); 12 | 13 | ASSERT(60, ({ char n=3; int x[5][n]; sizeof(x); })); 14 | ASSERT(12, ({ char n=3; int x[5][n]; sizeof(*x); })); 15 | 16 | ASSERT(60, ({ char n=3; int x[n][5]; sizeof(x); })); 17 | ASSERT(20, ({ char n=3; int x[n][5]; sizeof(*x); })); 18 | 19 | printf("[273] 为VLA支持指针算术运算\n"); 20 | ASSERT(0, ({ int n=10; int x[n+1][n+6]; int *p=x; for (int i = 0; i 36 | static void verrorAt(char *Filename, char *Input, int LineNo, char *Loc, 37 | char *Fmt, va_list VA) { 38 | // 查找包含loc的行 39 | char *Line = Loc; 40 | // Line递减到当前行的最开始的位置 41 | // LineContents; P < Loc; P++) 72 | if (*P == '\n') 73 | LineNo++; 74 | 75 | va_list VA; 76 | va_start(VA, Fmt); 77 | verrorAt(CurrentFile->Name, CurrentFile->Contents, LineNo, Loc, Fmt, VA); 78 | exit(1); 79 | } 80 | 81 | // Tok解析出错 82 | void errorTok(Token *Tok, char *Fmt, ...) { 83 | va_list VA; 84 | va_start(VA, Fmt); 85 | verrorAt(Tok->File->Name, Tok->File->Contents, Tok->LineNo, Tok->Loc, Fmt, 86 | VA); 87 | exit(1); 88 | } 89 | 90 | // Tok解析警告 91 | void warnTok(Token *Tok, char *Fmt, ...) { 92 | va_list VA; 93 | va_start(VA, Fmt); 94 | verrorAt(Tok->File->Name, Tok->File->Contents, Tok->LineNo, Tok->Loc, Fmt, 95 | VA); 96 | va_end(VA); 97 | } 98 | 99 | // 判断Tok的值是否等于指定值,没有用char,是为了后续拓展 100 | bool equal(Token *Tok, char *Str) { 101 | // 比较字符串LHS(左部),RHS(右部)的前N位,S2的长度应大于等于N. 102 | // 比较按照字典序,LHSRHS返回正值 103 | // 同时确保,此处的Op位数=N 104 | return memcmp(Tok->Loc, Str, Tok->Len) == 0 && Str[Tok->Len] == '\0'; 105 | } 106 | 107 | // 跳过指定的Str 108 | Token *skip(Token *Tok, char *Str) { 109 | if (!equal(Tok, Str)) 110 | errorTok(Tok, "expect '%s'", Str); 111 | return Tok->Next; 112 | } 113 | 114 | // 消耗掉指定Token 115 | bool consume(Token **Rest, Token *Tok, char *Str) { 116 | // 存在 117 | if (equal(Tok, Str)) { 118 | *Rest = Tok->Next; 119 | return true; 120 | } 121 | // 不存在 122 | *Rest = Tok; 123 | return false; 124 | } 125 | 126 | // 生成新的Token 127 | static Token *newToken(TokenKind Kind, char *Start, char *End) { 128 | // 分配1个Token的内存空间 129 | Token *Tok = calloc(1, sizeof(Token)); 130 | Tok->Kind = Kind; 131 | Tok->Loc = Start; 132 | Tok->Len = End - Start; 133 | // 输入文件 134 | Tok->File = CurrentFile; 135 | Tok->Filename = CurrentFile->DisplayName; 136 | // 读取是否为行首,然后设置为false 137 | Tok->AtBOL = AtBOL; 138 | AtBOL = false; 139 | // 读取是否为前面是空格,然后设置为false 140 | Tok->HasSpace = HasSpace; 141 | HasSpace = false; 142 | return Tok; 143 | } 144 | 145 | // 判断Str是否以SubStr开头 146 | static bool startsWith(char *Str, char *SubStr) { 147 | // 比较LHS和RHS的N个字符是否相等 148 | return strncmp(Str, SubStr, strlen(SubStr)) == 0; 149 | } 150 | 151 | // 判断标记符的首字母规则 152 | // [a-zA-Z_] 153 | bool isIdent1(char C) { 154 | // a-z与A-Z在ASCII中不相连,所以需要分别判断 155 | return ('a' <= C && C <= 'z') || ('A' <= C && C <= 'Z') || C == '_'; 156 | } 157 | 158 | // 判断标记符的非首字母的规则 159 | // [a-zA-Z0-9_] 160 | bool isIdent2(char C) { return isIdent1(C) || ('0' <= C && C <= '9'); } 161 | 162 | // 读取标识符,并返回其长度 163 | static int readIdent(char *Start) { 164 | char *P = Start; 165 | uint32_t C = decodeUTF8(&P, P); 166 | // 如果不是标识符,返回0 167 | if (!isIdent1_1(C)) 168 | return 0; 169 | 170 | // 遍历标识符所有字符 171 | while (true) { 172 | char *Q; 173 | C = decodeUTF8(&Q, P); 174 | if (!isIdent2_1(C)) 175 | // 返回标识符长度 176 | return P - Start; 177 | P = Q; 178 | } 179 | } 180 | 181 | // 返回一位十六进制转十进制 182 | // hexDigit = [0-9a-fA-F] 183 | // 16: 0 1 2 3 4 5 6 7 8 9 A B C D E F 184 | // 10: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 185 | static int fromHex(char C) { 186 | if ('0' <= C && C <= '9') 187 | return C - '0'; 188 | if ('a' <= C && C <= 'f') 189 | return C - 'a' + 10; 190 | return C - 'A' + 10; 191 | } 192 | 193 | // 读取操作符 194 | static int readPunct(char *Ptr) { 195 | // 判断多字节的操作符 196 | static char *Kw[] = {"<<=", ">>=", "...", "==", "!=", "<=", ">=", "->", 197 | "+=", "-=", "*=", "/=", "++", "--", "%=", "&=", 198 | "|=", "^=", "&&", "||", "<<", ">>", "##", 199 | }; 200 | 201 | // 遍历列表匹配Ptr字符串 202 | for (int I = 0; I < sizeof(Kw) / sizeof(*Kw); ++I) { 203 | if (startsWith(Ptr, Kw[I])) 204 | return strlen(Kw[I]); 205 | } 206 | 207 | // 判断1字节的操作符 208 | return ispunct(*Ptr) ? 1 : 0; 209 | } 210 | 211 | // 判断是否为关键字 212 | static bool isKeyword(Token *Tok) { 213 | static HashMap Map; 214 | 215 | // 哈希表容量为0,说明还没初始化 216 | if (Map.Capacity == 0) { 217 | static char *Kw[] = { 218 | "return", "if", "else", 219 | "for", "while", "int", 220 | "sizeof", "char", "struct", 221 | "union", "long", "short", 222 | "void", "typedef", "_Bool", 223 | "enum", "static", "goto", 224 | "break", "continue", "switch", 225 | "case", "default", "extern", 226 | "_Alignof", "_Alignas", "do", 227 | "signed", "unsigned", "const", 228 | "volatile", "auto", "register", 229 | "restrict", "__restrict", "__restrict__", 230 | "_Noreturn", "float", "double", 231 | "typeof", "asm", "_Thread_local", 232 | "__thread", "_Atomic", "__attribute__", 233 | }; 234 | 235 | // 遍历关键字列表插入哈希表 236 | for (int I = 0; I < sizeof(Kw) / sizeof(*Kw); I++) 237 | hashmapPut(&Map, Kw[I], (void *)1); 238 | } 239 | 240 | return hashmapGet2(&Map, Tok->Loc, Tok->Len); 241 | } 242 | 243 | // 读取转义字符 244 | static int readEscapedChar(char **NewPos, char *P) { 245 | if ('0' <= *P && *P <= '7') { 246 | // 读取一个八进制数字,不能长于三位 247 | // \abc = (a*8+b)*8+c 248 | int C = *P++ - '0'; 249 | if ('0' <= *P && *P <= '7') { 250 | C = (C << 3) + (*P++ - '0'); 251 | if ('0' <= *P && *P <= '7') 252 | C = (C << 3) + (*P++ - '0'); 253 | } 254 | *NewPos = P; 255 | return C; 256 | } 257 | 258 | if (*P == 'x') { 259 | P++; 260 | // 判断是否为十六进制数字 261 | if (!isxdigit(*P)) 262 | errorAt(P, "invalid hex escape sequence"); 263 | 264 | int C = 0; 265 | // 读取一位或多位十六进制数字 266 | // \xWXYZ = ((W*16+X)*16+Y)*16+Z 267 | for (; isxdigit(*P); P++) 268 | C = (C << 4) + fromHex(*P); 269 | *NewPos = P; 270 | return C; 271 | } 272 | 273 | *NewPos = P + 1; 274 | 275 | switch (*P) { 276 | case 'a': // 响铃(警报) 277 | return '\a'; 278 | case 'b': // 退格 279 | return '\b'; 280 | case 't': // 水平制表符,tab 281 | return '\t'; 282 | case 'n': // 换行 283 | return '\n'; 284 | case 'v': // 垂直制表符 285 | return '\v'; 286 | case 'f': // 换页 287 | return '\f'; 288 | case 'r': // 回车 289 | return '\r'; 290 | // 属于GNU C拓展 291 | case 'e': // 转义符 292 | return 27; 293 | default: // 默认将原字符返回 294 | return *P; 295 | } 296 | } 297 | 298 | // 读取到字符串字面量结尾 299 | static char *stringLiteralEnd(char *P) { 300 | char *Start = P; 301 | for (; *P != '"'; P++) { 302 | if (*P == '\n' || *P == '\0') 303 | errorAt(Start, "unclosed string literal"); 304 | if (*P == '\\') 305 | P++; 306 | } 307 | return P; 308 | } 309 | 310 | // 读取字符串字面量:字符串开始的位置,左引号的位置 311 | static Token *readStringLiteral(char *Start, char *Quote) { 312 | // 读取到字符串字面量的右引号 313 | char *End = stringLiteralEnd(Quote + 1); 314 | // 定义一个与字符串字面量内字符数+1的Buf 315 | // 用来存储最大位数的字符串字面量 316 | char *Buf = calloc(1, End - Quote); 317 | // 实际的字符位数,一个转义字符为1位 318 | int Len = 0; 319 | 320 | // 将读取后的结果写入Buf 321 | for (char *P = Quote + 1; P < End;) { 322 | if (*P == '\\') { 323 | Buf[Len++] = readEscapedChar(&P, P + 1); 324 | } else { 325 | Buf[Len++] = *P++; 326 | } 327 | } 328 | 329 | // Token这里需要包含带双引号的字符串字面量 330 | Token *Tok = newToken(TK_STR, Start, End + 1); 331 | // 为\0增加一位 332 | Tok->Ty = arrayOf(TyChar, Len + 1); 333 | Tok->Str = Buf; 334 | return Tok; 335 | } 336 | 337 | // 解码UTF-8的字符串并将其转码为UTF-16 338 | // 339 | // UTF-16 使用2字节或4字节对字符进行编码。 340 | // 小于U+10000的码点,使用2字节。 341 | // 大于U+10000的码点,使用4字节(每2个字节被称为代理项,即前导代理和后尾代理)。 342 | static Token *readUTF16StringLiteral(char *Start, char *Quote) { 343 | char *End = stringLiteralEnd(Quote + 1); 344 | uint16_t *Buf = calloc(2, End - Start); 345 | int Len = 0; 346 | 347 | // 遍历引号内的字符 348 | for (char *P = Quote + 1; P < End;) { 349 | // 处理转义字符 350 | if (*P == '\\') { 351 | Buf[Len++] = readEscapedChar(&P, P + 1); 352 | continue; 353 | } 354 | 355 | // 解码UTF-8的字符串文字 356 | uint32_t C = decodeUTF8(&P, P); 357 | if (C < 0x10000) { 358 | // 用2字节存储码点 359 | Buf[Len++] = C; 360 | } else { 361 | // 用2字节存储码点 362 | C -= 0x10000; 363 | // 前导代理 364 | Buf[Len++] = 0xd800 + ((C >> 10) & 0x3ff); 365 | // 后尾代理 366 | Buf[Len++] = 0xdc00 + (C & 0x3ff); 367 | } 368 | } 369 | 370 | // 构建UTF-16编码的字符串终结符 371 | Token *Tok = newToken(TK_STR, Start, End + 1); 372 | Tok->Ty = arrayOf(TyUShort, Len + 1); 373 | Tok->Str = (char *)Buf; 374 | return Tok; 375 | } 376 | 377 | // 解码UTF-8的字符串并将其转码为UTF-32 378 | // 379 | // UTF-32是4字节编码 380 | static Token *readUTF32StringLiteral(char *Start, char *Quote, Type *Ty) { 381 | char *End = stringLiteralEnd(Quote + 1); 382 | uint32_t *Buf = calloc(4, End - Quote); 383 | int Len = 0; 384 | 385 | // 解码UTF-8的字符串文字 386 | for (char *P = Quote + 1; P < End;) { 387 | if (*P == '\\') 388 | // 处理转义字符 389 | Buf[Len++] = readEscapedChar(&P, P + 1); 390 | else 391 | // 解码UTF-8 392 | Buf[Len++] = decodeUTF8(&P, P); 393 | } 394 | 395 | // 构建UTF-32编码的字符串终结符 396 | Token *Tok = newToken(TK_STR, Start, End + 1); 397 | Tok->Ty = arrayOf(Ty, Len + 1); 398 | Tok->Str = (char *)Buf; 399 | return Tok; 400 | } 401 | 402 | // 读取字符字面量 403 | static Token *readCharLiteral(char *Start, char *Quote, Type *Ty) { 404 | char *P = Quote + 1; 405 | // 解析字符为 \0 的情况 406 | if (*P == '\0') 407 | errorAt(Start, "unclosed char literal"); 408 | 409 | // 解析字符 410 | int C; 411 | // 转义 412 | if (*P == '\\') 413 | C = readEscapedChar(&P, P + 1); 414 | else 415 | // 对于其他字符进行解码 416 | C = decodeUTF8(&P, P); 417 | 418 | // strchr返回以 ' 开头的字符串,若无则为NULL 419 | char *End = strchr(P, '\''); 420 | if (!End) 421 | errorAt(P, "unclosed char literal"); 422 | 423 | // 构造一个NUM的终结符,值为C的数值 424 | Token *Tok = newToken(TK_NUM, Start, End + 1); 425 | Tok->Val = C; 426 | Tok->Ty = Ty; 427 | return Tok; 428 | } 429 | 430 | // 转换预处理数值 431 | static bool convertPPInt(Token *Tok) { 432 | // 获取终结符对应的字符串 433 | char *P = Tok->Loc; 434 | 435 | // 读取二、八、十、十六进制 436 | // 默认为十进制 437 | int Base = 10; 438 | // 比较两个字符串前2个字符,忽略大小写,并判断是否为数字 439 | if (!strncasecmp(P, "0x", 2) && isxdigit(P[2])) { 440 | // 十六进制 441 | P += 2; 442 | Base = 16; 443 | } else if (!strncasecmp(P, "0b", 2) && (P[2] == '0' || P[2] == '1')) { 444 | // 二进制 445 | P += 2; 446 | Base = 2; 447 | } else if (*P == '0') { 448 | // 八进制 449 | Base = 8; 450 | } 451 | 452 | // 将字符串转换为Base进制的数字 453 | int64_t Val = strtoul(P, &P, Base); 454 | 455 | // 读取U L LL后缀 456 | bool L = false; 457 | bool U = false; 458 | 459 | // LLU 460 | if (startsWith(P, "LLU") || startsWith(P, "LLu") || startsWith(P, "llU") || 461 | startsWith(P, "llu") || startsWith(P, "ULL") || startsWith(P, "Ull") || 462 | startsWith(P, "uLL") || startsWith(P, "ull")) { 463 | P += 3; 464 | L = U = true; 465 | } else if (!strncasecmp(P, "lu", 2) || !strncasecmp(P, "ul", 2)) { 466 | // LU 467 | P += 2; 468 | L = U = true; 469 | } else if (startsWith(P, "LL") || startsWith(P, "ll")) { 470 | // LL 471 | P += 2; 472 | L = true; 473 | } else if (*P == 'L' || *P == 'l') { 474 | // L 475 | P++; 476 | L = true; 477 | } else if (*P == 'U' || *P == 'u') { 478 | // U 479 | P++; 480 | U = true; 481 | } 482 | 483 | // 不能作为整型进行解析 484 | if (P != Tok->Loc + Tok->Len) 485 | return false; 486 | 487 | // 推断出类型,采用能存下当前数值的类型 488 | Type *Ty; 489 | if (Base == 10) { 490 | if (L && U) 491 | Ty = TyULong; 492 | else if (L) 493 | Ty = TyLong; 494 | else if (U) 495 | Ty = (Val >> 32) ? TyULong : TyUInt; 496 | else 497 | Ty = (Val >> 31) ? TyLong : TyInt; 498 | } else { 499 | if (L && U) 500 | Ty = TyULong; 501 | else if (L) 502 | Ty = (Val >> 63) ? TyULong : TyLong; 503 | else if (U) 504 | Ty = (Val >> 32) ? TyULong : TyUInt; 505 | else if (Val >> 63) 506 | Ty = TyULong; 507 | else if (Val >> 32) 508 | Ty = TyLong; 509 | else if (Val >> 31) 510 | Ty = TyUInt; 511 | else 512 | Ty = TyInt; 513 | } 514 | 515 | // 构造NUM的终结符 516 | Tok->Kind = TK_NUM; 517 | Tok->Val = Val; 518 | Tok->Ty = Ty; 519 | return true; 520 | } 521 | 522 | // 预处理阶段的数字字面量比后面阶段的定义更宽泛 523 | // 因而先将数字字面量标记为pp-number,随后再转为常规数值终结符 524 | // 525 | // 转换预处理数值终结符为常规数值终结符 526 | static void convertPPNumber(Token *Tok) { 527 | // 尝试作为整型常量解析 528 | if (convertPPInt(Tok)) 529 | return; 530 | 531 | // 如果不是整型,那么一定是浮点数 532 | char *End; 533 | long double Val = strtod(Tok->Loc, &End); 534 | 535 | // 处理浮点数后缀 536 | Type *Ty; 537 | if (*End == 'f' || *End == 'F') { 538 | Ty = TyFloat; 539 | End++; 540 | } else if (*End == 'l' || *End == 'L') { 541 | Ty = TyLDouble; 542 | End++; 543 | } else { 544 | Ty = TyDouble; 545 | } 546 | 547 | // 构建浮点数终结符 548 | if (Tok->Loc + Tok->Len != End) 549 | errorTok(Tok, "invalid numeric constant"); 550 | 551 | Tok->Kind = TK_NUM; 552 | Tok->FVal = Val; 553 | Tok->Ty = Ty; 554 | } 555 | 556 | // 转换预处理终结符 557 | void convertPPTokens(Token *Tok) { 558 | for (Token *T = Tok; T->Kind != TK_EOF; T = T->Next) { 559 | if (isKeyword(T)) 560 | // 将关键字的终结符设为为TK_KEYWORD 561 | T->Kind = TK_KEYWORD; 562 | else if (T->Kind == TK_PP_NUM) 563 | // 转换预处理数值 564 | convertPPNumber(T); 565 | } 566 | } 567 | 568 | // 为所有Token添加行号 569 | static void addLineNumbers(Token *Tok) { 570 | // 读取当前文件的内容 571 | char *P = CurrentFile->Contents; 572 | int N = 1; 573 | 574 | do { 575 | if (P == Tok->Loc) { 576 | Tok->LineNo = N; 577 | Tok = Tok->Next; 578 | } 579 | if (*P == '\n') 580 | N++; 581 | } while (*P++); 582 | } 583 | 584 | // 词法解析字符串字面量 585 | Token *tokenizeStringLiteral(Token *Tok, Type *BaseTy) { 586 | Token *T; 587 | if (BaseTy->Size == 2) 588 | // UTF-16 589 | T = readUTF16StringLiteral(Tok->Loc, Tok->Loc); 590 | else 591 | // UTF-32 592 | T = readUTF32StringLiteral(Tok->Loc, Tok->Loc, BaseTy); 593 | T->Next = Tok->Next; 594 | return T; 595 | } 596 | 597 | // 终结符解析,文件名,文件内容 598 | Token *tokenize(File *FP) { 599 | // 设定当前文件 600 | CurrentFile = FP; 601 | 602 | // 读取相应的内容 603 | char *P = FP->Contents; 604 | 605 | Token Head = {}; 606 | Token *Cur = &Head; 607 | 608 | // 文件开始设置为行首 609 | AtBOL = true; 610 | // 文件开始设置为前面没有空格 611 | HasSpace = false; 612 | 613 | while (*P) { 614 | // 跳过行注释 615 | if (startsWith(P, "//")) { 616 | P += 2; 617 | while (*P != '\n') 618 | P++; 619 | HasSpace = true; 620 | continue; 621 | } 622 | 623 | // 跳过块注释 624 | if (startsWith(P, "/*")) { 625 | // 查找第一个"*/"的位置 626 | char *Q = strstr(P + 2, "*/"); 627 | if (!Q) 628 | errorAt(P, "unclosed block comment"); 629 | P = Q + 2; 630 | HasSpace = true; 631 | continue; 632 | } 633 | 634 | // 匹配换行符,设置为行首 635 | if (*P == '\n') { 636 | P++; 637 | AtBOL = true; 638 | HasSpace = true; 639 | continue; 640 | } 641 | 642 | // 跳过所有空白符如:空格、回车 643 | if (isspace(*P)) { 644 | ++P; 645 | HasSpace = true; 646 | continue; 647 | } 648 | 649 | // 解析整型和浮点数 650 | if (isdigit(*P) || (*P == '.' && isdigit(P[1]))) { 651 | char *Q = P++; 652 | while (true) { 653 | if (P[0] && P[1] && strchr("eEpP", P[0]) && strchr("+-", P[1])) 654 | P += 2; 655 | else if (isalnum(*P) || *P == '.') 656 | P++; 657 | else 658 | break; 659 | } 660 | Cur = Cur->Next = newToken(TK_PP_NUM, Q, P); 661 | continue; 662 | } 663 | 664 | // 解析字符串字面量 665 | if (*P == '"') { 666 | Cur->Next = readStringLiteral(P, P); 667 | Cur = Cur->Next; 668 | P += Cur->Len; 669 | continue; 670 | } 671 | 672 | // UTF-8字符串字面量 673 | if (startsWith(P, "u8\"")) { 674 | Cur = Cur->Next = readStringLiteral(P, P + 2); 675 | P += Cur->Len; 676 | continue; 677 | } 678 | 679 | // UTF-16字符串字面量 680 | if (startsWith(P, "u\"")) { 681 | Cur = Cur->Next = readUTF16StringLiteral(P, P + 1); 682 | P += Cur->Len; 683 | continue; 684 | } 685 | 686 | // 宽字符串字面量 687 | if (startsWith(P, "L\"")) { 688 | Cur = Cur->Next = readUTF32StringLiteral(P, P + 1, TyInt); 689 | P += Cur->Len; 690 | continue; 691 | } 692 | 693 | // UTF-32字符串字面量 694 | if (startsWith(P, "U\"")) { 695 | Cur = Cur->Next = readUTF32StringLiteral(P, P + 1, TyUInt); 696 | P += Cur->Len; 697 | continue; 698 | } 699 | 700 | // 解析字符字面量 701 | if (*P == '\'') { 702 | Cur->Next = readCharLiteral(P, P, TyInt); 703 | // 单字节字符 704 | Cur->Val = (char)Cur->Val; 705 | Cur = Cur->Next; 706 | P += Cur->Len; 707 | continue; 708 | } 709 | 710 | // UTF-16字符字面量 711 | if (startsWith(P, "u'")) { 712 | // 使用两个字节 713 | Cur = Cur->Next = readCharLiteral(P, P + 1, TyUShort); 714 | Cur->Val &= 0xffff; 715 | P += Cur->Len; 716 | continue; 717 | } 718 | 719 | // 宽字符字面量,占两个字节 720 | if (startsWith(P, "L'")) { 721 | Cur = Cur->Next = readCharLiteral(P, P + 1, TyInt); 722 | P += Cur->Len; 723 | continue; 724 | } 725 | 726 | // UTF-32 字符字面量 727 | if (startsWith(P, "U'")) { 728 | // 使用四个字节 729 | Cur = Cur->Next = readCharLiteral(P, P + 1, TyUInt); 730 | P += Cur->Len; 731 | continue; 732 | } 733 | 734 | // 解析标记符或关键字 735 | // [a-zA-Z_][a-zA-Z0-9_]* 736 | int IdentLen = readIdent(P); 737 | if (IdentLen) { 738 | Cur->Next = newToken(TK_IDENT, P, P + IdentLen); 739 | Cur = Cur->Next; 740 | P += Cur->Len; 741 | continue; 742 | } 743 | 744 | // 解析操作符 745 | int PunctLen = readPunct(P); 746 | if (PunctLen) { 747 | Cur->Next = newToken(TK_PUNCT, P, P + PunctLen); 748 | Cur = Cur->Next; 749 | // 指针前进Punct的长度位 750 | P += PunctLen; 751 | continue; 752 | } 753 | 754 | // 处理无法识别的字符 755 | errorAt(P, "invalid token"); 756 | } 757 | 758 | // 解析结束,增加一个EOF,表示终止符。 759 | Cur->Next = newToken(TK_EOF, P, P); 760 | // 为所有Token添加行号 761 | addLineNumbers(Head.Next); 762 | // Head无内容,所以直接返回Next 763 | return Head.Next; 764 | } 765 | 766 | // 返回指定文件的内容 767 | static char *readFile(char *Path) { 768 | FILE *FP; 769 | 770 | if (strcmp(Path, "-") == 0) { 771 | // 如果文件名是"-",那么就从输入中读取 772 | FP = stdin; 773 | } else { 774 | FP = fopen(Path, "r"); 775 | // 文件读取失败 776 | if (!FP) 777 | return NULL; 778 | } 779 | 780 | // 要返回的字符串 781 | char *Buf; 782 | size_t BufLen; 783 | FILE *Out = open_memstream(&Buf, &BufLen); 784 | 785 | // 读取整个文件 786 | while (true) { 787 | char Buf2[4096]; 788 | // fread从文件流中读取数据到数组中 789 | // 数组指针Buf2,数组元素大小1,数组元素个数4096,文件流指针 790 | int N = fread(Buf2, 1, sizeof(Buf2), FP); 791 | if (N == 0) 792 | break; 793 | // 数组指针Buf2,数组元素大小1,实际元素个数N,文件流指针 794 | fwrite(Buf2, 1, N, Out); 795 | } 796 | 797 | // 对文件完成了读取 798 | if (FP != stdin) 799 | fclose(FP); 800 | 801 | // 刷新流的输出缓冲区,确保内容都被输出到流中 802 | fflush(Out); 803 | // 确保最后一行以'\n'结尾 804 | if (BufLen == 0 || Buf[BufLen - 1] != '\n') 805 | // 将字符输出到流中 806 | fputc('\n', Out); 807 | fputc('\0', Out); 808 | fclose(Out); 809 | return Buf; 810 | } 811 | 812 | // 获取输入文件 813 | File **getInputFiles(void) { return InputFiles; } 814 | 815 | // 新建一个File 816 | File *newFile(char *Name, int FileNo, char *Contents) { 817 | File *FP = calloc(1, sizeof(File)); 818 | FP->Name = Name; 819 | FP->DisplayName = FP->Name; 820 | FP->FileNo = FileNo; 821 | FP->Contents = Contents; 822 | return FP; 823 | } 824 | 825 | // 替换 \r 或 \r\n 为 \n 826 | static void canonicalizeNewline(char *P) { 827 | int I = 0, J = 0; 828 | 829 | while (P[I]) { 830 | if (P[I] == '\r' && P[I + 1] == '\n') { 831 | // 替换\r\n 832 | I += 2; 833 | P[J++] = '\n'; 834 | } else if (P[I] == '\r') { 835 | // 替换\r 836 | I++; 837 | P[J++] = '\n'; 838 | } else { 839 | P[J++] = P[I++]; 840 | } 841 | } 842 | 843 | P[J] = '\0'; 844 | } 845 | 846 | // 移除续行,即反斜杠+换行符的形式 847 | static void removeBackslashNewline(char *P) { 848 | // 旧字符串的索引I(从0开始) 849 | // 新字符串的索引J(从0开始) 850 | // 因为J始终<=I,所以二者共用空间,不会有问题 851 | int I = 0, J = 0; 852 | 853 | // 为了维持行号不变,这里记录了删除的行数 854 | int N = 0; 855 | 856 | // 如果指向的字符存在 857 | while (P[I]) { 858 | // 如果是 '\\'和'\n' 859 | if (P[I] == '\\' && P[I + 1] == '\n') { 860 | // I跳过这两个字符 861 | I += 2; 862 | // 删除的行数+1 863 | N++; 864 | } 865 | // 如果是换行符 866 | else if (P[I] == '\n') { 867 | // P[J]='\n' 868 | // I、J都+1 869 | P[J++] = P[I++]; 870 | // 如果删除过N个续行,那么在这里增加N个换行 871 | // 以保证行号不变 872 | for (; N > 0; N--) 873 | P[J++] = '\n'; 874 | } 875 | // 其他情况,P[J]=P[I] 876 | // I、J都+1 877 | else { 878 | P[J++] = P[I++]; 879 | } 880 | } 881 | 882 | // 如果最后还删除过N个续行,那么在这里增加N个换行 883 | for (; N > 0; N--) 884 | P[J++] = '\n'; 885 | // 以'\0'结束 886 | P[J] = '\0'; 887 | } 888 | 889 | // 读取unicode字符 890 | static uint32_t readUniversalChar(char *P, int Len) { 891 | uint32_t C = 0; 892 | for (int I = 0; I < Len; I++) { 893 | if (!isxdigit(P[I])) 894 | return 0; 895 | // 左移(十六进制数的)4位,然后存入当前十六进制数 896 | C = (C << 4) | fromHex(P[I]); 897 | } 898 | return C; 899 | } 900 | 901 | // 替换\u或\U转义序列为相应的UTF-8编码 902 | static void convertUniversalChars(char *P) { 903 | char *Q = P; 904 | 905 | while (*P) { 906 | if (startsWith(P, "\\u")) { 907 | // 16位(4个十六进制数字)宽字符串字面量 908 | uint32_t C = readUniversalChar(P + 2, 4); 909 | if (C) { 910 | P += 6; 911 | Q += encodeUTF8(Q, C); 912 | } else { 913 | *Q++ = *P++; 914 | } 915 | } else if (startsWith(P, "\\U")) { 916 | // 32位(8个十六进制数字)宽字符串字面量 917 | uint32_t C = readUniversalChar(P + 2, 8); 918 | if (C) { 919 | P += 10; 920 | Q += encodeUTF8(Q, C); 921 | } else { 922 | *Q++ = *P++; 923 | } 924 | } else if (P[0] == '\\') { 925 | // 反斜杠 \ 的匹配 926 | *Q++ = *P++; 927 | *Q++ = *P++; 928 | } else { 929 | // 其他字符 930 | *Q++ = *P++; 931 | } 932 | } 933 | 934 | *Q = '\0'; 935 | } 936 | 937 | // 词法分析文件 938 | Token *tokenizeFile(char *Path) { 939 | // 读取文件内容 940 | char *P = readFile(Path); 941 | if (!P) 942 | return NULL; 943 | 944 | // 读取UTF-8的BOM标记 945 | if (!memcmp(P, "\xef\xbb\xbf", 3)) 946 | P += 3; 947 | 948 | // 规范化换行符 949 | canonicalizeNewline(P); 950 | // 移除续行 951 | removeBackslashNewline(P); 952 | // 转换unicode字符为UTF-8编码 953 | convertUniversalChars(P); 954 | 955 | // 文件编号 956 | static int FileNo; 957 | // 文件路径,文件编号从1开始,文件内容 958 | File *FP = newFile(Path, FileNo + 1, P); 959 | 960 | // 为汇编的.file指示保存文件名 961 | // 最后字符串为空,作为结尾。 962 | // realloc根据(FileNo + 2)重新分配给定的内存区域 963 | InputFiles = realloc(InputFiles, sizeof(char *) * (FileNo + 2)); 964 | // 当前文件存入字符串对应编号-1位置 965 | InputFiles[FileNo] = FP; 966 | // 最后字符串为空,作为结尾。 967 | InputFiles[FileNo + 1] = NULL; 968 | // 文件编号加1 969 | FileNo++; 970 | 971 | // 词法分析文件 972 | return tokenize(FP); 973 | } 974 | -------------------------------------------------------------------------------- /type.c: -------------------------------------------------------------------------------- 1 | #include "rvcc.h" 2 | 3 | // (Type){...}构造了一个复合字面量,相当于Type的匿名变量。 4 | Type *TyVoid = &(Type){TY_VOID, 1, 1}; 5 | Type *TyBool = &(Type){TY_BOOL, 1, 1}; 6 | 7 | Type *TyChar = &(Type){TY_CHAR, 1, 1}; 8 | Type *TyShort = &(Type){TY_SHORT, 2, 2}; 9 | Type *TyInt = &(Type){TY_INT, 4, 4}; 10 | Type *TyLong = &(Type){TY_LONG, 8, 8}; 11 | 12 | Type *TyUChar = &(Type){TY_CHAR, 1, 1, true}; 13 | Type *TyUShort = &(Type){TY_SHORT, 2, 2, true}; 14 | Type *TyUInt = &(Type){TY_INT, 4, 4, true}; 15 | Type *TyULong = &(Type){TY_LONG, 8, 8, true}; 16 | 17 | Type *TyFloat = &(Type){TY_FLOAT, 4, 4}; 18 | Type *TyDouble = &(Type){TY_DOUBLE, 8, 8}; 19 | Type *TyLDouble = &(Type){TY_LDOUBLE, 16, 16}; 20 | 21 | static Type *newType(TypeKind Kind, int Size, int Align) { 22 | Type *Ty = calloc(1, sizeof(Type)); 23 | Ty->Kind = Kind; 24 | Ty->Size = Size; 25 | Ty->Align = Align; 26 | return Ty; 27 | } 28 | 29 | // 判断Type是否为整数 30 | bool isInteger(Type *Ty) { 31 | TypeKind K = Ty->Kind; 32 | return K == TY_BOOL || K == TY_CHAR || K == TY_SHORT || K == TY_INT || 33 | K == TY_LONG || K == TY_ENUM; 34 | } 35 | 36 | // 判断Type是否为浮点数 37 | bool isFloNum(Type *Ty) { 38 | return Ty->Kind == TY_FLOAT || Ty->Kind == TY_DOUBLE || 39 | Ty->Kind == TY_LDOUBLE; 40 | } 41 | 42 | // 判断是否为float或double,而非long double 43 | bool isSFloNum(Type *Ty) { 44 | return Ty->Kind == TY_FLOAT || Ty->Kind == TY_DOUBLE; 45 | } 46 | 47 | // 判断是否为数字 48 | bool isNumeric(Type *Ty) { return isInteger(Ty) || isFloNum(Ty); } 49 | 50 | // 类型兼容检测函数 51 | bool isCompatible(Type *T1, Type *T2) { 52 | // 类型1、2完全相同,则直接返回true 53 | if (T1 == T2) 54 | return true; 55 | 56 | // 类型1存在原始类型,则检测该原始类型和类型2的兼容性 57 | if (T1->Origin) 58 | return isCompatible(T1->Origin, T2); 59 | 60 | // 类型2存在原始类型,则检测该原始类型和类型1的兼容性 61 | if (T2->Origin) 62 | return isCompatible(T1, T2->Origin); 63 | 64 | // 不存在原始类型时,二类型不相等则直接返回false 65 | if (T1->Kind != T2->Kind) 66 | return false; 67 | 68 | // 遍历类型1(此时,与类型2相同) 69 | switch (T1->Kind) { 70 | case TY_CHAR: 71 | case TY_SHORT: 72 | case TY_INT: 73 | case TY_LONG: 74 | // 二者 都为 或 都不为 无符号类型,则为真 75 | return T1->IsUnsigned == T2->IsUnsigned; 76 | case TY_FLOAT: 77 | case TY_DOUBLE: 78 | case TY_LDOUBLE: 79 | // 浮点类型直接返回真 80 | return true; 81 | case TY_PTR: 82 | // 指针,则比较二者所指向的基础类型 83 | return isCompatible(T1->Base, T2->Base); 84 | case TY_FUNC: { 85 | // 比较二者的返回类型,有异则为假 86 | if (!isCompatible(T1->ReturnTy, T2->ReturnTy)) 87 | return false; 88 | // 比较二者是否 都为 或 都不为 可变参数函数,有异则为假 89 | if (T1->IsVariadic != T2->IsVariadic) 90 | return false; 91 | 92 | Type *P1 = T1->Params; 93 | Type *P2 = T2->Params; 94 | // 遍历两个函数的参数,有异则为假 95 | for (; P1 && P2; P1 = P1->Next, P2 = P2->Next) 96 | if (!isCompatible(P1, P2)) 97 | return false; 98 | // 比较两个函数的参数个数,有异则为假,无异则为真 99 | return P1 == NULL && P2 == NULL; 100 | } 101 | case TY_ARRAY: 102 | // 比较数组的基础类型,有异则为假 103 | if (!isCompatible(T1->Base, T2->Base)) 104 | return false; 105 | // 比较数组的个数,有异则为假,无异则为真 106 | return T1->ArrayLen < 0 && T2->ArrayLen < 0 && T1->ArrayLen == T2->ArrayLen; 107 | default: 108 | return false; 109 | } 110 | } 111 | 112 | // 复制类型 113 | Type *copyType(Type *Ty) { 114 | Type *Ret = calloc(1, sizeof(Type)); 115 | *Ret = *Ty; 116 | // 记录原始类型 117 | Ret->Origin = Ty; 118 | return Ret; 119 | } 120 | 121 | // 指针类型,并且指向基类 122 | Type *pointerTo(Type *Base) { 123 | Type *Ty = newType(TY_PTR, 8, 8); 124 | Ty->Base = Base; 125 | // 将指针作为无符号类型进行比较 126 | Ty->IsUnsigned = true; 127 | return Ty; 128 | } 129 | 130 | // 函数类型,并赋返回类型 131 | Type *funcType(Type *ReturnTy) { 132 | // C语言标准不允许sizeof(),但GCC允许计算为1 133 | Type *Ty = newType(TY_FUNC, 1, 1); 134 | Ty->ReturnTy = ReturnTy; 135 | return Ty; 136 | } 137 | 138 | // 构造数组类型, 传入 数组基类, 元素个数 139 | Type *arrayOf(Type *Base, int Len) { 140 | Type *Ty = newType(TY_ARRAY, Base->Size * Len, Base->Align); 141 | Ty->Base = Base; 142 | Ty->ArrayLen = Len; 143 | return Ty; 144 | } 145 | 146 | // 构造可变长数组类型 147 | Type *VLAOf(Type *Base, Node *Len) { 148 | Type *Ty = newType(TY_VLA, 8, 8); 149 | Ty->Base = Base; 150 | Ty->VLALen = Len; 151 | return Ty; 152 | } 153 | 154 | // 构造枚举类型 155 | Type *enumType(void) { return newType(TY_ENUM, 4, 4); } 156 | 157 | // 构造结构体类型 158 | Type *structType(void) { return newType(TY_STRUCT, 0, 1); } 159 | 160 | // 获取容纳左右部的类型 161 | static Type *getCommonType(Type *Ty1, Type *Ty2) { 162 | if (Ty1->Base) 163 | return pointerTo(Ty1->Base); 164 | 165 | // 为函数指针进行常规算术转换 166 | if (Ty1->Kind == TY_FUNC) 167 | return pointerTo(Ty1); 168 | if (Ty2->Kind == TY_FUNC) 169 | return pointerTo(Ty2); 170 | 171 | // 处理浮点类型 172 | // 优先使用long double类型 173 | if (Ty1->Kind == TY_LDOUBLE || Ty2->Kind == TY_LDOUBLE) 174 | return TyLDouble; 175 | // 其次使用double类型 176 | if (Ty1->Kind == TY_DOUBLE || Ty2->Kind == TY_DOUBLE) 177 | return TyDouble; 178 | // 其次使用float类型 179 | if (Ty1->Kind == TY_FLOAT || Ty2->Kind == TY_FLOAT) 180 | return TyFloat; 181 | 182 | // 小于四字节则为int 183 | if (Ty1->Size < 4) 184 | Ty1 = TyInt; 185 | if (Ty2->Size < 4) 186 | Ty2 = TyInt; 187 | 188 | // 选择二者中更大的类型 189 | if (Ty1->Size != Ty2->Size) 190 | return (Ty1->Size < Ty2->Size) ? Ty2 : Ty1; 191 | 192 | // 优先返回无符号类型(更大) 193 | if (Ty2->IsUnsigned) 194 | return Ty2; 195 | return Ty1; 196 | } 197 | 198 | // 进行常规的算术转换 199 | static void usualArithConv(Node **LHS, Node **RHS) { 200 | Type *Ty = getCommonType((*LHS)->Ty, (*RHS)->Ty); 201 | // 将左右部转换到兼容的类型 202 | *LHS = newCast(*LHS, Ty); 203 | *RHS = newCast(*RHS, Ty); 204 | } 205 | 206 | // 为节点内的所有节点添加类型 207 | void addType(Node *Nd) { 208 | // 判断 节点是否为空 或者 节点类型已经有值,那么就直接返回 209 | if (!Nd || Nd->Ty) 210 | return; 211 | 212 | // 递归访问所有节点以增加类型 213 | addType(Nd->LHS); 214 | addType(Nd->RHS); 215 | addType(Nd->Cond); 216 | addType(Nd->Then); 217 | addType(Nd->Els); 218 | addType(Nd->Init); 219 | addType(Nd->Inc); 220 | 221 | // 访问链表内的所有节点以增加类型 222 | for (Node *N = Nd->Body; N; N = N->Next) 223 | addType(N); 224 | // 访问链表内的所有参数节点以增加类型 225 | for (Node *N = Nd->Args; N; N = N->Next) 226 | addType(N); 227 | 228 | switch (Nd->Kind) { 229 | // 将节点类型设为 int 230 | case ND_NUM: 231 | Nd->Ty = TyInt; 232 | return; 233 | // 将节点类型设为 节点左部的类型 234 | case ND_ADD: 235 | case ND_SUB: 236 | case ND_MUL: 237 | case ND_DIV: 238 | case ND_MOD: 239 | case ND_BITAND: 240 | case ND_BITOR: 241 | case ND_BITXOR: 242 | // 对左右部转换 243 | usualArithConv(&Nd->LHS, &Nd->RHS); 244 | Nd->Ty = Nd->LHS->Ty; 245 | return; 246 | case ND_NEG: { 247 | // 对左部转换 248 | Type *Ty = getCommonType(TyInt, Nd->LHS->Ty); 249 | Nd->LHS = newCast(Nd->LHS, Ty); 250 | Nd->Ty = Ty; 251 | return; 252 | } 253 | // 将节点类型设为 节点左部的类型 254 | // 左部不能是数组节点 255 | case ND_ASSIGN: 256 | if (Nd->LHS->Ty->Kind == TY_ARRAY) 257 | errorTok(Nd->LHS->Tok, "not an lvalue"); 258 | if (Nd->LHS->Ty->Kind != TY_STRUCT) 259 | // 对右部转换 260 | Nd->RHS = newCast(Nd->RHS, Nd->LHS->Ty); 261 | Nd->Ty = Nd->LHS->Ty; 262 | return; 263 | // 将节点类型设为 int 264 | case ND_EQ: 265 | case ND_NE: 266 | case ND_LT: 267 | case ND_LE: 268 | // 对左右部转换 269 | usualArithConv(&Nd->LHS, &Nd->RHS); 270 | Nd->Ty = TyInt; 271 | return; 272 | case ND_FUNCALL: 273 | Nd->Ty = Nd->FuncType->ReturnTy; 274 | return; 275 | // 将节点类型设为 int 276 | case ND_NOT: 277 | case ND_LOGOR: 278 | case ND_LOGAND: 279 | Nd->Ty = TyInt; 280 | return; 281 | // 将节点类型设为 左部的类型 282 | case ND_BITNOT: 283 | case ND_SHL: 284 | case ND_SHR: 285 | Nd->Ty = Nd->LHS->Ty; 286 | return; 287 | // 将节点类型设为 变量的类型 288 | case ND_VAR: 289 | case ND_VLA_PTR: 290 | Nd->Ty = Nd->Var->Ty; 291 | return; 292 | // 如果:左或右部为void则为void,否则为二者兼容的类型 293 | case ND_COND: 294 | if (Nd->Then->Ty->Kind == TY_VOID || Nd->Els->Ty->Kind == TY_VOID) { 295 | Nd->Ty = TyVoid; 296 | } else { 297 | usualArithConv(&Nd->Then, &Nd->Els); 298 | Nd->Ty = Nd->Then->Ty; 299 | } 300 | return; 301 | // 将节点类型设为 右部的类型 302 | case ND_COMMA: 303 | Nd->Ty = Nd->RHS->Ty; 304 | return; 305 | // 将节点类型设为 成员的类型 306 | case ND_MEMBER: 307 | Nd->Ty = Nd->Mem->Ty; 308 | return; 309 | // 将节点类型设为 指针,并指向左部的类型 310 | case ND_ADDR: { 311 | Type *Ty = Nd->LHS->Ty; 312 | // 左部如果是数组, 则为指向数组基类的指针 313 | if (Ty->Kind == TY_ARRAY) 314 | Nd->Ty = pointerTo(Ty->Base); 315 | else 316 | Nd->Ty = pointerTo(Ty); 317 | return; 318 | } 319 | // 节点类型:如果解引用指向的是指针,则为指针指向的类型;否则报错 320 | case ND_DEREF: 321 | // 如果不存在基类, 则无法解引用 322 | if (!Nd->LHS->Ty->Base) 323 | errorTok(Nd->Tok, "invalid pointer dereference"); 324 | if (Nd->LHS->Ty->Base->Kind == TY_VOID) 325 | errorTok(Nd->Tok, "dereferencing a void pointer"); 326 | 327 | Nd->Ty = Nd->LHS->Ty->Base; 328 | return; 329 | // 节点类型为 最后的表达式语句的类型 330 | case ND_STMT_EXPR: 331 | if (Nd->Body) { 332 | Node *Stmt = Nd->Body; 333 | while (Stmt->Next) 334 | Stmt = Stmt->Next; 335 | if (Stmt->Kind == ND_EXPR_STMT) { 336 | Nd->Ty = Stmt->LHS->Ty; 337 | return; 338 | } 339 | } 340 | errorTok(Nd->Tok, "statement expression returning void is not supported"); 341 | return; 342 | case ND_LABEL_VAL: 343 | Nd->Ty = pointerTo(TyVoid); 344 | return; 345 | // 节点类型为 布尔类型 346 | case ND_CAS: 347 | addType(Nd->CasAddr); 348 | addType(Nd->CasOld); 349 | addType(Nd->CasNew); 350 | Nd->Ty = TyBool; 351 | 352 | if (Nd->CasAddr->Ty->Kind != TY_PTR) 353 | errorTok(Nd->CasAddr->Tok, "pointer expected"); 354 | if (Nd->CasOld->Ty->Kind != TY_PTR) 355 | errorTok(Nd->CasOld->Tok, "pointer expected"); 356 | return; 357 | // 节点类型为 左部所指向的类型 358 | case ND_EXCH: 359 | if (Nd->LHS->Ty->Kind != TY_PTR) 360 | errorTok(Nd->CasAddr->Tok, "pointer expected"); 361 | Nd->Ty = Nd->LHS->Ty->Base; 362 | return; 363 | default: 364 | break; 365 | } 366 | } 367 | -------------------------------------------------------------------------------- /unicode.c: -------------------------------------------------------------------------------- 1 | #include "rvcc.h" 2 | 3 | // 将unicode字符编码为UTF8的格式 4 | int encodeUTF8(char *Buf, uint32_t C) { 5 | // 1字节UTF8编码,可用7位,0~127,与ASCII码兼容 6 | // 0x7F=0b01111111=127 7 | if (C <= 0x7F) { 8 | // 首字节内容为:0xxxxxxx 9 | Buf[0] = C; 10 | return 1; 11 | } 12 | 13 | // 2字节UTF8编码,可用11位,128~2047 14 | // 0x7FF=0b111 11111111=2047 15 | if (C <= 0x7FF) { 16 | // 首字节内容为:110xxxxx 17 | Buf[0] = 0b11000000 | (C >> 6); 18 | // 后续字节都为:10xxxxxx 19 | Buf[1] = 0b10000000 | (C & 0b00111111); 20 | return 2; 21 | } 22 | 23 | // 3字节UTF8编码,可用16位,2048~65535 24 | // 0xFFFF=0b11111111 11111111=65535 25 | if (C <= 0xFFFF) { 26 | // 首字节内容为:1110xxxx 27 | Buf[0] = 0b11100000 | (C >> 12); 28 | // 后续字节都为:10xxxxxx 29 | Buf[1] = 0b10000000 | ((C >> 6) & 0b00111111); 30 | Buf[2] = 0b10000000 | (C & 0b00111111); 31 | return 3; 32 | } 33 | 34 | // 4字节UTF8编码,可用21位,65536~1114111 35 | // 0x10FFFF=1114111 36 | // 37 | // 首字节内容为:11110xxx 38 | Buf[0] = 0b11110000 | (C >> 18); 39 | // 后续字节都为:10xxxxxx 40 | Buf[1] = 0b10000000 | ((C >> 12) & 0b00111111); 41 | Buf[2] = 0b10000000 | ((C >> 6) & 0b00111111); 42 | Buf[3] = 0b10000000 | (C & 0b00111111); 43 | return 4; 44 | } 45 | 46 | // 将UTF-8的格式解码为unicode字符 47 | uint32_t decodeUTF8(char **NewPos, char *P) { 48 | // 1字节UTF8编码,0~127,与ASCII码兼容 49 | if ((unsigned char)*P < 128) { 50 | *NewPos = P + 1; 51 | return *P; 52 | } 53 | 54 | char *Start = P; 55 | int Len; 56 | uint32_t C; 57 | 58 | if ((unsigned char)*P >= 0b11110000) { 59 | // 4字节UTF8编码,首字节内容为:11110xxx 60 | Len = 4; 61 | C = *P & 0b111; 62 | } else if ((unsigned char)*P >= 0b11100000) { 63 | // 3字节UTF8编码,首字节内容为:1110xxxx 64 | Len = 3; 65 | C = *P & 0b1111; 66 | } else if ((unsigned char)*P >= 0b11000000) { 67 | // 2字节UTF8编码,首字节内容为:110xxxxx 68 | Len = 2; 69 | C = *P & 0b11111; 70 | } else { 71 | errorAt(Start, "invalid UTF-8 sequence"); 72 | } 73 | 74 | // 后续字节都为:10xxxxxx 75 | for (int I = 1; I < Len; I++) { 76 | if ((unsigned char)P[I] >> 6 != 0b10) 77 | errorAt(Start, "invalid UTF-8 sequence"); 78 | C = (C << 6) | (P[I] & 0b111111); 79 | } 80 | 81 | // 前进Len字节 82 | *NewPos = P + Len; 83 | // 返回获取到的值 84 | return C; 85 | } 86 | 87 | // 判断字符C是否在Range内 88 | static bool inRange(uint32_t *Range, uint32_t C) { 89 | for (int I = 0; Range[I] != -1; I += 2) 90 | if (Range[I] <= C && C <= Range[I + 1]) 91 | return true; 92 | return false; 93 | } 94 | 95 | // C是否可以为 标识符的首字符 96 | bool isIdent1_1(uint32_t C) { 97 | // C11允许除ASCII字符外的一些字符用于标识符 98 | static uint32_t Range[] = { 99 | '_', '_', 'a', 'z', 'A', 'Z', '$', '$', 100 | 0x00A8, 0x00A8, 0x00AA, 0x00AA, 0x00AD, 0x00AD, 0x00AF, 0x00AF, 101 | 0x00B2, 0x00B5, 0x00B7, 0x00BA, 0x00BC, 0x00BE, 0x00C0, 0x00D6, 102 | 0x00D8, 0x00F6, 0x00F8, 0x00FF, 0x0100, 0x02FF, 0x0370, 0x167F, 103 | 0x1681, 0x180D, 0x180F, 0x1DBF, 0x1E00, 0x1FFF, 0x200B, 0x200D, 104 | 0x202A, 0x202E, 0x203F, 0x2040, 0x2054, 0x2054, 0x2060, 0x206F, 105 | 0x2070, 0x20CF, 0x2100, 0x218F, 0x2460, 0x24FF, 0x2776, 0x2793, 106 | 0x2C00, 0x2DFF, 0x2E80, 0x2FFF, 0x3004, 0x3007, 0x3021, 0x302F, 107 | 0x3031, 0x303F, 0x3040, 0xD7FF, 0xF900, 0xFD3D, 0xFD40, 0xFDCF, 108 | 0xFDF0, 0xFE1F, 0xFE30, 0xFE44, 0xFE47, 0xFFFD, 0x10000, 0x1FFFD, 109 | 0x20000, 0x2FFFD, 0x30000, 0x3FFFD, 0x40000, 0x4FFFD, 0x50000, 0x5FFFD, 110 | 0x60000, 0x6FFFD, 0x70000, 0x7FFFD, 0x80000, 0x8FFFD, 0x90000, 0x9FFFD, 111 | 0xA0000, 0xAFFFD, 0xB0000, 0xBFFFD, 0xC0000, 0xCFFFD, 0xD0000, 0xDFFFD, 112 | 0xE0000, 0xEFFFD, -1, 113 | }; 114 | 115 | return inRange(Range, C); 116 | } 117 | 118 | // C是否可以为 标识符的非首字符 119 | bool isIdent2_1(uint32_t C) { 120 | // 这里是用于非首位的字符 121 | static uint32_t Range[] = { 122 | '0', '9', '$', '$', 0x0300, 0x036F, 0x1DC0, 123 | 0x1DFF, 0x20D0, 0x20FF, 0xFE20, 0xFE2F, -1, 124 | }; 125 | 126 | return isIdent1_1(C) || inRange(Range, C); 127 | } 128 | 129 | // 返回在固定宽度字体中需要多少列来显示给定字符 130 | static int charWidth(uint32_t C) { 131 | // 此范围内的字符具有零个列宽 132 | static uint32_t Range1[] = { 133 | 0x0000, 0x001F, 0x007f, 0x00a0, 0x0300, 0x036F, 0x0483, 0x0486, 134 | 0x0488, 0x0489, 0x0591, 0x05BD, 0x05BF, 0x05BF, 0x05C1, 0x05C2, 135 | 0x05C4, 0x05C5, 0x05C7, 0x05C7, 0x0600, 0x0603, 0x0610, 0x0615, 136 | 0x064B, 0x065E, 0x0670, 0x0670, 0x06D6, 0x06E4, 0x06E7, 0x06E8, 137 | 0x06EA, 0x06ED, 0x070F, 0x070F, 0x0711, 0x0711, 0x0730, 0x074A, 138 | 0x07A6, 0x07B0, 0x07EB, 0x07F3, 0x0901, 0x0902, 0x093C, 0x093C, 139 | 0x0941, 0x0948, 0x094D, 0x094D, 0x0951, 0x0954, 0x0962, 0x0963, 140 | 0x0981, 0x0981, 0x09BC, 0x09BC, 0x09C1, 0x09C4, 0x09CD, 0x09CD, 141 | 0x09E2, 0x09E3, 0x0A01, 0x0A02, 0x0A3C, 0x0A3C, 0x0A41, 0x0A42, 142 | 0x0A47, 0x0A48, 0x0A4B, 0x0A4D, 0x0A70, 0x0A71, 0x0A81, 0x0A82, 143 | 0x0ABC, 0x0ABC, 0x0AC1, 0x0AC5, 0x0AC7, 0x0AC8, 0x0ACD, 0x0ACD, 144 | 0x0AE2, 0x0AE3, 0x0B01, 0x0B01, 0x0B3C, 0x0B3C, 0x0B3F, 0x0B3F, 145 | 0x0B41, 0x0B43, 0x0B4D, 0x0B4D, 0x0B56, 0x0B56, 0x0B82, 0x0B82, 146 | 0x0BC0, 0x0BC0, 0x0BCD, 0x0BCD, 0x0C3E, 0x0C40, 0x0C46, 0x0C48, 147 | 0x0C4A, 0x0C4D, 0x0C55, 0x0C56, 0x0CBC, 0x0CBC, 0x0CBF, 0x0CBF, 148 | 0x0CC6, 0x0CC6, 0x0CCC, 0x0CCD, 0x0CE2, 0x0CE3, 0x0D41, 0x0D43, 149 | 0x0D4D, 0x0D4D, 0x0DCA, 0x0DCA, 0x0DD2, 0x0DD4, 0x0DD6, 0x0DD6, 150 | 0x0E31, 0x0E31, 0x0E34, 0x0E3A, 0x0E47, 0x0E4E, 0x0EB1, 0x0EB1, 151 | 0x0EB4, 0x0EB9, 0x0EBB, 0x0EBC, 0x0EC8, 0x0ECD, 0x0F18, 0x0F19, 152 | 0x0F35, 0x0F35, 0x0F37, 0x0F37, 0x0F39, 0x0F39, 0x0F71, 0x0F7E, 153 | 0x0F80, 0x0F84, 0x0F86, 0x0F87, 0x0F90, 0x0F97, 0x0F99, 0x0FBC, 154 | 0x0FC6, 0x0FC6, 0x102D, 0x1030, 0x1032, 0x1032, 0x1036, 0x1037, 155 | 0x1039, 0x1039, 0x1058, 0x1059, 0x1160, 0x11FF, 0x135F, 0x135F, 156 | 0x1712, 0x1714, 0x1732, 0x1734, 0x1752, 0x1753, 0x1772, 0x1773, 157 | 0x17B4, 0x17B5, 0x17B7, 0x17BD, 0x17C6, 0x17C6, 0x17C9, 0x17D3, 158 | 0x17DD, 0x17DD, 0x180B, 0x180D, 0x18A9, 0x18A9, 0x1920, 0x1922, 159 | 0x1927, 0x1928, 0x1932, 0x1932, 0x1939, 0x193B, 0x1A17, 0x1A18, 160 | 0x1B00, 0x1B03, 0x1B34, 0x1B34, 0x1B36, 0x1B3A, 0x1B3C, 0x1B3C, 161 | 0x1B42, 0x1B42, 0x1B6B, 0x1B73, 0x1DC0, 0x1DCA, 0x1DFE, 0x1DFF, 162 | 0x200B, 0x200F, 0x202A, 0x202E, 0x2060, 0x2063, 0x206A, 0x206F, 163 | 0x20D0, 0x20EF, 0x302A, 0x302F, 0x3099, 0x309A, 0xA806, 0xA806, 164 | 0xA80B, 0xA80B, 0xA825, 0xA826, 0xFB1E, 0xFB1E, 0xFE00, 0xFE0F, 165 | 0xFE20, 0xFE23, 0xFEFF, 0xFEFF, 0xFFF9, 0xFFFB, 0x10A01, 0x10A03, 166 | 0x10A05, 0x10A06, 0x10A0C, 0x10A0F, 0x10A38, 0x10A3A, 0x10A3F, 0x10A3F, 167 | 0x1D167, 0x1D169, 0x1D173, 0x1D182, 0x1D185, 0x1D18B, 0x1D1AA, 0x1D1AD, 168 | 0x1D242, 0x1D244, 0xE0001, 0xE0001, 0xE0020, 0xE007F, 0xE0100, 0xE01EF, 169 | -1, 170 | }; 171 | 172 | // 若为零列宽字符则返回0 173 | if (inRange(Range1, C)) 174 | return 0; 175 | 176 | // 此范围内的字符具有两个列宽 177 | static uint32_t Range2[] = { 178 | 0x1100, 0x115F, 0x2329, 0x2329, 0x232A, 0x232A, 0x2E80, 0x303E, 179 | 0x3040, 0xA4CF, 0xAC00, 0xD7A3, 0xF900, 0xFAFF, 0xFE10, 0xFE19, 180 | 0xFE30, 0xFE6F, 0xFF00, 0xFF60, 0xFFE0, 0xFFE6, 0x1F000, 0x1F644, 181 | 0x20000, 0x2FFFD, 0x30000, 0x3FFFD, -1, 182 | }; 183 | 184 | // 若为二列宽字符则返回2 185 | if (inRange(Range2, C)) 186 | return 2; 187 | // 其他作为一列宽字符返回1 188 | return 1; 189 | } 190 | 191 | // 返回在固定宽度字体中需要多少列来显示给定字符串 192 | int displayWidth(char *P, int Len) { 193 | char *Start = P; 194 | // 字符串的总宽度 195 | int W = 0; 196 | // 遍历字符串内的所有字符 197 | while (P - Start < Len) { 198 | // 对字符进行解码 199 | uint32_t C = decodeUTF8(&P, P); 200 | // 累加上字符的宽度 201 | W += charWidth(C); 202 | } 203 | return W; 204 | } 205 | --------------------------------------------------------------------------------