mini-dog-c编译器开发 - 01 功能需求与设计

本篇为 mini-dog-c 编译器开发系列第一篇,介绍编译器的功能需求和总体设计。

1. 什么是编译器?

编译器是一种将高级语言 翻译成低级语言(如机器码或汇编)的程序。它的核心工作分为三个阶段:

  1. 词法分析 (Lexical Analysis):将源代码字符串分解成一个个 token

  2. 语法分析 (Syntax Analysis):将 token 流组织成树形结构 (AST)

  3. 语义分析与代码生成:遍历 AST,执行相应操作或生成目标代码

2. mini-dog-c 功能需求

2.1 支持的 Token 类型

Token 类型 说明 示例
IDENT 标识符 foo, my_var, test123
CHAR_LITERAL 字符字面量 'a', 'x'
BOOL_LITERAL 布尔字面量 true, false
INT_LITERAL 整数字面量 42, 0, 1024
DOUBLE_LITERAL 浮点字面量 3.14, 0.5
STRING_LITERAL 字符串字面量 "hello world"
ASSIGN 赋值 =
PLUS 加法 +
MINUS 减法 -
STAR 乘法 *
SLASH 除法 /
NOT 逻辑非 !
EQ 相等 ==
NE 不等 !=
LE 小于等于 <=
GE 大于等于 >=
LT 小于 <
GT 大于 >
COMMA 逗号 ,
SEMICOLON 分号 ;
COLON 冒号 :
LPAREN 左圆括号 (
RPAREN 右圆括号 )
LBRACE 左花括号 {
RBRACE 右花括号 }
LBRACKET 左方括号 [
RBRACKET 右方括号 ]
FN 关键词 fn
LET 关键词 let
IF 关键词 if
ELSE 关键词 else
RETURN 关键词 return
EOF 文件结束

2.2 语法规则 (BNF 表示)

复制代码
program       ::= statement*
statement     ::= let_decl | fn_decl | return_stmt | expr_stmt
let_decl      ::= "let" IDENT "=" expr ";"
fn_decl       ::= "fn" IDENT "(" params? ")" block
params        ::= IDENT ("," IDENT)*
block         ::= "{" statement* "}"
return_stmt   ::= "return" expr ";"
if_stmt       ::= "if" "(" expr ")" block ("else" block)?
expr_stmt     ::= expr ";"
expr          ::= assign_expr
assign_expr   ::= IDENT "=" assign_expr | logical_or_expr
logical_or_expr ::= logical_and_expr ("||" logical_and_expr)*
logical_and_expr ::= equality_expr ("&&" equality_expr)*
equality_expr ::= relational_expr (("==" | "!=") relational_expr)*
relational_expr ::= additive_expr (("<" | ">" | "<=" | ">=") additive_expr)*
additive_expr ::= multiplicative_expr (("+" | "-") multiplicative_expr)*
multiplicative_expr ::= unary_expr (("*" | "/") unary_expr)*
unary_expr    ::= ("!" | "-") unary_expr | primary
primary       ::= IDENT | literal | "(" expr ")"
literal       ::= INT_LITERAL | DOUBLE_LITERAL | CHAR_LITERAL | BOOL_LITERAL | STRING_LITERAL

2.3 示例程序

复制代码
fn add(a, b) {
    let result = a + b;
    return result;
}
​
fn main() {
    let x = 10;
    let y = 20;
    let sum = add(x, y);
    if (sum > 0) {
        println("sum is positive:", sum);
    } else {
        println("sum is not positive");
    }
}

2.4 内建函数

函数 说明 示例
print(...) 打印若干值(无换行) print("x =", x)
println(...) 打印若干值(末尾换行) println("Hello!")

3. 编译器架构设计

3.1 目录结构

复制代码
mini-dog-c/
├── include/
│   └── common.h           # 公共类型和宏定义
├── src/
│   ├── token.h / token.c  # Token 定义
│   ├── lexer.h / lexer.c  # 词法分析器
│   ├── ast.h / ast.c      # 抽象语法树
│   ├── parser.h / parser.c # 语法分析器
│   ├── evaluator.h / evaluator.c # 解释器
│   └── main.c             # 主程序
├── tests/
│   ├── test_lexer.c      # 词法分析器测试
│   ├── test_parser.c      # 语法分析器测试
│   └── test_evaluator.c  # 解释器测试
└── Makefile

3.2 各模块职责

模块 职责
token 定义 Token 类型和 Token 结构
lexer 将源代码字符串转换为 Token 流
ast 定义 AST 节点结构
parser 将 Token 流解析为 AST
evaluator 遍历 AST,执行解释执行

3.3 数据流

复制代码
源代码字符串
    ↓
Lexer: 逐字符扫描,识别 Token
    ↓
Token 流 (Token[])
    ↓
Parser: 递归下降解析,构建 AST
    ↓
AST (节点树)
    ↓
Evaluator: 深度优先遍历,执行操作
    ↓
输出结果

4. 设计决策

4.1 为什么选择解释器而非代码生成?

mini-dog-c 是一个教学用的编译器,目标是通过解释执行来展示编译器的工作原理。解释器更简单,无需处理目标平台的寄存器、内存布局等问题。

4.2 为什么选择递归下降解析?

递归下降解析器:

  • 简单直观,易于理解和实现

  • 对于 mini-dog-c 的简单语法足够用

  • 不需要复杂的外部工具(如 yacc/bison)

4.3 错误处理策略

  • 词法错误:跳过非法字符,继续扫描

  • 语法错误:记录错误位置,尝试继续解析

  • 运行时错误:在解释执行时检测

5. 开发计划

  1. 第一阶段:实现 Token 定义和词法分析器

  2. 第二阶段:实现 AST 节点定义

  3. 第三阶段:实现递归下降语法分析器

  4. 第四阶段:实现解释执行器

  5. 第五阶段:编写测试用例

6. 小结

本文档定义了 mini-dog-c 编译器的功能需求和总体架构。接下来我们将实现词法分析器。

相关推荐
shada5 小时前
mini-dog-c编译器开发 - 03 抽象语法树(AST)
编译器
众少成多积小致巨11 天前
Soong构建入门
android·go·编译器
杨艺韬19 天前
Rust编译器原理-第11章 闭包:匿名函数的编译器实现
rust·编译器
杨艺韬19 天前
Rust编译器原理-第15章 MIR 优化:编译器的中间表示与优化管线
rust·编译器
杨艺韬19 天前
Rust编译器原理-第6章 单态化:泛型的编译期展开
rust·编译器
杨艺韬19 天前
Rust编译器原理-第14章 宏系统:编译期的元编程引擎
rust·编译器
杨艺韬19 天前
Rust编译器原理-第16章 LLVM 代码生成:从 MIR 到机器码
rust·编译器
杨艺韬19 天前
Rust编译器原理-第5章 内存布局:编译器如何排列数据
rust·编译器
杨艺韬19 天前
Rust编译器原理-第3章 借用检查器:编译器如何证明内存安全
rust·编译器