16.2 TinyC 编译器
现在可以将 TinyC 前端和 TinyC 后端整合起来了。新建一个空的 tinyc 目录,然后 cd 到此目录,之后新建一个 sources 目录,然后将以下 7 个文件放到 sources 目录下:
然后在 tinyc 目录下新建一个脚本文件 build.sh ,内容如下:
- mkdir -p release
- flex sources/scanner.l
- bison -vdty sources/parser.y
- gcc -o release/tcc-frontend lex.yy.c y.tab.c
- rm -f y.* lex.*
- gcc -m32 -c -o tio.o sources/tio.c
- ar -crv release/libtio.a tio.o > /dev/null
- rm -f tio.o
- cp sources/macro.inc sources/pysim.py sources/tcc sources/pysimulate release/
- chmod u+x release/tcc release/pysimulate
- export PATH=$PATH:$PWD/release
- echo "export PATH=\$PATH:$PWD/release" >> ~/.bashrc
在终端输入 source build.sh 将编译生成 TinyC 前端 tcc-frontend 、库文件 libtio.a ,并放在 release 目录下,同时将 macro.inc, pysim.py, pysimulate, tcc 这四个文件拷贝至 release 目录,最后,将 release 目录输出到 PATH 环境变量中。现在,在终端输入 tcc filename.c 就可以利用 TinyC 编译成可执行程序了,而输入 pysimulate filename.asm -da 则可以用 Pcode 模拟器单步调试中间代码 Pcode 了。
让我们来测试一下第一章的示例代码 test.c 吧,将其放在当前目录,然后在终端输入 tcc test.c ,将生成一个 test-c-build 目录,此目录中包含了中间代码文件 test.asm 、函数定义宏文件 test.inc 、目标文件 test.o 、最终的可执行文件 test 。可以输入 test-c-build/test 来运行可执行文件,也可以输入 pysimulate test-c-build/test.asm -da 用 Pcode 模拟器单步调试中间代码。
脚本文件 tcc 首先调用 tcc-frontend 将输入文件(假设为 test.c )编译为 test.asm 和 test.inc ,然后调用 nasm ,将 test.asm 、 test.inc 和 macro.inc 三个文件一起汇编成 test.o ,最后调用 ld 将 test.o 和 libtio.a 一起链接为最终的可执行程序 test 。 tcc 的内容如下:
- #!/usr/bin/env bash
- if [ $# != 1 ];
- then
- echo "Usage: $0 <filename>"
- exit 1
- fi
- if ! [ -f $1 ];
- then
- echo "Error: File $1 does NOT exists."
- exit 1
- fi
- tccdir=$(dirname $0)
- filename=${1%.*}
- fileext=${1##*.}
- objdir=$filename-$fileext-build
- "$(dirname $0)/tcc-frontend" $1
- nasm -f elf32 -P"$tccdir/macro.inc" -P"$filename.inc" -o "$filename.o" "$filename.asm"
- ld -m elf_i386 -o "$filename" "$filename.o" -L"$tccdir" -ltio
- mkdir -p "$objdir"
- mv "$filename.asm" "$filename.inc" "$filename.o" "$filename" "$objdir/"
脚本文件 pysimulate 将调用 python 和 pysim.py 文件,模拟运行输入的 Pcode 文件,其内容如下:
- #!/usr/bin/env bash
- if [[ ($# != 1) && ($# != 2) ]];
- then
- echo "Usage: $0 <filename> [-da]"
- exit 1
- fi
- if ! [ -f $1 ];
- then
- echo "Error: File $1 does NOT exists."
- exit 1
- fi
- python "$(dirname $0)/pysim.py" $1 $2
下面来测试一下第 14 章最后的测试文件包 samples.zip ,将其解包至 samples 目录,再在当前目录新建一个脚本文件 testall.sh ,内容如下:
- for src in $(ls samples/*.c)
- do
- filename=${src%.*}
- fileext=${src##*.}
- filenakedname=${filename##*/}
- objdir=$filename-$fileext-build
- clear
- echo build \"$src\" and run
- echo
- tcc "$src"
- "$objdir/$filenakedname"
- echo
- echo press any key to continue...
- read -n 1
- done
最后在终端输入 bash testall.sh 将对所有文件进行编译、运行。
至此 TinyC 编译器全部完成。
第 16 章完