MiniC编译器实现——西北工业大学编译原理实验课

西北工业大学编译原理实验课

2023.06.28

要求与目标

实验目标:

  1. 理解并掌握词法分析、语法分析、语义分析、中间代码生成功能
  2. 理解并掌握非线性 IR:抽象语法树
  3. 理解并掌握线性 IR:三地址语句或四元式

实验要求:

  1. 识别程序是否符合MiniC的语法要求
  2. 输入MiniC的源文件
  3. 输出程序的中间IR表示
  4. 输出抽象语法树,通过Graphviz显示
  5. 输出控制流图,通过Graphviz显示

总体完成情况

在这里插入图片描述

minic

功能

  1. ✅选项-a可产生抽象语法树AST

    cmake-build-debug\minic.exe -a -o test.jpg test.c

  2. ✅选项-r可产生线性IR

    cmake-build-debug\minic.exe -i -o test.ir test.c

  3. ✅选项-c可产生控制流图

    cmake-build-debug\minic.exe -c main -o test_main_cfg.png test.c

功能示例

  1. 028_if_test1.c抽象语法树

语法树描述

  1. 028_if_test1.c 线性ir

    define i32 @ifElse() {
        declare i32 %l0 ; variable: return
        declare i32 %l1 ; variable: a
        declare i32 %t2
        declare i1 %t3
        declare i32 %t4
        declare i32 %t5
        declare i32 %t6
        declare i32 %t7
        entry
        %l1 = 5
        %t2 = %l1
        %t3 = cmp eq %t2, 5
        bc %t3, label .L3, label .L4
    .L3:
        %l1 = 25
        br label .L5
    .L4:
        %t4 = %l1
        %t5 = mul %t4, 2
        %l1 = %t5
        br label .L5
    .L5:
        %t6 = %l1
        %l0 = %t6
        %t7 = %l0
        exit %t7
    }
    define i32 @main() {
        declare i32 %l0 ; variable: return
        declare i32 %t1
        declare i32 %t2
        entry
        %t1 = call i32 @ifElse()
        %l0 = %t1
        %t2 = %l0
        exit %t2
    }
    
  2. 028_if_test1.c 控制流图

在这里插入图片描述

具体功能

词法分析

  1. 词法分析使用flex实现
  2. 识别MiniC文法的所有终结符(标识符、关键字、十进制、八进制、十六进制整数)
  3. C语言的注释识别支持
  4. 提供文法识别错误的行号定位信息

语法分析

  1. 语法分析使用bison实现
  2. 支持int和void类型,变量只允许int,函数返回值可以使用void和int
  3. 变量定义(含全局变量、局部变量)与使用
  4. 表达式语句、空语句支持
  5. if语句、while语句和赋值语句支持
  6. 语句块支持
  7. 表达式支持算术运算、关系运算、逻辑运算;满足C语言的优先级、结合性等要求
  8. 支持函数定义、声明与函数调用
  9. 支持一维数组和多维数组定义与使用
  10. 简单变量定义时初始化支持(语法支持,语义暂不支持)
  11. 支持for循环
  12. 支持自增与自减运算
  13. 语法分析错误检查与定位(暂只支持错误定位,不支持错误类型判断)

语义分析

  1. 采用语法制导翻译,生成抽象语法树
  2. 遍历抽象语法树产生中间IR
  3. 变量分层管理支持,支持变量的作用域,特别是变量的重名
  4. 变量或函数要先声明后使用,否则语义错误
  5. 逻辑运算支持短路求值
  6. 具备简单的语义错误检查定位和输出
  7. 中间IR表达采用实验定义IR

代码优化

  1. 基本块划分与控制流图生成
  2. 控制流图图形化显示(使用graphviz的API产生控制流图)
  3. 控制流的优化
    1. 删除不可达基本块
    2. 删除多余Label指令
  4. IR的优化
    1. 常量折叠(a = 2+3等价于a=5)
    2. 没有了

源代码构成

文件名作用
minic.l借助flex工具实现的词法分析器脚本源代码
minic_lex.cpp借助flex工具实现的词法分析器自动生成C语言源文件
minic_lex.h借助flex工具实现的词法分析器自动生成C语言头文件
minic.y借助bison工具实现的语法分析器脚本源代码
minic_yacc.cpp借助bison工具实现的语法分析器自动生成C语言源文件
minic_yacc.h借助bison工具实现的语法分析器自动生成C语言头文件
ast.cpp抽象语法树创建所需要的函数
ast.hast.cpp对应的头文件
parser.hflex和bison工具用到的节点属性定义
graph.cpp遍历抽象语法树利用graphviz生成图片
graph.hgraph.cpp对应的头文件
symbol.cpp符号表管理
symbol.hsymbol.cpp对应的头文件
genSymbol.cpp产生符号表并进行语义检查
genIR.cpp线性IR指令类的实现
IRInst.h线性IR指令类的头文件
IRCode.cpp线性IR管理类的实现
cfg.h,.cfg.cpp控制流图的头文件及其实现
Basic_block_division.cpp实现基本块划分
common.cpp,common.h一些通用函数的定义与实现
test.c测试用例
main.cpp计算器程序的主函数

各模块之间的关系

在这里插入图片描述

完整代码

GitHub:https://github.com/LC044/MiniC

  • 9
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
minic编译器的词法分析器主要用来将源代码文本转换为单词序列,每个单词代表程序中的一个符号。下面是一个简单的minic编译器词法分析器的示例: ```c #include <stdio.h> #include <ctype.h> #define MAX_TOKEN_LEN 100 typedef enum { T_EOF, T_PLUS, T_MINUS, T_MULTIPLY, T_DIVIDE, T_ASSIGN, T_SEMICOLON, T_LPAREN, T_RPAREN, T_IDENT, T_NUMBER } TokenType; typedef struct { TokenType type; char value[MAX_TOKEN_LEN + 1]; } Token; Token get_token() { Token token = {T_EOF, ""}; int i = 0; char c = getchar(); while (isspace(c)) { c = getchar(); } if (c == '+') { token.type = T_PLUS; } else if (c == '-') { token.type = T_MINUS; } else if (c == '*') { token.type = T_MULTIPLY; } else if (c == '/') { token.type = T_DIVIDE; } else if (c == '=') { token.type = T_ASSIGN; } else if (c == ';') { token.type = T_SEMICOLON; } else if (c == '(') { token.type = T_LPAREN; } else if (c == ')') { token.type = T_RPAREN; } else if (isalpha(c)) { token.type = T_IDENT; token.value[i++] = c; c = getchar(); while (isalnum(c) && i < MAX_TOKEN_LEN) { token.value[i++] = c; c = getchar(); } ungetc(c, stdin); } else if (isdigit(c)) { token.type = T_NUMBER; token.value[i++] = c; c = getchar(); while (isdigit(c) && i < MAX_TOKEN_LEN) { token.value[i++] = c; c = getchar(); } ungetc(c, stdin); } token.value[i] = '\0'; return token; } int main() { Token token; do { token = get_token(); printf("Token: type=%d, value=%s\n", token.type, token.value); } while (token.type != T_EOF); return 0; } ``` 该词法分析器根据minic编译器的语法规则,识别出了 +、-、*、/、=、;、(、)、标识符和数字这些单词,并将它们分别以相应的类型和值存储在Token结构体中。这些Token可以进一步被用于minic编译器的语法分析和代码生成等阶段。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值