D
C 风格的语法,写起来比 C 宽松一些。
在手机上怎么跑
vml run examples/d/test/sysinfo.d
编译要等一会儿(C 那种要一两分钟,脚本类语言几秒)。程序跑起来后屏幕底部就是手柄,方向键 + 四个动作键都在;点右上角返回可以回到命令行。
写法要点
- 入口
void main() - 直接调用
ui_* - 与 C 一样注意数组越界
示例
| 文件 | 演示什么 |
|---|---|
test/catch.d | 接方块 |
test/sysinfo.d | 设备信息 |
同目录还有:demo/demo_std.d、test/libs.d、tty/demo_tty.d、ui/demo_ui.d
下面的内容是从 VML 源码里直接带的(third_party/vml/VMLPrepares/DCompiler/): README 讲这个前端支持什么、怎么编;语言规范 讲语法本身。上游一改,这里重新生成就是最新的。
语言规范
D 语言编译器规范说明
版本:v1.0 | 日期:2026-07-06 | 修订者:深圳市探索智能科技有限公司
元数据
| 属性 | 值 |
|---|---|
| 语言 | D |
| 标准 | D 2.0 子集 |
| 年份 | 2001 年首次发布 |
| 完成度 | ~97% |
| 源文件扩展名 | .d |
| 文件编码 | UTF-8 (默认) |
概述
D 是一门系统编程语言,采用 C-like 语法与模块化设计。本编译器实现的是 D 2.0 规范的功能子集,面向 VML 虚拟机的 MCU 安全子集环境运行。编译流程为:
source.d → [预处理器] → [Lexer] → [Parser] → [CodeGenerator] → VML汇编 (.vml)
编译器入口
- 主编译器类:
DCompiler.DCompiler - 插件注册:
DCompilerPlugin(实现CompilerPluginExBase) - 独立运行:
CompilerProgram.MainAsync()— 使用SimpleCompilerProgram包装
调用约定
采用类 C 调用约定:参数从右到左压栈,调用者负责栈清理。R0 寄存器存放返回值(整数/布尔/指针),浮点返回值使用 F0 寄存器。
支持的特性
1. 数据类型
| 类型 | 关键字 | VML IR 宽度 | 说明 |
|---|---|---|---|
| 空类型 | void | — | 函数无返回值 |
| 整数 | int | 32-bit signed | 支持十进制和十六进制 (0x) 字面量 |
| 单精度浮点 | float | 32-bit | IEEE 754 单精度 |
| 双精度浮点 | double | 64-bit | 当前降级为 float 存储 |
| 布尔 | bool | 32-bit | true = 1, false = 0 |
| 字符串 | string | 指针 (32-bit) | 不可变字符数组,字面量存入 data section |
| 字符 | char | 8-bit | 单引号字面量,存储为 int |
| 类 | class | 引用类型 | 成员通过 R12-0 (this) 访问 |
| 结构体 | struct | 值类型 | 语法上支持,解析与 class 相同 |
| 接口 | interface | 占位 | 解析跳过内部声明 |
| 枚举 | enum | 32-bit | 支持显式赋值 = expr |
字面量语法:
- 整数:
42,0x2A,0xFF - 浮点:
3.14,0.5 - 布尔:
true,false - 空:
null - 字符串:
"hello world"(双引号,支持转义字符) - 字符:
'a','\n'(单引号,支持转义字符) - this 引用:
this(指向当前对象,存储在 R12-0)
2. 模块系统
module mymodule; // 声明当前模块名
import std.stdio; // 导入模块
import foo.bar.baz; // 点分导入路径
import 语句仅支持静态导入语法,解析时提取模块名用于库链接。module 声明语法上接受但不产生实际语义作用。
3. 变量声明
int x = 10; // 声明 + 初始化
float pi; // 声明(默认初始化 0)
string name = "hello"; // 字符串变量
bool flag = true; // 布尔变量
char c = 'A'; // 字符变量
ClassName obj; // 类类型变量(默认初始化为 0/null)
语义:
- 局部变量分配在栈帧中 (R12 相对偏移,每次分配 4 字节)
- 全局变量分配在 data section 中 (
var_name标签) - 不指定初始化器时,默认初始化为 0
- for 循环初始化段内支持声明新变量
4. 运算符
4.1 算术运算符
| 运算符 | 操作 | 示例 |
|---|---|---|
+ | 加法 | a + b |
- | 減法 | a - b |
* | 乘法 | a * b |
/ | 除法 | a / b |
% | 取模 | a % b |
^^ | 幂运算 | a ^^ b |
注意: ^^ 幂运算在 VML 层面不支持原生幂指令,编译器将 ^^ 降级为乘法 * 作为近似实现。
4.2 比较运算符
| 运算符 | 操作 | 说明 |
|---|---|---|
== | 等于 | 返回 1/0 |
!= | 不等于 | 返回 1/0 |
< | 小于 | 返回 1/0 |
> | 大于 | 返回 1/0 |
<= | 小于等于 | 返回 1/0 |
>= | 大于等于 | 返回 1/0 |
比较运算返回整数值:1 为 true,0 为 false。
4.3 逻辑运算符
| 运算符 | 操作 | 说明 |
|---|---|---|
&& | 逻辑与 | CMP + JE 短路求值 |
|| | 逻辑或 | 短路求值 |
! | 逻辑非 | 一元取反 |
逻辑运算使用短路求值策略:&& 在左操作数为假时跳过右操作数;|| 在左操作数为真时跳过右操作数。
4.4 赋值运算符
| 运算符 | 操作 |
|---|---|
= | 直接赋值 |
+= | 加法赋值 |
-= | 減法赋值 |
*= | 乘法赋值 |
/= | 除法赋值 |
复合赋值运算符 (+=, -=, *=, /=) 在内部展开为 a = a op value 形式:
a += b; // 等价于 a = a + b;
a -= 5; // 等价于 a = a - 5;
a *= 2; // 等价于 a = a * 2;
a /= 3; // 等价于 a = a / 3;
5. 控制流
5.1 if / else 语句
if (condition) {
// then body
}
if (condition) {
// then body
} else {
// else body
}
if (x > 0) {
return 1;
} else if (x < 0) {
return -1;
} else {
return 0;
}
条件求值后与 0 比较,为假时跳转到 else 标签或 end 标签。
5.2 while 语句
while (condition) {
// loop body
}
5.3 do-while 语句
do {
// loop body
} while (condition);
实现方式: do-while 在编译时展开为 { body; while (cond) { body } }。
5.4 for 语句 (C 风格)
for (init; condition; increment) {
// loop body
}
// 示例
for (int i = 0; i < 10; i = i + 1) {
x = x + i;
}
三子句均为可选项:
init: 可为变量声明或表达式,执行一次condition: 在每次迭代前求值,为假时退出循环increment: 在每次迭代体执行后求值
5.5 break / continue
break 和 continue 关键字当前未实现。在 Lexer 的关键字表中不存在这两个关键字,因此会被当作普通标识符处理。
5.6 return 语句
return; // void 返回
return expression; // 带值返回
返回值存入 R0 寄存器,恢复 R12 后执行 RET。
6. 函数
// 完整声明格式
int add(int a, int b) {
return a + b;
}
// void 返回类型
void greet(string name) {
// ...
}
// 无参数
int getAnswer() {
return 42;
}
语法: returnType functionName(paramType paramName, ...) { body }
内部实现:
- 函数标签:
func_functionName - 类方法标签:
class_ClassName_methodName - 序言: PUSH R15, PUSH R12, MOVE R12 R13 (保存帧指针和返回地址,建立新栈帧)
- 参数通过栈传递,在栈帧内偏移 +4 字节处访问第一个参数
- 结尾: POP R12, RET (恢复帧指针,返回调用者)
- 函数定义在主流程中被 JMP 跳过,只有被显式调用时才会执行
7. 类与结构体
7.1 class
class Animal {
void speak() {
// member function
}
int getAge() {
return this.age; // this 关键字号
}
}
class解析为ClassDeclNode- 成员函数按声明顺序生成
this关键字通过 R12-0 访问当前对象指针- 不支持继承(extends 关键字未实现)
- 不支持访问控制(public/private/protected 未实现)
- 不支持构造/析构函数
7.2 struct
struct Point {
int x;
int y;
}
语法上与 class 相同,共用 ClassDeclNode AST 节点。区别仅在语义层面(值类型 vs 引用类型),当前实现不做区分。
7.3 interface
interface Drawable {
void draw();
}
interface 声明进行解析,跳过内部声明体,返回占位 AST 节点。接口方法不生成代码。
7.4 enum
enum Color {
Red, // 隐式值 0
Green, // 隐式值 1
Blue = 5, // 显式赋值
Yellow // 隐式值 6
}
- 枚举成员名由
Identifier识别 - 支持
= expression显式赋值 - 成员之间以逗号分隔(结尾逗号可选)
- 枚举声明体以分号结束 (
};)
8. 注释
| 类型 | 语法 | 说明 |
|---|---|---|
| 单行注释 | // text | 从 // 到行尾 |
| 块注释 | /* text */ | 多行,不可嵌套 |
| 嵌套块注释 | /+ text +/ | D 语言原生嵌套注释,当前未专门支持 |
编译器内部的 LexerBase.SkipBlockComment 处理 /* ... */,SkipLineComment 处理 // ...。/+ ... +/ 嵌套注释语法当前未在 Lexer 中实现。
注意: 注释 token 在 Tokenize 阶段产生但不参与语法分析 (被 SkipComments() 跳过)。
9. 字符串字面量
"hello world" // 普通字符串
"line1\nline2" // 含转义字符
"quote: \"inside\"" // 转义双引号
- 双引号界定
- 内部转义字符由
LexerBase.ReadStringLiteral处理(支持\n,\t,\\,\",\0等标准 C 转义序列) - 字符串字面量在 data section 中分配,通过
MOVE R0, label加载地址 - 相同内容的字符串被缓存去重
10. 字符字面量
'a' // 字符 'a'
'\n' // 换行符
'\t' // 制表符
'\\' // 反斜杠
- 单引号界定
- 解析为整数值(字符的 ASCII/Unicode 码点)
- 与字符串字面量共用
ReadStringLiteral方法处理
11. 表达式语法
Expression := Assignment
Assignment := LogicalOr ('=' | '+=' | '-=' | '*=' | '/=') Assignment | LogicalOr
LogicalOr := LogicalAnd ('||' LogicalAnd)*
LogicalAnd := Comparison ('&&' Comparison)*
Comparison := Additive (('==' | '!=' | '<' | '>' | '<=' | '>=') Additive)*
Additive := Multiplicative (('+' | '-') Multiplicative)*
Multiplicative := Unary (('*' | '/' | '%' | '^^') Unary)*
Unary := ('-' | '!') Unary | Postfix
Postfix := Primary ('(' Arguments? ')')*
Primary := Integer | Float | String | Char | true | false | null
| this | Identifier | '(' Expression ')'
12. 表达式优先级
按优先级从低到高排列:
| 优先级 | 运算符 | 结合性 |
|---|---|---|
| 1 (最低) | = += -= *= /= | 右结合 |
| 2 | || | 左结合 |
| 3 | && | 左结合 |
| 4 | == != < > <= >= | 左结合 |
| 5 | + - | 左结合 |
| 6 | * / % ^^ | 左结合 |
| 7 | - (一元) ! (一元) | 右结合 |
| 8 (最高) | () (函数调用) | 左结合 |
13. 预处理器支持
编译器集成了 C 风格预处理器 (Preprocessor),在词法分析前执行:
预定义宏
| 宏名 | 值 | 说明 |
|---|---|---|
__VML__ | 1 | VML 目标平台标识 |
__VML_VERSION__ | "1.65.32" | VML 工具链版本 |
__D__ | 1 | D 语言源文件标识 |
__DATE__ | "MMM dd yyyy" | 编译日期 |
__TIME__ | "HH:mm:ss" | 编译时间 |
预处理指令
支持标准 C 预处理指令,仅当源文件包含 # 字符时才激活预处理器:
#include "file"/#include <file>#define NAME value/#define NAME#undef NAME#if/#ifdef/#ifndef/#else/#elif/#endif#pragma(传递到编译管线)#error "message"- 行继续符
\
14. 入口点与库链接
- 程序入口点为
main标签(非main函数,而是 VML 程序起始点) - 编译器自动链接 D 标准库 (目录
Lib/d/),通过CompilerHelper.LinkStandardLibrary执行 import声明的模块自动解析为库文件路径并链接
限制与未实现特性
以下特性属于 D 语言完整规范但目前不支持:
元编程
- 模板 (Template):
template T(T)— 模板元编程核心特性,未实现 - 混入 (Mixin):
mixin("string")— 编译时代码生成,未实现 - CTFE (编译时函数求值): 不支持在编译期执行函数
- 约束 (Constraint):
if (is(T == int))模板约束,未实现
契约编程
- in 契约:
in { assert(x > 0); }— 前置条件,未实现 - out 契约:
out (result) { assert(result > 0); }— 后置条件,未实现 - invariant:
invariant() { ... }— 类不变量,未实现
内存管理
- GC (垃圾回收): D 的默认内存管理策略,因 MCU 安全子集限制而跳过
- new 表达式:
new ClassName()— 关键字识别但不生成分配代码 - delete: 显式析构,未实现
控制流
- switch / case: 多分支选择,未实现
- break: 循环中断,未实现 (关键字不在词法解析表中)
- continue: 继续下一次迭代,未实现 (关键字不在词法解析表中)
- foreach / foreach_reverse: 范围迭代,未实现
- goto: 跳转语句,未实现
- scope 语句:
scope(exit),scope(success),scope(failure)— 作用域守卫,未实现 - with 语句:
with (expr) { ... }— 作用域缩短,未实现 - synchronized: 多线程同步,未实现
- try / catch / finally: 异常处理,因 MCU 安全子集限制跳过
类型系统
- auto: 类型推导,未实现
- const / immutable: 类型修饰符,未实现
- alias: 类型别名,未实现
- typeof: 类型获取,未实现
- delegate / function: 委托与函数指针,未实现
- enum 作为清单类型:
enum E : string { ... }— 仅支持基本整数枚举 - union: 联合体,未实现
复合类型
- 关联数组:
int[string] aa;— 键值对容器,未实现 - 动态数组:
int[] arr;— 切片与动态数组,未实现 - 静态数组:
int[10] arr;— 固定大小数组,未实现 - 切片操作:
arr[0..$],arr[1..3]— 未实现
其他
- unittest 块:
unittest { ... }— 单元测试块,未实现 - version / debug: 条件编译块,未实现 (可通过预处理器
#ifdef替代) - 属性 (Property):
@property T name()— 未实现 - 操作符重载:
T opBinary(string op)(T rhs)— 未实现 - UFCS (统一函数调用语法):
obj.method()等价method(obj),未实现 - 模块构造函数/析构函数:
static this(),static ~this()— 未实现 - 嵌套函数/闭包: 函数内定义函数,未实现
- Ranges (范围):
std.range等惰性求值抽象,未实现 - list (链表字面量): 如
[1, 2, 3],未实现
编译选项
通过 CLI 工具 VMLTool 调用时支持的编译选项:
| 选项 | 含义 |
|---|---|
-o <file> | 输出文件路径 |
-mode mcu | MCU 安全子集模式 (默认) |
-mode os | 完整 OS 模式 |
--std=<std> | 指定语言标准版本 |
-D <macro> | 定义预处理宏 |
-U <macro> | 取消预处理宏定义 |
-I <path> | 添加 include 搜索路径 |
-L <path> | 添加库搜索路径 |
-static | 静态链接 |
-shared | 动态链接 |
-target <arch> | 指定目标架构 |
完整语法参考 (EBNF)
Program := { TopLevelDecl }
TopLevelDecl := ModuleDecl | ImportDecl | FuncDef | VarDecl
| ClassDecl | StructDecl | InterfaceDecl | EnumDecl
ModuleDecl := "module" Identifier ";"
ImportDecl := "import" Identifier { "." Identifier } ";"
Type := "void" | "int" | "float" | "double" | "bool"
| "string" | "char" | Identifier
VarDecl := Type Identifier [ "=" Expression ] ";"
FuncDef := Type Identifier "(" [ ParamList ] ")" Block
ParamList := Type Identifier { "," Type Identifier }
ClassDecl := "class" Identifier "{" { Declaration } "}" ";"
StructDecl := "struct" Identifier "{" { Declaration } "}" ";"
InterfaceDecl := "interface" Identifier "{" { Declaration } "}" ";"
EnumDecl := "enum" Identifier "{" EnumMember { "," EnumMember } [ "," ] "}" ";"
EnumMember := Identifier [ "=" Expression ]
Block := "{" { Statement } "}"
Statement := ReturnStmt | IfStmt | WhileStmt | DoWhileStmt
| ForStmt | VarDecl | ExpressionStmt
ReturnStmt := "return" [ Expression ] ";"
IfStmt := "if" "(" Expression ")" Block [ "else" (IfStmt | Block) ]
WhileStmt := "while" "(" Expression ")" Block
DoWhileStmt := "do" Block "while" "(" Expression ")" ";"
ForStmt := "for" "(" [ForInit] ";" [ Expression ] ";" [ Expression ] ")" Block
ForInit := VarDecl | Expression
ExpressionStmt:= Expression ";"
Expression := Assignment
Assignment := LogicalOr [ ("=" | "+=" | "-=" | "*=" | "/=") Assignment ]
LogicalOr := LogicalAnd { "||" LogicalAnd }
LogicalAnd := Comparison { "&&" Comparison }
Comparison := Additive [ ("==" | "!=" | "<" | ">" | "<=" | ">=") Additive ]
Additive := Multiplicative { ("+" | "-") Multiplicative }
Multiplicative:= Unary { ("*" | "/" | "%" | "^^") Unary }
Unary := ["-" | "!"] Postfix
Postfix := Primary { "(" [ Expression { "," Expression } ] ")" }
Primary := Integer | FloatLiteral | StringLiteral | CharLiteral
| "true" | "false" | "null" | "this"
| Identifier
| "(" Expression ")"
Identifier := Letter { Letter | Digit | "_" }
Integer := Digit { Digit } | "0x" HexDigit { HexDigit }
FloatLiteral := Digit { Digit } "." Digit { Digit }
StringLiteral := '"' { Character } '"'
CharLiteral := "'" Character "'"
Comment := "//" { Character }
BlockComment := "/*" { Character } "*/"
🆕 字符串编码 (v1.65.19)
该语言编译器通过共享库 (Lib/shared/) 间接使用 VML 字符串体系。
| 伪指令 | 宽度 | 编码 | C 类型 |
|---|---|---|---|
.string | 8-bit | UTF-8 | char* |
.wstring | 16-bit | UTF-16LE | wchar_t* |
.ustring | 32-bit | UTF-32LE | char32_t* |
MCU 模式 (默认): 字符串输出为 UTF-8 (.string) OS 模式: 可通过 VML_WSTRING 宏判断编码
共享库已提供宽字符串转换函数 (wchar.h/uchar.h),各语言编译器可按需使用。
编译器 README
D 编译器
路径: VMLPrepares/DCompiler/ 完成度: ~97% | 🟢 生产可用 标准库: Lib/d/
功能
- ✅ 词法分析 + 语法分析 + 代码生成 (Lexer/Parser/CodeGenerator)
- ✅ 模块系统: module/import
- ✅ 类/结构体/接口/枚举: class/struct/interface/enum
- ✅ C 风格类型系统 (int/float/double/bool/string/char/void)
- ✅ 控制流 (if/else/while/for/do-while/foreach/break/continue)
- ✅ 运算符: ++/--/位运算/三元运算符
- ✅ 32-bit signed int, 32-bit float, 64-bit double, 8-bit char
- ✅ 36 测试 0 失败
- ⚠️ 模板元编程 — 未实现
- ⚠️ contract/invariant — 未实现
- ✅ C 风格预处理 (#ifdef/#ifndef/#define/#include)
编译模式
MCU 模式(默认 --mode mcu)
MCU 模式针对单片机/裸机环境优化。
跳过(MCU 不支持):
- 模板元编程 (编译期展开过大)
- contract/invariant
保留:
- 基本 OOP (class/struct/interface)
- 模块导入
- 完整运算符支持
OS 模式(--mode os)
OS 模式支持全部语言特性。
RAM 级别
--ram k:KB级别--ram m:MB级别(默认)--ram g:GB级别
使用
dotnet run --project VMLTool -- input.d -o output.vml
测试
VMLTests/NewCompilerTests.cs— 36 测试 (0 失败)VMLTests/FullPipelineTests.cs— 全管线测试Examples/d/— 示例程序 (start/factorial/file_io/info)Examples/benchmark/— bench_int_d.d / bench_float_d.d