docs(wiki): 改建第 12 章为编译系统,统一 long 宽度口径并补齐章节编号
- 12-project.md 改建为 12-compilation-system.md:介绍编译系统总览、工程配置 project.vpj 与 viperbuild 元编程;同步 README 与第 17 章的引用 - README.MD:新增「C-LIKE 语法(逐步支持)」小节——自研语法器 includes/ast 将逐步 支持 C-LIKE 写法,双端写法与语义长期维护,但实际工程仍推荐 ABC-LIKE;流水线章节 去掉「Python 单文件模式 / project.json」旧措辞,改述工程根来源并补 --src 与 viperbuild - 02-type-system.md:long / unsigned long 位宽改为平台相关(Windows LLP64=32、 LP64=64)并补注权威实现;修正 stdint.LONGLONG / ULONGLONG 展开;统一整型 None 判空写法 - 05-classes.md:补 t.Anonymous 废弃告警;07-control-flow.md:for-else 改为已实现措辞 - 15/16/17/18 章重编号为 14/15/16/17,填补 14-oo-refactor 删除后的编号空洞, 同步各章标题与全仓引用
This commit is contained in:
1 parent
1ac88f3241
commit
947c1b35e5
12 files changed
+324
-331
No files matched your search
+31
-17
@@ -20,7 +20,7 @@ Viper 的类型系统通过 `t` 模块提供,所有类型注解继承 `t.CType
|
||||
| `int` | `t.CInt` | `i32` |
|
||||
| `uint` | `t.CUnsignedInt` | `i32` |
|
||||
| `short` / `ushort` | `t.CShort` / `t.CUnsignedShort` | `i16` |
|
||||
| `long` / `ulong` | `t.CLong` / `t.CUnsignedLong` | `i32`(Windows LLP64)或 `i64` |
|
||||
| `long` / `ulong` | `t.CLong` / `t.CUnsignedLong` | `i32`(Windows LLP64)/ `i64`(LP64) |
|
||||
| `longlong` / `ulonglong` | `t.CLongLong` / `t.CUnsignedLongLong` | `i64` |
|
||||
| `char` | `t.CChar` | `i8` |
|
||||
| `uchar` | `t.CUnsignedChar` | `i8` |
|
||||
@@ -107,13 +107,16 @@ s: []char = "hi" # 长度推导 ≡ t.CArray[char, None]
|
||||
| `t.CChar` | `char` | 8 | 是 |
|
||||
| `t.CShort` | `short` | 16 | 是 |
|
||||
| `t.CInt` | `int` | 32 | 是 |
|
||||
| `t.CLong` | `long` | 64 | 是 |
|
||||
| `t.CLong` | `long` | 32 / 64 | 是 |
|
||||
| `t.CUnsignedChar` | `unsigned char` | 8 | 否 |
|
||||
| `t.CUnsignedShort` | `unsigned short` | 16 | 否 |
|
||||
| `t.CUnsigned` / `t.CUnsignedInt` | `unsigned int` | 32 | 否 |
|
||||
| `t.CUnsignedLong` | `unsigned long` | 64 | 否 |
|
||||
| `t.CUnsignedLong` | `unsigned long` | 32 / 64 | 否 |
|
||||
| `t.CSignedChar` | `signed char` | 8 | 是 |
|
||||
|
||||
> **平台相关(`long` / `unsigned long`)**:宽度随目标平台——Windows(LLP64)下为 **32 位**(对齐 `ULONG`/`DWORD`),其余目标(LP64 / 裸机 ELF)为 **64 位**;`long long` / `unsigned long long` 恒为 64 位。
|
||||
> TPC 由 `configure_platform(triple)` 设置 `_LONG_SIZE` / `_UNSIGNED_LONG_SIZE`(`TransPyC/lib/includes/t.py`),TPV 由 `TypeGenResolve._long_llvm_ty` 按同一口径给出(Windows triple ⇒ `i32`,否则 `i64`)。
|
||||
|
||||
值得注意的是,t.CUnsigned 一般不单独使用,而是配合其它有符号类型,替换表示无符号,比如 `t.CUnsigned | t.CInt`,由于为了便于使用一些常用类型,则将其组合为常用的 `t.CUnsignedInt` 等。
|
||||
|
||||
### 固定宽度整数类型
|
||||
@@ -177,8 +180,8 @@ s: []char = "hi" # 长度推导 ≡ t.CArray[char, None]
|
||||
| `stdint.USHORT` | `t.CUnsignedShort` | - |
|
||||
| `stdint.LONG` | `t.CLong` | - |
|
||||
| `stdint.ULONG` | `t.CUnsignedLong` | - |
|
||||
| `stdint.LONGLONG` | `t.CLong \| t.CLong` | - |
|
||||
| `stdint.ULONGLONG` | `t.CUnsignedLong \| t.CLong` | - |
|
||||
| `stdint.LONGLONG` | `t.CLongLong` | - |
|
||||
| `stdint.ULONGLONG` | `t.CUnsignedLongLong` | - |
|
||||
| `stdint.FLOAT` | `t.CFloat` | - |
|
||||
| `stdint.DOUBLE` | `t.CDouble` | - |
|
||||
|
||||
@@ -357,26 +360,37 @@ if p is not None: ... # ✅ → icmp ne <ptr>, null
|
||||
if p == 0: ... # ❌ 不用:虽同样编译为 icmp eq <ptr>, null,但语义要绕"指针 vs 整型"特例分支
|
||||
```
|
||||
|
||||
**以整型承载地址/句柄的字段判空,相反**:必须与整型字面量比较(`!= 0` / `== 0`)。
|
||||
例:`llvmlite.LLVMType.Pointee` 是 `i64`(地址值),写 `x.Pointee is not None` **判不出空**——
|
||||
两侧编译器对"值类型 vs None"的处理是:TPC 直接折成常量(`is not None` → `i1 1`、`is None` → `i1 0`,
|
||||
`TransPyC/lib/core/Handles/HandlesExprOps.py:383-395`);TPV 把 `None` 物化为数值 0 后按整数比较
|
||||
(`TransPyV/App/lib/core/Gen/Expr/ExprGenOps.vp:684-713`)。⇒ 这类判空写 `!= 0` 才两侧同效。
|
||||
**以整型承载地址/句柄的字段判空**:整型上的 `None` **隐式表示 0**,两侧编译器都按此判定:
|
||||
|
||||
反例现场(守卫写出去了、但运行期没触发)与逐字 IR 证据:`Debugger/rawptr-migration-and-fastfail.md` §36。
|
||||
```python
|
||||
x is not None # ≡ x != 0 x != None # ≡ x != 0
|
||||
x is None # ≡ x == 0 x == None # ≡ x == 0
|
||||
```
|
||||
|
||||
即:这类判空既可写 `!= 0` / `== 0`,也可写 `is not None` / `is None`(以及 `!= None` / `== None`),**两侧同效**。
|
||||
|
||||
- **TPC**:`TransPyC/lib/core/Handles/HandlesExprOps.py:400-420` —— 一侧是 `IntType`、另一侧是空指针常量(`None`)时,
|
||||
把 `None` 侧换成该整型的常量 0 再发 `icmp eq`,`is not` / `!=` 取反。该分支刻意排在「指针 vs 整型」特例之前,
|
||||
否则 `i8` 会命中 `Gen._load(null)`(从空指针 load)。
|
||||
- **TPV**:`TransPyV/App/lib/core/Gen/Expr/ExprGenOps.vp:649-694` —— 同样把 `None` 侧物化为整数 0 后走 `icmp eq/ne`
|
||||
(`None is x` 与 `x is None` 两个方向、`is` 与 `==` 都覆盖)。
|
||||
|
||||
> 历史:早期 TPC 把「整型 vs None」直接折成常量(`is not None` → `i1 1`、`is None` → `i1 0`),
|
||||
> 于是「整型守卫」恒真/恒假、判不出空;而 TPV 已按 0 比较 ⇒ 两侧不一致。现已统一为「整数上的 None = 0」。
|
||||
> 修复前的现场与逐字 IR 证据见 `Debugger/rawptr-migration-and-fastfail.md` §36。
|
||||
|
||||
#### 双侧 IR 证据(判据写法 → 生成码)
|
||||
|
||||
| 写法 | 静态类型 | 生成 IR | 结论 |
|
||||
|---|---|---|---|
|
||||
| `p is None` / `p == 0` | 指针 | `icmp eq <ptr>, null` | 有效(命名 `is_cmp` / `cmpresult`) |
|
||||
| `x is not None` | **整型 i64** | **无 icmp**,折成常量 `i1 1` | **失效**(守卫恒真) |
|
||||
| `x is None` | **整型 i64** | **无 icmp**,折成常量 `i1 0` | **失效**(守卫恒假 → 死代码) |
|
||||
| `x != 0` / `x == 0` | 整型 i64 | `icmp ne/eq i64 %x, 0` | 有效(两侧同效) |
|
||||
| `x is not None` / `x != None` / `x != 0` | 整型 | `icmp ne <int> %x, 0` | 有效(两侧同效) |
|
||||
| `x is None` / `x == None` / `x == 0` | 整型 | `icmp eq <int> %x, 0` | 有效(两侧同效) |
|
||||
|
||||
逐字实证(`x = elem_ptr.Ty.Pointee`,`LLVMType*` 的 REnum 载荷槽,偏移 8、`load i64`):
|
||||
`TransPyV/output/818a0677d1e7fe22.ll:17979-17991` 中指针侧真的有 `icmp`,整型侧却只有
|
||||
`%"and.result.4" = phi i1 [0, %"endif.19"], [1, %"and.rhs0.4"]`(`and.rhs0.4` 块内 `load i64` 后直接 `br`)。
|
||||
逐字实证(**语义统一之前**的历史现场):`x = elem_ptr.Ty.Pointee`(`LLVMType*` 的 REnum 载荷槽,偏移 8、`load i64`)时,
|
||||
`TransPyV/output/818a0677d1e7fe22.ll:17979-17991` 中指针侧有 `icmp`,整型侧却只有
|
||||
`%"and.result.4" = phi i1 [0, %"endif.19"], [1, %"and.rhs0.4"]`(`and.rhs0.4` 块内 `load i64` 后直接 `br`)
|
||||
——那是 TPC 把「整型 vs None」折成常量的结果;现已统一为整数 0 比较,该现场不再出现。
|
||||
|
||||
#### 读"对象首字"(vptr)的唯一可用写法
|
||||
|
||||
|
||||
+17
-1
@@ -85,6 +85,22 @@ class Config:
|
||||
obj_ptr: MyClass* = &MyClass(arg1, arg2)
|
||||
```
|
||||
|
||||
### 匿名结构体成员(❌)
|
||||
|
||||
> WARNING: **警告:** `t.Anonymous` 已废弃。由于 Viper 在声明结构体,枚举等处不需要关键字,因此 `t.Anonymouse` 是不需要使用的。此关键字不再维护,强行使用可能导致未定义行为。
|
||||
|
||||
继承 `t.Anonymous` 的类作为匿名成员嵌入:
|
||||
|
||||
```python
|
||||
class Header(t.Anonymous):
|
||||
magic: uint32
|
||||
version: uint32
|
||||
|
||||
class Packet:
|
||||
Header # 匿名嵌入,可直接访问 Packet.magic
|
||||
length: uint32
|
||||
```
|
||||
|
||||
### 字节序标记
|
||||
|
||||
> 待实现(尚无字节序处理代码)。
|
||||
@@ -265,7 +281,7 @@ novirtual class GNode(GSListNode[GNode]): # 递归泛型继承
|
||||
# 此时 GNode.Next: GNode* —— 强类型,零转型
|
||||
```
|
||||
|
||||
这是 C(`void*` + cast)、C++(模板继承但无 `novirtual` 精细控制)、Rust(无继承,需 trait bound)**当然都可以表达,但是无法这样简洁**的能力。
|
||||
这是 C(`void*` + cast)、C++(模板继承但无 `novirtual` 精细控制)、Rust(无继承,需 trait bound)均无法如此简洁表达的能力。
|
||||
|
||||
### 实例化
|
||||
|
||||
|
||||
@@ -209,7 +209,7 @@ novirtual class GNode(LinkedNode): # 非多态继承
|
||||
|
||||
子类调用父类方法时,实际机制为**调用点解析**:编译器沿 MRO(方法解析顺序)定位到**定义该方法**的父类,按字节偏移调整 `this` 指针后 `bitcast`,在调用点**直接调用**父类实现(无 wrapper 生成、无尾调用)。
|
||||
|
||||
> 这里的 MRO 为「深度优先 + 声明顺序 + 去重」(含自身),**不是** Python 的 C3 线性化;详见 [15-multiple-inheritance.md](15-multiple-inheritance.md)。
|
||||
> 这里的 MRO 为「深度优先 + 声明顺序 + 去重」(含自身),**不是** Python 的 C3 线性化;详见 [14-multiple-inheritance.md](14-multiple-inheritance.md)。
|
||||
|
||||
### 跨模块继承
|
||||
|
||||
|
||||
+3
-2
@@ -143,7 +143,7 @@ for item in container:
|
||||
|
||||
### for-else
|
||||
|
||||
> 期望实现——当前编译器不生成 orelse 代码,else 块会被忽略
|
||||
`for` 支持 `else` 子句,与 `while-else` 一样是语言的一部分:
|
||||
|
||||
```python
|
||||
for i in range(count):
|
||||
@@ -153,6 +153,8 @@ else:
|
||||
serial.puts("not found\n")
|
||||
```
|
||||
|
||||
`else` 块在循环**正常结束**(迭代耗尽,非 `break` 退出)时执行;`break` 会跳过 else。
|
||||
|
||||
### break 和 continue
|
||||
|
||||
```python
|
||||
@@ -240,7 +242,6 @@ match value:
|
||||
|
||||
## assert 语句
|
||||
> 避免使用此语句,此语句未经充分测试,在多数情况下,编译器不知道如何展示结果。
|
||||
> 需要断言时**推荐使用 `testcheck` 库的断言**(`import testcheck`,核心断言为 `testcheck.check(cond, ok_msg, fail_msg)`,另有 `begin`/`section`/`ok`/`fail`/`info`/`end`/`summary`)。
|
||||
> 期望实现——当前语句分派无 assert 分支
|
||||
|
||||
```python
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
> 本章待修订(机制与实现存在偏差,见各节标注)
|
||||
>
|
||||
> 说明:本章讲的是**语言层 `try/except`**(错误码 + 错误消息出参)。运行期崩溃 / 按键时打印的**调用栈回溯**是另一套机制,见 [17-traceback.md](17-traceback.md)。
|
||||
> 说明:本章讲的是**语言层 `try/except`**(错误码 + 错误消息出参)。运行期崩溃 / 按键时打印的**调用栈回溯**是另一套机制,见 [16-traceback.md](16-traceback.md)。
|
||||
|
||||
Viper 支持 Python 风格的 `try/except/finally` 异常处理,采用基于错误码 + 错误消息出参的传播机制(不使用 C++ 风格的零开销异常)。
|
||||
|
||||
|
||||
@@ -0,0 +1,252 @@
|
||||
# 12 - 编译系统
|
||||
|
||||
本章介绍 Viper 的编译系统:从源码到可执行产物的流水线、工程配置 `project.vpj`,以及**用 Viper 自己写构建配置**的元编程内建库 `viperbuild`。
|
||||
|
||||
## 编译系统总览
|
||||
|
||||
Viper 目前有两条编译路径,二者共享同一套语言语义:
|
||||
|
||||
| 编译器 | 实现语言 | 定位 |
|
||||
|--------|----------|------|
|
||||
| **TPC**(TransPyC) | Python | 种子编译器:纯 Python 实现,用于自举起点与快速试验 |
|
||||
| **TPV**(TransPyV) | Viper | 自举产物:由 TPC 编译出的 Viper 原生编译器,日常构建走它 |
|
||||
|
||||
两阶段编译模型:
|
||||
|
||||
- **Phase 1(声明阶段)**:从入口出发按 `import` 递归建依赖图 → 1a 注册 struct/enum/union → 1b-pre 生成 `.vpi` 签名存根 → 1b 全量翻译生成 `.stub.ll`(声明)。
|
||||
- **Phase 2(翻译与链接)**
|
||||
- **Phase A-pre-vpi / Phase A-pre**:加载依赖 `.vpi`,预翻译准备
|
||||
- **Phase A**:主循环多遍收敛翻译,`.stub.ll` / `.text.ll` 在此写盘
|
||||
- **Phase B**:`llc` 并行编译 `.ll` → `.obj`
|
||||
- **Phase B+**:缺失 includes 按需编译
|
||||
- **Phase C**:链接(链接器由工程配置的 `linker.cmd` 决定)
|
||||
|
||||
### SHA1 命名空间与增量编译
|
||||
|
||||
- 每个源文件按内容算 SHA1(取前 16 个十六进制字符);`temp` 下按 `{temp}/{sha1[0:2]}/` 切片存放 `<SHA1>.vpi` / `.stub.ll` / `.text.ll` / `.deps.txt`。
|
||||
- **命名空间**:未 `export` 的函数与结构体带 SHA1 前缀,消除跨模块符号冲突。
|
||||
- **增量**:SHA1 不变则缓存命中直接复用;内容变化才重生成。映射表在内存 `Sha1Store` / `StubMergerStore` 中多遍收敛构建,`temp/_sha1_map.txt` 仅供人读。
|
||||
- 旧产物清理:`--clear-cache`(只清 temp)/ `--rebuild-includes`(只清 includes 预编译缓存)。
|
||||
|
||||
## 工程配置 `project.vpj`
|
||||
|
||||
工程使用 `project.vpj`(JSON)管理编译与链接参数。
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Kernel",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./Kernel",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": ["-filetype=obj", "-mtriple=x86_64-none-elf", "-relocation-model=static", "-O2"]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "ld.lld.exe",
|
||||
"flags": ["-m", "elf_x86_64", "-T", "linker.ld", "--oformat", "elf64-x86-64", "--strip-all"],
|
||||
"static_libs": [],
|
||||
"dynamic_libs": [],
|
||||
"output": "kernel.bin"
|
||||
},
|
||||
"includes": ["../../includes"],
|
||||
"target": {
|
||||
"triple": "x86_64-none-elf",
|
||||
"datalayout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 配置项说明
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `name` / `version` | string | 项目名 / 版本 |
|
||||
| `source_dir` | string | 源代码目录(相对 `project.vpj` 所在目录) |
|
||||
| `build_dir` | string | 构建目录(默认 `./.tpv_build`);`temp` / `output` 均由它派生 |
|
||||
| `compiler.cmd` / `compiler.flags` | string / string[] | 编译器命令(通常 `llc`)与标志 |
|
||||
| `linker.cmd` / `linker.flags` | string / string[] | 链接器命令与标志 |
|
||||
| `linker.static_libs` | string[] | 静态库 / 目标文件(`.a` / `.obj`) |
|
||||
| `linker.dynamic_libs` | string[] | 动态库(`.dll` / `.so`) |
|
||||
| `linker.output` | string | 输出文件名 |
|
||||
| `includes` | string[] | 模块搜索路径列表(多目录按序查找) |
|
||||
| `target.triple` | string | LLVM 目标三元组 |
|
||||
| `target.datalayout` | string | LLVM 数据布局字符串 |
|
||||
| `options.slice_level` | int | 切片优化级别(见下表) |
|
||||
| `options.sha1_slice_level` | int | SHA1 切片存储级别(默认 1;≥1 时产物按 `{temp}/{sha1[0:2]}/` 存放) |
|
||||
| `options.target` | string | 编译目标(目前仅 `llvm`) |
|
||||
| `options.strict_mode` | bool | 严格模式 |
|
||||
|
||||
**无统一默认 triple**:由各工程自行指定(TransPyV 自身为 `x86_64-pc-windows-gnu`;ViperOS 内核为 `x86_64-none-elf`)。`target.datalayout` 与 `target.triple` 会写入 `.ll` 模块头(`target triple` / `target datalayout`)。
|
||||
|
||||
常用 `llc` 标志:`-filetype=obj`(出目标文件)、`-mtriple=...`、`-relocation-model=pic|static`、`-O0..3`。
|
||||
|
||||
常用 `ld.lld` 标志:`-m elf_x86_64`、`-T linker.ld`、`--oformat elf64-x86-64|binary`(内核用 binary)、`--strip-all`。
|
||||
|
||||
### 切片优化级别
|
||||
|
||||
| 级别 | 名称 | 说明 |
|
||||
|------|------|------|
|
||||
| `0` | `no_optimize` | 无优化 |
|
||||
| `1` | `conservative` | 保守优化 |
|
||||
| `2` | `moderate` | 适度优化 |
|
||||
| `3` | `aggressive` | 激进优化(默认) |
|
||||
| `s` | `size` | 体积优化 |
|
||||
|
||||
### 项目结构与产物布局
|
||||
|
||||
```
|
||||
HelloWorld/
|
||||
├── project.vpj # 项目配置
|
||||
├── main.vp # 入口
|
||||
└── .tpv_build/ # 构建目录(build_dir,自动生成)
|
||||
├── temp/ # 临时文件
|
||||
│ └── <sha1[0:2]>/ # SHA1 切片子目录(sha1_slice_level ≥ 1)
|
||||
│ ├── <SHA1>.vpi # 签名存根
|
||||
│ ├── <SHA1>.stub.ll # LLVM IR 声明
|
||||
│ ├── <SHA1>.text.ll # 含代码的 .ll
|
||||
│ └── <SHA1>.deps.txt # 依赖信息
|
||||
└── output/ # 输出文件
|
||||
└── helloworld.exe
|
||||
```
|
||||
|
||||
内核类工程另含 `linker.ld` 链接脚本(`ENTRY` + `.text/.rodata/.data/.bss` 段控),由工程自行维护。
|
||||
|
||||
## 编译命令
|
||||
|
||||
### TPC(Python 种子编译器)
|
||||
|
||||
```bash
|
||||
python TransPyC.py -f InputFile -o OutputFile [options]
|
||||
```
|
||||
|
||||
| 参数 | 说明 |
|
||||
|------|------|
|
||||
| `-f` | 输入文件路径 |
|
||||
| `-o` | 输出文件路径 |
|
||||
| `-wh` | 头文件列表 |
|
||||
| `-debug` | 调试输出文件 |
|
||||
| `-cc` / `-cflags` | 编译命令 / 编译标志 |
|
||||
| `-run` / `-args` | 编译后运行 / 运行参数 |
|
||||
| `-h` | 辅助文件(C 或 Python) |
|
||||
|
||||
### TPV(自举产物)
|
||||
|
||||
```bash
|
||||
# 工程模式:按 project.vpj 构建
|
||||
TransPyV.exe --project project.vpj [--clean] [--run]
|
||||
|
||||
# viperbuild 模式:入口文件自带构建配置(无需 project.vpj)
|
||||
TransPyV.exe --src App/main.vp [--run]
|
||||
```
|
||||
|
||||
常用开关(完整清单见 [TransPyV/README.md](../TransPyV/README.md)):
|
||||
|
||||
| 开关 | 说明 |
|
||||
|------|------|
|
||||
| `--project <path>` | `project.vpj` 路径(不给则在当前目录、上级目录查找) |
|
||||
| `--src <path>` | 入口文件;构建配置由依赖闭包内的 `viperbuild` 提供(与 `--project` 互斥) |
|
||||
| `--clean` | 清理 temp / output / includes 预编译缓存 |
|
||||
| `--rebuild-includes` | 只删 includes 预编译缓存,强制重编 includes |
|
||||
| `--clear-cache` | 只清 temp 缓存(`.vpi` / `.stub.ll` / `.text.ll`) |
|
||||
| `--phase 1\|2\|all` | 1 = 只做 stub 分离;2 = 只做 IR 组合 + 编译;all = 全部(默认) |
|
||||
| `--run` | 编译成功后立即运行产物 |
|
||||
| `--asan` | ASan 模式(`opt -passes=asan` 插桩;运行库须由 `linker.static_libs` 声明,否则 fail-fast) |
|
||||
| `--traceback` | 生成栈回溯支持(DWARF 元数据 + `<exe>.stackmap`),见 [16-traceback.md](16-traceback.md) |
|
||||
| `--detection` / `--detection-deep` | MemBuddy 分配检测(`0xCDCD` 标记 + 探针) |
|
||||
| `--no-llvmpeephole` | 关闭 FunctionPrint 的本地窥孔(T2 store/load 转发、T3 空 bitcast) |
|
||||
| `--repl` | 启动交互式 REPL,见 [15-repl.md](15-repl.md) |
|
||||
| `--nowarn-register` | 抑制 Phase A 依赖类 WARN |
|
||||
| `--version` / `--help` | 版本 / 帮助 |
|
||||
|
||||
## viperbuild —— 用 Viper 写构建配置(元编程)
|
||||
|
||||
`viperbuild` 是**编译器内建的编译期宏库**(与 `t` / `c` / `ctraits` 同级),它让构建配置直接写在 Viper 源码里,免去额外维护 `project.vpj` 的负担。它**不产生任何运行时代码**。
|
||||
|
||||
### 定位与边界
|
||||
|
||||
| 扩展名 | 是什么 | 编译器 | Vipeye(LSP) |
|
||||
|--------|--------|--------|---------------|
|
||||
| `.vp` | 可执行 Viper 源码 | 编译 | 推导 |
|
||||
| `.vpi` | 模块签名存根(编译器自产自销) | 读取(跨模块类型主通道) | 推导 |
|
||||
| `.vpnc` | **不可执行的 `.vp`** | **完全无视** | 推导 |
|
||||
| `.vpnci` | **不可执行的 `.vpi`** | **完全无视** | 推导 |
|
||||
|
||||
`.vpnc` / `.vpnci` 是「Vipeye(基于 pyright 的 VSCode Viper LSP)专用、编译器零感知」的松散 Viper DSL,**不是**为 `viperbuild` 专设。
|
||||
|
||||
`viperbuild` 本身也**不是** `.vpnc`:它没有磁盘模块与 `.vpi`,是编译器直接拦截的内建名(`_check_import_sha1` 对 `viperbuild` 豁免)。仓库里的 [includes/viperbuild.vpnci](../includes/viperbuild.vpnci) 只是给 Vipeye 看的存根。
|
||||
|
||||
### 使用方法
|
||||
|
||||
配置写在**入口文件依赖闭包内**的任一 `.vp` 模块里(不必在入口文件本身):
|
||||
|
||||
```python
|
||||
import viperbuild as vb
|
||||
|
||||
COMMON_FLAGS = ["-O0", "-g"]
|
||||
|
||||
proj = vb.Project("TransPyV", "1.0.0") # 也支持 Project(name=..., version=...)
|
||||
proj.source = "./App" # 缺省 = 入口文件所在目录
|
||||
proj.buildroot = "./.tpv_build" # 缺省 = source + "/.tpv_build"
|
||||
proj.includes = ["../includes"] # 缺省 = 从 exe 目录向上 0..3 层探测 includes
|
||||
proj.compiler = ["llc", "-filetype=obj", "-relocation-model=pic", *COMMON_FLAGS]
|
||||
proj.linker = ["clang++", "-fuse-ld=lld", "-lmsvcrt", "-lucrt", "-g"]
|
||||
proj.static_libs = [".../libclang_rt.asan_dynamic-x86_64.dll.a"]
|
||||
proj.dynamic_libs = []
|
||||
proj.output = "TransPyV.exe" # 缺省 = 入口文件名 + ".exe"
|
||||
|
||||
proj.build(triple="x86_64-pc-windows-gnu",
|
||||
datalayout="e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128")
|
||||
```
|
||||
|
||||
也可以批量赋值:
|
||||
|
||||
```python
|
||||
proj.config(source="./App", buildroot="./.tpv_build", includes=["../includes"], ...)
|
||||
```
|
||||
|
||||
`build()` 的目标平台三种写法(**互斥**):
|
||||
|
||||
- `build(triple=..., datalayout=...)`:显式指定,**必须成对给出**;
|
||||
- `build(selfmachine=True)`:运行时探测本机架构(当前支持 AMD64 →
|
||||
`x86_64-pc-windows-gnu` + 对应 datalayout);
|
||||
- `build()`:什么都不给,等价 `selfmachine=True`。
|
||||
|
||||
`selfmachine=True` 与显式 `triple`/`datalayout` **同时给 ⇒ fatal**。
|
||||
|
||||
### 支持的常量表达式
|
||||
|
||||
字段右值只接受常量表达式:
|
||||
|
||||
- 字符串字面量;同文件先定义的字符串常量 / `define` 常量(引用);
|
||||
- 字符串 `+` 拼接;
|
||||
- `list[str]` 字面量,支持 `*名字` 展开(引用同文件的列表常量);
|
||||
- 列表之间 `+` 拼接。
|
||||
|
||||
### 约束与 fail-fast
|
||||
|
||||
- 一个依赖闭包内**只允许一个** Project 对象,出现第二个即 fatal。
|
||||
- Project 是**宏类型**:只允许「字段赋值 / `config()` / `build()`」,**禁止读取**(当右值用即 fatal)。
|
||||
- `source` 缺省为入口文件所在目录;显式指定时,**入口文件必须位于其下**,否则 fatal。
|
||||
- 没找到 `import viperbuild`、配置损坏(类型不符 / 未知字段 / 用了未定义常量)、`build()` 缺失或重复调用、`--project` 与 `--src` 同时给 —— 一律 fatal,**不静默兜底**。
|
||||
|
||||
### `--src` 的语义
|
||||
|
||||
`--src <入口文件>` 时:
|
||||
|
||||
1. **Pass 0**:从入口文件出发 BFS 展开**依赖闭包**(搜索根 = 入口目录 + 当前目录;stdlib 模块跳过),识别 `import viperbuild` 并提取配置,写回编译器内部配置;
|
||||
2. 随后按**工程模式**构建:扫描 `source_dir` 下的 `.vp` 一起编译链接(**没有**「只编一个文件」的独立单文件模式)。
|
||||
|
||||
翻译期 `viperbuild` 的宏语句(`proj = vb.Project(...)` / `proj.<字段> = ...` / `proj.config()` / `proj.build()`)会由翻译器**整体擦除**,不生成任何 IR;`import viperbuild` 本身也只记账不产码。
|
||||
|
||||
> Pass 0 的实现位于 [TransPyV/App/lib/core/builtin/ViperBuild.vp](../TransPyV/App/lib/core/builtin/ViperBuild.vp)。
|
||||
|
||||
## 平台说明
|
||||
|
||||
当前工具链与运行时验证以 **Windows** 为主(`llc` + mingw `clang++`),原因是计划与精力有限,并非语言 / 编译器设计上的限制;实际大量代码可跨平台复用,后续按需扩展。
|
||||
-296
@@ -1,296 +0,0 @@
|
||||
# 12 - 项目配置与构建
|
||||
|
||||
Viper 项目使用 `project.vpj` 配置文件管理编译和链接参数(Python 单文件模式仍接受 `project.json`)。
|
||||
|
||||
## project.vpj 结构
|
||||
|
||||
```json
|
||||
{
|
||||
"name": "Kernel",
|
||||
"version": "1.0.0",
|
||||
"source_dir": "./Kernel",
|
||||
"build_dir": "./.tpv_build",
|
||||
"compiler": {
|
||||
"cmd": "llc",
|
||||
"flags": ["-filetype=obj", "-mtriple=x86_64-none-elf", "-relocation-model=static", "-O2"]
|
||||
},
|
||||
"linker": {
|
||||
"cmd": "ld.lld.exe",
|
||||
"flags": [
|
||||
"-m", "elf_x86_64",
|
||||
"-T", "linker.ld",
|
||||
"--oformat", "elf64-x86-64",
|
||||
"--strip-all"
|
||||
],
|
||||
"output": "kernel.bin"
|
||||
},
|
||||
"includes": ["../../includes"],
|
||||
"target": {
|
||||
"triple": "x86_64-none-elf",
|
||||
"datalayout": "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
|
||||
},
|
||||
"options": {
|
||||
"slice_level": 3,
|
||||
"sha1_slice_level": 1,
|
||||
"target": "llvm",
|
||||
"strict_mode": true
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 配置项说明
|
||||
|
||||
### 基本信息字段
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `name` | string | 项目名称 |
|
||||
| `version` | string | 项目版本 |
|
||||
| `source_dir` | string | 源代码目录(相对于 project.vpj 所在目录) |
|
||||
| `build_dir` | string | 构建目录(默认 `./.tpv_build`);`temp`/`output` 均由它派生 |
|
||||
|
||||
### 编译器配置
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `compiler.cmd` | string | 编译器命令(通常为 `llc`) |
|
||||
| `compiler.flags` | string[] | 编译器标志 |
|
||||
|
||||
常用 `llc` 标志:
|
||||
- `-filetype=obj`:输出目标文件
|
||||
- `-mtriple=x86_64-none-elf`:目标三元组
|
||||
- `-relocation-model=static`:静态重定位
|
||||
- `-O2`:优化级别
|
||||
|
||||
### 链接器配置
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `linker.cmd` | string | 链接器命令(通常为 `ld.lld.exe`;TransPyV 宿主工程为 `clang++`) |
|
||||
| `linker.flags` | string[] | 链接器标志 |
|
||||
| `linker.static_libs` | string[] | 静态库/目标文件列表(`.a`/`.obj`) |
|
||||
| `linker.dynamic_libs` | string[] | 动态库列表(`.dll`/`.so`) |
|
||||
| `linker.output` | string | 输出文件名 |
|
||||
|
||||
支持 DSO(动态共享对象)构建:开启后产物为 `*_dso.ll`。
|
||||
|
||||
常用 `ld.lld` 标志:
|
||||
- `-m elf_x86_64`:ELF x86_64 格式
|
||||
- `-T linker.ld`:链接脚本
|
||||
- `--oformat elf64-x86-64`:输出 ELF 格式
|
||||
- `--oformat binary`:输出原始二进制(用于内核)
|
||||
- `--strip-all`:去除所有符号信息
|
||||
|
||||
### 目标平台配置
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `target.triple` | string | LLVM 目标三元组 |
|
||||
| `target.datalayout` | string | LLVM 数据布局字符串 |
|
||||
|
||||
注意:**无统一默认 triple**——由各工程 `project.vpj` 自行指定(TransPyV 自身为 `x86_64-pc-windows-gnu`;ViperOS 内核为 `x86_64-none-elf`)。`target.datalayout` 同样随工程配置,内核工程常用:
|
||||
`e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128`
|
||||
|
||||
> **平台说明**:当前工具链与运行时验证以 **Windows** 为主(`llc` + mingw `clang++`),原因是**计划与精力有限**,并非语言/编译器设计上的限制;**实际大量代码可跨平台复用**,后续按需扩展到其它平台。
|
||||
|
||||
### 包含路径
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `includes` | string[] | 模块搜索路径列表 |
|
||||
|
||||
### 编译选项
|
||||
|
||||
| 字段 | 类型 | 说明 |
|
||||
|------|------|------|
|
||||
| `options.slice_level` | int | 切片优化级别(0-3) |
|
||||
| `options.sha1_slice_level` | int | SHA1 切片存储级别(默认 1;≥1 时产物按 `{temp}/{sha1[0:2]}/` 子目录存放) |
|
||||
| `options.target` | string | 编译目标(目前仅支持 `llvm`) |
|
||||
| `options.strict_mode` | bool | 严格模式 |
|
||||
|
||||
## 切片优化级别
|
||||
|
||||
| 级别 | 名称 | 说明 |
|
||||
|------|------|------|
|
||||
| `0` | `no_optimize` | 无优化 |
|
||||
| `1` | `conservative` | 保守优化 |
|
||||
| `2` | `moderate` | 适度优化 |
|
||||
| `3` | `aggressive` | 激进优化(默认) |
|
||||
| `s` | `size` | 体积优化 |
|
||||
|
||||
## 项目结构示例
|
||||
|
||||
### 内核项目
|
||||
|
||||
```
|
||||
VKernel/
|
||||
├── project.vpj # 项目配置
|
||||
├── linker.ld # 链接脚本
|
||||
├── Kernel/ # 源代码目录
|
||||
│ ├── main.vp # 内核入口
|
||||
│ ├── bootinfo.vp
|
||||
│ ├── intr/
|
||||
│ │ ├── gdt.vp
|
||||
│ │ ├── idt.vp
|
||||
│ │ └── syscall.vp
|
||||
│ ├── drivers/
|
||||
│ │ ├── serial/
|
||||
│ │ ├── video/
|
||||
│ │ ├── storage/
|
||||
│ │ └── ...
|
||||
│ └── ...
|
||||
├── .tpv_build/ # 构建目录(build_dir,自动生成)
|
||||
│ ├── temp/ # 临时文件
|
||||
│ │ ├── <sha1[0:2]>/ # SHA1 切片子目录(sha1_slice_level ≥ 1)
|
||||
│ │ │ ├── <SHA1>.vpi # 签名存根
|
||||
│ │ │ ├── <SHA1>.stub.ll # LLVM IR 声明
|
||||
│ │ │ ├── <SHA1>.text.ll # 含代码的 .ll
|
||||
│ │ │ └── <SHA1>.deps.txt # 依赖信息
|
||||
│ │ └── _sha1_map.txt # SHA1→源文件路径映射(仅人类可读)
|
||||
│ └── output/ # 输出文件
|
||||
│ ├── kernel.bin # 内核二进制
|
||||
│ ├── *.deps.txt # 依赖信息
|
||||
│ └── linker.ld # 生成的链接脚本
|
||||
```
|
||||
|
||||
### 应用项目
|
||||
|
||||
```
|
||||
HelloWorld/
|
||||
├── project.vpj # 项目配置
|
||||
├── linker.ld # 链接脚本
|
||||
├── main.vp # 应用入口
|
||||
└── .tpv_build/ # 构建目录(自动生成)
|
||||
├── temp/ # 临时文件
|
||||
└── output/ # 输出文件
|
||||
└── helloworld.elf # ELF 可执行文件
|
||||
```
|
||||
|
||||
### 库项目
|
||||
|
||||
```
|
||||
SerialLogger/
|
||||
├── project.vpj # 项目配置
|
||||
├── linker.ld # 链接脚本
|
||||
├── serial_logger.vp # 库源码
|
||||
└── .tpv_build/ # 构建目录(自动生成)
|
||||
├── temp/ # 临时文件
|
||||
└── output/ # 输出文件
|
||||
```
|
||||
|
||||
## 链接脚本
|
||||
|
||||
ViperOS 使用自定义链接脚本控制内存布局:
|
||||
|
||||
```ld
|
||||
ENTRY(_start)
|
||||
|
||||
SECTIONS
|
||||
{
|
||||
. = 0x100000; /* 加载地址 */
|
||||
|
||||
.text : {
|
||||
*(.text.startup)
|
||||
*(.text*)
|
||||
}
|
||||
|
||||
.rodata : {
|
||||
*(.rodata*)
|
||||
}
|
||||
|
||||
.data : {
|
||||
*(.data*)
|
||||
}
|
||||
|
||||
.bss : {
|
||||
*(.bss*)
|
||||
*(COMMON)
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 编译命令
|
||||
|
||||
TransPyC 编译器的基本用法(注:适用于单个文件,而不适用于工程):
|
||||
|
||||
```bash
|
||||
python TransPyC.py -f InputFile -o OutputFile [options]
|
||||
```
|
||||
|
||||
### 命令行参数
|
||||
|
||||
| 参数 | 说明 |
|
||||
|------|------|
|
||||
| `-f` | 输入文件路径 |
|
||||
| `-o` | 输出文件路径 |
|
||||
| `-wh` | 头文件列表 |
|
||||
| `-debug` | 调试输出文件 |
|
||||
| `-cc` | 编译命令 |
|
||||
| `-cflags` | 编译标志 |
|
||||
| `-run` | 编译后运行 |
|
||||
| `-args` | 运行参数 |
|
||||
| `-h` | 辅助文件(C 或 Python) |
|
||||
|
||||
工程编译使用(`--project` 指定工程文件):
|
||||
```bash
|
||||
python Projectrans.py --project project.vpj
|
||||
```
|
||||
即可
|
||||
|
||||
## TransPyV 命令行开关
|
||||
|
||||
用自举产物 `TransPyV.exe` 编译工程时的常用开关(完整清单见 [TransPyV/README.md](../TransPyV/README.md)):
|
||||
|
||||
| 开关 | 说明 |
|
||||
|------|------|
|
||||
| `--project <path>` | `project.vpj` 路径(不给则在当前目录、上级目录查找) |
|
||||
| `--clean` | 清理 temp / output / includes 预编译缓存 |
|
||||
| `--rebuild-includes` | 只删 includes 预编译缓存,强制重编 includes |
|
||||
| `--clear-cache` | 只清 temp 缓存(`.vpi` / `.stub.ll` / `.text.ll`) |
|
||||
| `--phase 1\|2\|all` | 1 = 只做 stub 分离;2 = 只做 IR 组合 + 编译;all = 全部(默认) |
|
||||
| `--run` | 编译成功后立即运行产物 |
|
||||
| `--asan` | ASan 模式(`opt -passes=asan` 插桩;运行库须由 `linker.static_libs` 声明,否则 fail-fast) |
|
||||
| `--traceback` | 生成栈回溯支持(DWARF 元数据 + `<exe>.stackmap` 旁文件),见 [17-traceback.md](17-traceback.md) |
|
||||
| `--detection` / `--detection-deep` | MemBuddy 分配检测(`0xCDCD` 标记 + 探针) |
|
||||
| `--no-llvmpeephole` | 关闭 FunctionPrint 的本地窥孔(T2 store/load 转发、T3 空 bitcast) |
|
||||
| `--backend llvm\|mlir` | 后端选择(`llvmlite` / `mlirlite`) |
|
||||
| `--repl` | 启动交互式 REPL,见 [16-repl.md](16-repl.md) |
|
||||
| `--nowarn-register` | 抑制 Phase A 依赖类 WARN |
|
||||
| `--version` / `--help` | 版本 / 帮助 |
|
||||
|
||||
## 构建流程(真实骨架)
|
||||
|
||||
工程构建的实际流水线:
|
||||
|
||||
- **Phase 1(声明阶段)**:扫描入口与依赖并建依赖图 → 1a 结构体注册 → 1b 生成 `.vpi` 并翻译生成 stub
|
||||
- **Phase 2(翻译与链接)**
|
||||
- **Phase A-pre-vpi / Phase A-pre**:加载 `.vpi`,预翻译准备
|
||||
- **Phase A**:主循环多遍收敛翻译,`.stub.ll`/`.text.ll` 在此写盘
|
||||
- **Phase B**:`llc` 并行编译 `.ll` → `.o`
|
||||
- **Phase B+**:缺失 includes 按需编译
|
||||
- **Phase C**:链接(`linker.cmd` 决定链接器)
|
||||
|
||||
## 增量编译
|
||||
|
||||
TransPyC 支持基于 SHA1 的增量编译,与两阶段编译模型紧密耦合:
|
||||
|
||||
### 阶段一增量
|
||||
|
||||
- 每个源文件按内容计算 SHA1 哈希(16 个十六进制字符,即 64 位截断)
|
||||
- 如果 `<SHA1>.vpi` 和 `<SHA1>.stub.ll` 已存在,则跳过生成(缓存命中)
|
||||
- 只有源文件内容变化导致 SHA1 变化时才重新生成声明接口
|
||||
- SHA1 → 源文件路径映射在内存 `Sha1Store` 中多遍收敛构建;`temp/_sha1_map.txt`(格式 `<sha1>:<relative_path>`)仅人类可读
|
||||
|
||||
### 阶段二增量
|
||||
|
||||
- 阶段二(Phase A 主循环)在内存 `Sha1Store`/`StubMergerStore` 中多遍收敛构建并复用映射,不依赖 `_sha1_map.txt`
|
||||
- 旧产物清理使用 `--clear-cache`
|
||||
- 共享符号表为内存 `StubMergerStore`,按需加载避免每个文件重复加载
|
||||
|
||||
### SHA1 命名空间与增量编译的协同
|
||||
|
||||
SHA1 同时服务于命名空间隔离和增量编译:
|
||||
- **命名空间**:未 `export` 的函数(内部非 `t.CExport`)和结构体使用 SHA1 前缀,消除符号冲突
|
||||
- **增量编译**:SHA1 不变则缓存命中,SHA1 变化则重新生成
|
||||
|
||||
详见 [README.MD 中 SHA1 命名空间机制](README.MD#sha1-命名空间机制)。
|
||||
@@ -1,4 +1,4 @@
|
||||
# Viper 多继承支持方案
|
||||
# 14 - Viper 多继承支持方案
|
||||
|
||||
> 背景:Viper 语法层已支持 `class X(A, B)`(`ClassDef.bases` 是列表,parser 正常解析),
|
||||
> 已支持 `class X(A, B)` 多继承:`StructEntry` 含 `ParentName`(首父兼容)+ `ParentNames` + `ParentCount`。
|
||||
@@ -1,4 +1,4 @@
|
||||
# 16 - 交互式 REPL
|
||||
# 15 - 交互式 REPL
|
||||
|
||||
`TransPyV` 内置一个交互式 REPL:把每一行/每一块 Viper 片段**即时编译成 DLL 并加载调用**,把结果回显出来。它支持会话变量(M2)与跨片段会话函数(M3),适合快速试验语法、验证表达式与类型行为。
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
# 17 - 栈回溯与调试信息
|
||||
# 16 - 栈回溯与调试信息
|
||||
|
||||
TransPyV 里的 "traceback" 有**两套完全不同的东西**,务必区分:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# 18 - 旗舰项目
|
||||
# 17 - 旗舰项目
|
||||
|
||||
前面 17 章讲的是 **Viper 这门语言**本身。本章介绍用 Viper 写出来的几个**真实、完整的工程**——它们既是语言能力的实证,也是编译器最重要的回归对象。
|
||||
前面 16 章讲的是 **Viper 这门语言**本身。本章介绍用 Viper 写出来的几个**真实、完整的工程**——它们既是语言能力的实证,也是编译器最重要的回归对象。
|
||||
|
||||
| 项目 | 位置 | 定位 |
|
||||
|------|------|------|
|
||||
@@ -63,7 +63,7 @@ TransPyV/
|
||||
exe\TransPyV.exe --project ViperApps\ViperMNIST\project.vpj --clean --run
|
||||
```
|
||||
|
||||
命令行参数详见 [12-project.md](12-project.md);自举过程与可行性分析详见 [13-bootstrapping.md](13-bootstrapping.md);交互式 REPL 见 [16-repl.md](16-repl.md)。
|
||||
命令行参数详见 [12-compilation-system.md](12-compilation-system.md);自举过程与可行性分析详见 [13-bootstrapping.md](13-bootstrapping.md);交互式 REPL 见 [15-repl.md](15-repl.md)。
|
||||
|
||||
> 自举注意点:自举后模块级全局变量带 **SHA1 前缀**(模块隔离),像 `_g_gen` 这类单例必须**逐模块赋值**,不能只在 `main.vp` 里赋裸名,否则部分模块会读到自己的 `None`。
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
|
||||
而实际上,下文中所有提到的 `C` 语言都是为了便于使用 `C` 的底层开发者理解。由于历史原因,在旧版本中我们使用 `C` 来作为中间语言,如同旧版本的 `C++` 一样,但现在 `target="c"` 的路径已经完全删除,`C` 路径永久不再受维护。
|
||||
|
||||
> **成熟度与当前任务(重要)**:Viper 的**语法在最新版本已经相当稳定**,对**现实工程已经可用**——[18-flagship-project.md](18-flagship-project.md) 中的 TransPyV(自举编译器)、ViperOS(裸机操作系统)、ViperMNIST(深度学习)等都是实证。因此当前的主要工作**不是**继续改动语法,而是**更正内部的存量代码**:把历史遗留的旧写法(`t.C*` / `c.*` / `T | t.CPtr` 等)迁移到新语法,详见 [02-type-system.md 类型书写规范](02-type-system.md#类型书写规范新语法推荐) 与仓库根目录的 `新规范`。
|
||||
> **成熟度与当前任务(重要)**:Viper 的**语法在最新版本已经相当稳定**,对**现实工程已经可用**——[17-flagship-project.md](17-flagship-project.md) 中的 TransPyV(自举编译器)、ViperOS(裸机操作系统)、ViperMNIST(深度学习)等都是实证。因此当前的主要工作**不是**继续改动语法,而是**更正内部的存量代码**:把历史遗留的旧写法(`t.C*` / `c.*` / `T | t.CPtr` 等)迁移到新语法,详见 [02-type-system.md 类型书写规范](02-type-system.md#类型书写规范新语法推荐) 与仓库根目录的 `新规范`。
|
||||
>
|
||||
> **Viper 的前身是一个玩具项目**(把 Python 转成 C),**但我们期望 Viper 不再是**:它拥有独立的类型系统、两阶段编译模型、`SHA1` 命名空间模块体系与自举编译器,目标是成为一门可用于真实系统开发的编程语言。
|
||||
|
||||
@@ -48,9 +48,15 @@ Viper 编译后的代码在底层等价于 `C` 编译后的机器码(都经过
|
||||
|
||||
> **FFI/导出新写法**:推荐使用语言软关键字 `extern`/`export`——`extern def foo(...) -> T` 仅声明外部函数(实现来自外部),`export def` 以裸名导出符号。解析器会把它们改写为返回注解中的存储类标记(`extern` → `T | t.State`,`export` → `t.CExport`),因此 `t.State`/`t.CExtern`/`t.CExport` 标记并未废弃,仍是内部承载(手写可用)。
|
||||
|
||||
### C-LIKE 语法(逐步支持)
|
||||
|
||||
Viper 的语法形态以 `Python`(ABC 系)为蓝本,但自研语法器 [includes/ast](../includes/ast) **将逐步支持 C-LIKE 写法**(C 风格的分隔与声明形式)。作者认为这是**值得投入**的方向,因此**两种写法及其语义都会被长期维护、保持一致**——不存在弃用某一端的计划。
|
||||
|
||||
就**实际工程**而言,仍然**推荐 ABC-LIKE 写法**:它与 `Python` 习惯一致、可读性最好,也是本仓库全部工程与文档采用的形态。
|
||||
|
||||
## 两阶段编译流程
|
||||
|
||||
Viper 的编译由 `Projectrans.py` 驱动,分为两个阶段。这是 Viper 编译模型的核心,理解两阶段编译是理解 `t.CDefine`、`t.CExport`、`t.CInline` 等关键概念的前提。
|
||||
Viper 的编译由入口驱动(TPC:`Projectrans.py`;TPV:`App/main.vp`),分为两个阶段。这是 Viper 编译模型的核心,理解两阶段编译是理解 `t.CDefine`、`t.CExport`、`t.CInline` 等关键概念的前提。
|
||||
|
||||
```
|
||||
源文件 (.vp) ──────────────────────────────────────────────────────
|
||||
@@ -84,7 +90,7 @@ Viper 的编译由 `Projectrans.py` 驱动,分为两个阶段。这是 Viper
|
||||
|
||||
#### 步骤 1:可达文件发现与拓扑排序
|
||||
|
||||
从入口文件(`main.vp` 或 `project.vpj` 指定;Python 单文件模式仍接受 `project.json`)出发,通过 `import` 语句递归遍历,找出所有可达的 `.vp` 源文件。然后对文件进行拓扑排序,确保被依赖的模块先被处理。
|
||||
从工程根出发,通过 `import` 语句递归遍历,找出所有可达的 `.vp` 源文件,再对文件进行拓扑排序,确保被依赖的模块先被处理。工程根由工程配置的 `source_dir` 指定(`TransPyV` 与 `TransPyV/Test` 用 `project.vpj`,`Test/*` 用同格式的 `project.json`);也可用 `--src <入口文件>`,此时构建配置由依赖闭包内的 `viperbuild` 提供(见 [12-compilation-system.md](12-compilation-system.md))。**不存在「只编一个文件」的单文件模式。**
|
||||
|
||||
```
|
||||
main.vp → import serial → import drivers.serial.uart.serial → ...
|
||||
@@ -165,7 +171,7 @@ sha1 = hashlib.sha1(content.encode('utf-8')).hexdigest()[:16]
|
||||
|
||||
#### 步骤 4:翻译源文件
|
||||
|
||||
对每个源文件,使用 `TransPyC` 翻译器将 Python AST 翻译为 LLVM IR:
|
||||
对每个源文件,使用对应翻译器(TPC `TransPyC` / TPV `lib/core/Gen`)将 AST 翻译为 LLVM IR:
|
||||
1. 将对应模块的 `.stub.ll` 声明嵌入到生成的 `.ll` 文件头部
|
||||
2. 所有被引用模块的 `.stub.ll` 声明也被嵌入
|
||||
3. 翻译 AST 节点为 LLVM IR 指令
|
||||
@@ -412,9 +418,9 @@ Viper **原本的语法完全符合 CPython**——源文件是合法的 Python
|
||||
|
||||
## 章节延伸
|
||||
|
||||
- 交互式 REPL(`--repl`)见 [16-repl.md](16-repl.md);
|
||||
- 栈回溯与调试信息(`--traceback` / DWARF)见 [17-traceback.md](17-traceback.md);
|
||||
- 用 Viper 写成的旗舰工程(TransPyV / VET / ViperOS / ViperMNIST)见 [18-flagship-project.md](18-flagship-project.md)。
|
||||
- 交互式 REPL(`--repl`)见 [15-repl.md](15-repl.md);
|
||||
- 栈回溯与调试信息(`--traceback` / DWARF)见 [16-traceback.md](16-traceback.md);
|
||||
- 用 Viper 写成的旗舰工程(TransPyV / VET / ViperOS / ViperMNIST)见 [17-flagship-project.md](17-flagship-project.md)。
|
||||
|
||||
## Hello World 示例(标准写法)
|
||||
|
||||
|
||||
Reference in new issue
Block a user