Skip to content
This repository has been archived by the owner on Dec 1, 2023. It is now read-only.

nonlinearthink/microc-coursework

Repository files navigation

microc

项目说明

本次大作业我做的是完善 microc程序 的一些c语言语法,是基于 microc 程序,在此基础上自己添加一些内容完成的。

  • 改进了类型系统,纠正了char类型的不合理设计,新增了float类型
  • 改进了变量定义,增加了带初始值的变量定义。
  • 增加了条件表达式
  • 增加了自增和自减运算
  • 改进了循环语句,增加了两种新的循环:for和do while,对现有的所有循环支持了break和continue
  • 增加了switch case语句,支持break,但不支持default

构建与执行

A 解释器

A.1 解释器 interpc.exe 构建

# 编译解释器 interpc.exe 命令行程序 
dotnet restore  interpc.fsproj   # 可选
dotnet clean  interpc.fsproj     # 可选
dotnet build -v n interpc.fsproj # 构建./bin/Debug/net5.0/interpc.exe ,-v n查看详细生成过程

# 执行解释器
./bin/Debug/net5.0/interpc.exe ex1.c 8
dotnet run -p interpc.fsproj ex1.c 8
dotnet run -p interpc.fsproj -g ex1.c 8  //显示token AST 等调试信息

# one-liner 
# 自行修改 interpc.fsproj  依次解释多个源文件
dotnet build -t:ccrun interpc.fsproj

A.2 dotnet命令行fsi中运行解释器

# 生成扫描器
# macos or linux
dotnet "~/.nuget/packages/fslexyacc/10.2.0/build/fsyacc/netcoreapp3.1/fsyacc.dll" -o "CLex.fs" --module CLex --unicode CLex.fsl
# windows
dotnet "%homepath%\.nuget\packages\fslexyacc\10.2.0\build\/fslex/netcoreapp3.1\fslex.dll"  -o "CLex.fs" --module CLex --unicode CLex.fsl

# 生成分析器
# macos or linux
dotnet "~/.nuget/packages/fslexyacc/10.2.0/build/fsyacc/netcoreapp3.1/fsyacc.dll" -o "CPar.fs" --module CPar CPar.fsy
# windows
dotnet "%homepath%\.nuget\packages\fslexyacc\10.2.0\build\/fsyacc/netcoreapp3.1\fsyacc.dll"  -o "CPar.fs" --module CPar CPar.fsy

# 命令行运行程序
dotnet fsi 

#r "nuget: FsLexYacc";;  //添加包引用
#load "Absyn.fs" "Debug.fs" "CPar.fs" "CLex.fs" "Parse.fs" "Interp.fs" "ParseAndRun.fs" ;; 

open ParseAndRun;;    //导入模块 ParseAndRun
fromFile "example\ex1.c";;    //显示 ex1.c的语法树
run (fromFile "example\ex1.c") [17];; //解释执行 ex1.c
run (fromFile "example\ex11.c") [8];; //解释执行 ex11.c

Debug.debug <-  true  //打开调试

run (fromFile "example\ex1.c") [8];; //解释执行 ex1.c
run (fromFile "example\ex11.c") [8];; //解释执行 ex11.
#q;;

解释器的主入口 是 interp.fs 中的 run 函数,具体看代码的注释

B 编译器

B.1 microc编译器构建步骤

# 构建 microc.exe 编译器程序 
dotnet restore  microc.fsproj # 可选
dotnet clean  microc.fsproj   # 可选
dotnet build  microc.fsproj   # 构建 ./bin/Debug/net5.0/microc.exe

dotnet run -p microc.fsproj example/ex1.c    # 执行编译器,编译 ex1.c,并输出  ex1.out 文件
dotnet run -p microc.fsproj -g example/ex1.c   # -g 查看调试信息

./bin/Debug/net5.0/microc.exe -g example/ex1.c  # 直接执行构建的.exe文件,同上效果

dotnet built -t:ccrun microc.fsproj     # 编译并运行 example 目录下多个文件
dotnet built -t:cclean microc.fsproj    # 清除生成的文件

B.2 dotnet fsi 中运行编译器

# 启动fsi
dotnet fsi

#r "nuget: FsLexYacc";;

#load "Absyn.fs"  "CPar.fs" "CLex.fs" "Debug.fs" "Parse.fs" "Machine.fs" "Backend.fs" "Comp.fs" "ParseAndComp.fs";;   

# 运行编译器
open ParseAndComp;;
compileToFile (fromFile "example\ex1.c") "ex1";; 

Debug.debug <-  true   # 打开调试
compileToFile (fromFile "example\ex4.c") "ex4";; # 观察变量在环境上的分配
#q;;


# fsi 中运行
#time "on";;  // 打开时间跟踪

# 参考A. 中的命令 比较下解释执行解释执行 与 编译执行 ex11.c 的速度

C 优化编译器

C.1 优化编译器 microcc.exe 构建步骤

dotnet restore  microcc.fsproj
dotnet clean  microcc.fsproj
dotnet build  microcc.fsproj           # 构建编译器

dotnet run -p microcc.fsproj ex11.c    # 执行编译器
./bin/Debug/net5.0/microcc.exe ex11.c  # 直接执行

C.2 dotnet fsi 中运行 backwards编译器

dotnet fsi -r ./bin/Debug/net5.0/FsLexYacc.Runtime.dll Absyn.fs CPar.fs CLex.fs Parse.fs Machine.fs Contcomp.fs ParseAndContcomp.fs   

open ParseAndContcomp;;
contCompileToFile (fromFile "example\ex11.c") "ex11.out";;
#q;;

D 虚拟机构建与运行

  • 运行下面的命令 查看 fac 0 , fac 3 的栈帧
  • 理解栈式虚拟机执行流程

D.1 dotnet

dotnet clean  machine.csproj
dotnet run -p machine.csproj ex9.out 3 # 运行虚拟机,执行 ex9.out 

./bin/Debug/net5.0/machine.exe ex9.out 3
./bin/Debug/net5.0/machine.exe -t ex9.out 0  // 运行虚拟机,执行 ex9.out ,-t 查看跟踪信息
./bin/Debug/net5.0/machine.exe -t ex9.out 3  // 运行虚拟机,执行 ex9.out ,-t 查看跟踪信息

D.2 C

# 编译 c 虚拟机
gcc -o machine.exe machine.c

# 虚拟机执行指令
machine.exe ex9.out 3

# 调试执行指令
machine.exe -trace ex9.out 0  # -trace  并查看跟踪信息
machine.exe -trace ex9.out 3

D.3 Java

javac Machine.java
java Machine ex9.out 3

javac Machinetrace.java
java Machinetrace ex9.out 0
java Machinetrace ex9.out 3

E 编译到x86_64

预备软件

#Linux
$sudo apt-get install build-essential nasm gcc

# Windows
# nasm 汇编器
https://www.nasm.us/pub/nasm/releasebuilds/2.15.05/win64/
# gcc 编译器
https://github.com/jmeubank/tdm-gcc/releases/download/v9.2.0-tdm-1/tdm-gcc-9.2.0.exe

步骤

栈式虚拟机指令编译到x86_64,简单示例

分步构建

# 生成 ex1.asm 汇编码 nasm 格式
dotnet run -p microc.fsproj example/ex1.c
# 汇编生成目标文件
nasm -f win64 example/ex1.asm -o example/ex1.o   # win
# nasm -f elf64 ex1.asm -o ex1.o   # linux  
# 编译运行时文件
gcc -c driver.c
# 链接运行时,生成可执行程序
gcc -g -o example/ex1.exe driver.o example/ex1.o
# 执行
./example/ex1.exe 8 

单步构建

# 使用 build target 编译 ex1.c
# 可修改 microc.fsproj 编译其他案例文件

dotnet  build -t:ccrunx86 microc.fsproj

调用约定

  • caller
    • 调用函数前,在栈上放置函数参数,个数为m
    • 将rbp入栈,调用函数
  • callee
    • 保存返回地址r,老的栈帧指针bp
    • 将参数搬移到本函数的栈帧初始位置
    • 将rbp设置到第一个参数的位置
    • rbx 保存函数的返回值

数据在栈上的保存方式

  • 如数组 a[2] 的元素按次序排在栈上,末尾保存数组变量a,内容是首元素 e0的地址
  • e0, e1, a

访问数组,先通过BP得到a的位置,然后通过a 得到首地址 e0,最后计算数组下标偏移地址,访问对应数组元素

  • 全局变量在栈上依次保存,x86 汇编中,glovar 是全局变量的起始地址

x86 bugs

  • *(p + 2) 指针运算不支持

Releases

No releases published

Packages

No packages published