Compare commits
5 Commits
459d1e1e10
..
v0.6.0
| Author | SHA1 | Date | |
|---|---|---|---|
| de91886712 | |||
| 39d8bad022 | |||
| 1e161ecfff | |||
| 143174ee4f | |||
| 2baf762d82 |
@@ -1,5 +1,22 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 0.6.0 (2026-06-05)
|
||||||
|
|
||||||
|
### Added
|
||||||
|
- 新类型: `i32` (32位有符号整数), `u64` (64位无符号整数), `char` (单字符) + 字符字面量 `'A'`
|
||||||
|
- guard 语句: `guard x >= 0 else { return -1; }` (parser 去糖为 if-else)
|
||||||
|
- 命名参数: `draw_rect(width: 10, height: 20)` 任意顺序传参,sema 重排序
|
||||||
|
- 管道 `|>`: `10 |> double() |> add(5)` → `add(double(10), 5)` (F#/Elixir 风格)
|
||||||
|
- 字符串插值: `"Hello, \(name)!"` → `"Hello, " + name + "!"` (Swift 风格)
|
||||||
|
- 4 个新集成测试: 25_new_types ~ 29_interp
|
||||||
|
|
||||||
|
### Changed
|
||||||
|
- **语法差异化**: `let mut` → `var`, `[T; N]` → `T[N]`, `..` → `to`, `impl` → `extend`
|
||||||
|
- 类型隐式转换: `can_implicit_convert()` 加宽规则 + codegen `coerce_int()`
|
||||||
|
- 符号表扩展: `Symbol.param_names` 支持命名参数匹配
|
||||||
|
- AST 扩展: `CALL_EXPR`/`METHOD_CALL` 增加 `arg_names` 字段
|
||||||
|
- 测试: 158 单元 (41+15+74+28) + 29 集成
|
||||||
|
|
||||||
## 0.5.0 (2026-06-05)
|
## 0.5.0 (2026-06-05)
|
||||||
|
|
||||||
### Added
|
### Added
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p align="center">
|
<p align="center">
|
||||||
<img src="https://img.shields.io/badge/version-0.5.0-blue" alt="version">
|
<img src="https://img.shields.io/badge/version-0.6.0-blue" alt="version">
|
||||||
<img src="https://img.shields.io/badge/C-17-555555" alt="C">
|
<img src="https://img.shields.io/badge/C-17-555555" alt="C">
|
||||||
<img src="https://img.shields.io/badge/LLVM-22.1.7-4B8BBE" alt="LLVM">
|
<img src="https://img.shields.io/badge/LLVM-22.1.7-4B8BBE" alt="LLVM">
|
||||||
<img src="https://img.shields.io/badge/GCC-15.x-darkgreen" alt="GCC">
|
<img src="https://img.shields.io/badge/GCC-15.x-darkgreen" alt="GCC">
|
||||||
@@ -16,18 +16,20 @@
|
|||||||
|
|
||||||
## 简介
|
## 简介
|
||||||
|
|
||||||
L Language 是一门学习型编译语言,手写词法分析、递归下降 + Pratt 解析、语义分析和 LLVM IR 代码生成,最终生成原生可执行文件。语法借鉴 Rust,类型系统支持类型推断。
|
L Language 是一门学习型编译语言,手写词法分析、递归下降 + Pratt 解析、语义分析和 LLVM IR 代码生成,最终生成原生可执行文件。语法博采众长(Rust/Swift/Elixir),拥有管道、字符串插值、命名参数等独有特性。
|
||||||
|
|
||||||
📖 **[语言参考手册](docs/language-reference.md)** — 完整的语法、类型、示例教程
|
📖 **[语言参考手册](docs/language-reference.md)** — 完整的语法、类型、示例教程
|
||||||
|
|
||||||
```rust
|
```rust
|
||||||
fn fib(n: i64) -> i64 {
|
fn double(x: i64) -> i64 {
|
||||||
if n < 2 { return n; }
|
return x * 2;
|
||||||
return fib(n - 1) + fib(n - 2);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() -> i64 {
|
fn main() -> i64 {
|
||||||
print_i64(fib(10)); // 输出 55
|
let name = "L";
|
||||||
|
print_str("Hello, \(name)!"); // 字符串插值
|
||||||
|
let result = 10 |> double() |> double(); // 管道
|
||||||
|
print_i64(result); // 40
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
@@ -41,8 +43,8 @@ fn main() -> i64 {
|
|||||||
```mermaid
|
```mermaid
|
||||||
graph TB
|
graph TB
|
||||||
subgraph 前端["编译器前端"]
|
subgraph 前端["编译器前端"]
|
||||||
Lexer[词法分析器<br/>手写状态机<br/>40 种 Token]
|
Lexer[词法分析器<br/>手写状态机<br/>55+ 种 Token]
|
||||||
Parser[语法分析器<br/>递归下降 + Pratt<br/>14 种 AST 节点]
|
Parser[语法分析器<br/>递归下降 + Pratt<br/>25 种 AST 节点]
|
||||||
Sema[语义分析器<br/>作用域链 + 类型推断<br/>类型检查 + 错误收集]
|
Sema[语义分析器<br/>作用域链 + 类型推断<br/>类型检查 + 错误收集]
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -69,13 +71,13 @@ graph TB
|
|||||||
| 模块 | 输入 | 输出 | 核心结构 |
|
| 模块 | 输入 | 输出 | 核心结构 |
|
||||||
|------|------|------|----------|
|
|------|------|------|----------|
|
||||||
| `lexer/` | `char*` 源码 | `Token[]` | `Token` {kind, start, length, line, col} |
|
| `lexer/` | `char*` 源码 | `Token[]` | `Token` {kind, start, length, line, col} |
|
||||||
| `parser/` | `Token[]` | `AstNode*` | 14 种节点 (Program..IdentExpr) |
|
| `parser/` | `Token[]` | `AstNode*` | 25 种节点 (Program..MethodCall) |
|
||||||
| `ast/` | — | 工厂函数 | `AstNode` {kind, type, as{union}} |
|
| `ast/` | — | 工厂函数 | `AstNode` {kind, type, as{union}} |
|
||||||
| `sema/` | `AstNode*` | 类型标注 | `Scope` 作用域链 + `Symbol` 符号表 |
|
| `sema/` | `AstNode*` | 类型标注 | `Scope` 作用域链 + `Symbol` 符号表 |
|
||||||
| `codegen/` | `AstNode*` | `LLVMModuleRef` | `CgCtx` {module, builder, var_table} |
|
| `codegen/` | `AstNode*` | `LLVMModuleRef` | `CgCtx` {module, builder, var_table} |
|
||||||
| `driver/` | 命令行参数 | exit code | 流水线串联 + 错误报告 |
|
| `driver/` | 命令行参数 | exit code | 流水线串联 + 错误报告 |
|
||||||
|
|
||||||
## 功能 (v0.5)
|
## 功能 (v0.6)
|
||||||
|
|
||||||
### 类型系统
|
### 类型系统
|
||||||
|
|
||||||
@@ -103,6 +105,7 @@ graph TB
|
|||||||
- `while` 循环
|
- `while` 循环
|
||||||
- `for i in 0 to 10` (去糖为 while)
|
- `for i in 0 to 10` (去糖为 while)
|
||||||
- `match expr { pat => { ... } _ => { ... } }` (去糖为 if-else)
|
- `match expr { pat => { ... } _ => { ... } }` (去糖为 if-else)
|
||||||
|
- `guard x >= 0 else { return -1; }` (去糖为 if-else)
|
||||||
- `return`
|
- `return`
|
||||||
|
|
||||||
### 函数 & 方法
|
### 函数 & 方法
|
||||||
@@ -111,11 +114,15 @@ graph TB
|
|||||||
- 返回类型校验
|
- 返回类型校验
|
||||||
- `extend StructName { fn method(self: Type) -> Ret { ... } }`
|
- `extend StructName { fn method(self: Type) -> Ret { ... } }`
|
||||||
- `instance.method(args)` 调用
|
- `instance.method(args)` 调用
|
||||||
|
- **命名参数**:`draw_rect(width: 10, height: 20)` 任意顺序传参
|
||||||
|
- **管道 `|>`**:`10 |> double() |> add(5)` 数据流从左到右
|
||||||
- 内建函数:`print_i64`, `print_f64`, `print_bool`, `print_str`
|
- 内建函数:`print_i64`, `print_f64`, `print_bool`, `print_str`
|
||||||
|
|
||||||
### 运算符
|
### 运算符 & 语法糖
|
||||||
|
|
||||||
`+ - * / %` `== != < > <= >=` `&& || !` `+= -= *= /=` `str + str`
|
`+ - * / %` `== != < > <= >=` `&& || !` `+= -= *= /=` `|>` `str + str`
|
||||||
|
|
||||||
|
- **字符串插值**:`"Hello, \(name)!"` → `"Hello, " + name + "!"`
|
||||||
|
|
||||||
### 内存管理
|
### 内存管理
|
||||||
|
|
||||||
@@ -133,8 +140,8 @@ graph TB
|
|||||||
### 从源码构建
|
### 从源码构建
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
git clone <repo-url>
|
git clone git@lhy-git.liuhangyv.top:Serendipity/l-language.git
|
||||||
cd "L Language"
|
cd l-language
|
||||||
mkdir build && cd build
|
mkdir build && cd build
|
||||||
cmake .. -G "MinGW Makefiles" -DCMAKE_PREFIX_PATH="D:/settings/Language/LLVM"
|
cmake .. -G "MinGW Makefiles" -DCMAKE_PREFIX_PATH="D:/settings/Language/LLVM"
|
||||||
mingw32-make -j4
|
mingw32-make -j4
|
||||||
@@ -142,6 +149,16 @@ mingw32-make -j4
|
|||||||
|
|
||||||
生成 `l_lang.exe`。
|
生成 `l_lang.exe`。
|
||||||
|
|
||||||
|
### 安装包(Windows)
|
||||||
|
|
||||||
|
下载 [L-Language-x.x.x-setup.exe](https://github.com/LHY0125/l-language/releases),双击安装。包含编译器、LLVM 运行时和 8 个示例程序,无需额外安装 GCC 或 LLVM。
|
||||||
|
|
||||||
|
安装包构建:
|
||||||
|
```bash
|
||||||
|
cd scripts && build_installer.bat
|
||||||
|
```
|
||||||
|
需要 NSIS 3.x。
|
||||||
|
|
||||||
## 使用
|
## 使用
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
@@ -159,7 +176,7 @@ mingw32-make -j4
|
|||||||
# 构建
|
# 构建
|
||||||
cd build && mingw32-make -j4
|
cd build && mingw32-make -j4
|
||||||
|
|
||||||
# 运行全部测试 (158 单元 + 24 集成)
|
# 运行全部测试 (158 单元 + 29 集成)
|
||||||
./l_lang_lexer_test.exe # 词法分析 (41 tests)
|
./l_lang_lexer_test.exe # 词法分析 (41 tests)
|
||||||
./l_lang_test.exe # 语法分析 (15 tests)
|
./l_lang_test.exe # 语法分析 (15 tests)
|
||||||
./l_lang_sema_test.exe # 语义分析 (74 tests)
|
./l_lang_sema_test.exe # 语义分析 (74 tests)
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# L Language 语言参考手册
|
# L Language 语言参考手册
|
||||||
|
|
||||||
> 版本 v0.5 | 158 测试全部通过 | LLVM 后端编译型语言
|
> 版本 v0.6 | 158 单元 + 29 集成测试全部通过 | LLVM 后端编译型语言
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
@@ -54,9 +54,12 @@ l_lang.exe hello.l -o hello.exe
|
|||||||
|
|
||||||
| 类型 | 关键字 | 范围/说明 | 示例 |
|
| 类型 | 关键字 | 范围/说明 | 示例 |
|
||||||
|------|--------|----------|------|
|
|------|--------|----------|------|
|
||||||
| 整数 | `i64` | 64位有符号,`-2^63 ~ 2^63-1` | `42`, `-7`, `0` |
|
| 32位整数 | `i32` | 32位有符号,`-2^31 ~ 2^31-1` | `100` |
|
||||||
|
| 64位整数 | `i64` | 64位有符号,`-2^63 ~ 2^63-1` | `42`, `-7`, `0` |
|
||||||
|
| 无符号整数 | `u64` | 64位无符号,`0 ~ 2^64-1` | `999` |
|
||||||
| 浮点 | `f64` | 64位双精度 | `3.14`, `-0.5`, `1.0` |
|
| 浮点 | `f64` | 64位双精度 | `3.14`, `-0.5`, `1.0` |
|
||||||
| 布尔 | `bool` | `true` 或 `false` | `true`, `false` |
|
| 布尔 | `bool` | `true` 或 `false` | `true`, `false` |
|
||||||
|
| 字符 | `char` | 单字符,ASCII | `'A'`, `'\n'` |
|
||||||
| 字符串 | `str` | UTF-8 文本 | `"Hello"`, `"你好"` |
|
| 字符串 | `str` | UTF-8 文本 | `"Hello"`, `"你好"` |
|
||||||
| 空类型 | `void` | 无返回值 | 用于函数返回类型 |
|
| 空类型 | `void` | 无返回值 | 用于函数返回类型 |
|
||||||
|
|
||||||
@@ -242,6 +245,67 @@ let result = add(3, 5);
|
|||||||
greet();
|
greet();
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### 命名参数
|
||||||
|
|
||||||
|
调用函数时可以标注参数名,命名参数可任意顺序,但必须放在位置参数之后:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn draw_rect(x: i64, y: i64, w: i64, h: i64) -> void {
|
||||||
|
// ...
|
||||||
|
}
|
||||||
|
|
||||||
|
draw_rect(0, 0, 100, 200); // 全位置
|
||||||
|
draw_rect(x: 1, y: 2, w: 10, h: 20); // 全命名
|
||||||
|
draw_rect(0, 0, w: 10, h: 20); // 混用
|
||||||
|
draw_rect(w: 10, h: 20, x: 1, y: 2); // 命名任意顺序
|
||||||
|
```
|
||||||
|
|
||||||
|
用 `:` 分隔参数名和值(与类型标注 `name: Type` 视觉统一)。
|
||||||
|
|
||||||
|
### guard 语句
|
||||||
|
|
||||||
|
guard 是提前返回的语法糖,用于提前处理异常条件:
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn abs(x: i64) -> i64 {
|
||||||
|
guard x >= 0 else { return -x; }
|
||||||
|
return x;
|
||||||
|
}
|
||||||
|
// guard x >= 0 else { ... } 去糖为:
|
||||||
|
// if !(x >= 0) { ... }
|
||||||
|
```
|
||||||
|
|
||||||
|
- `else` 块必须用花括号,通常包含 `return`/`continue` 等跳转
|
||||||
|
- guard 让正常路径的代码保持在左侧,提高可读性
|
||||||
|
|
||||||
|
### 管道 `|>`
|
||||||
|
|
||||||
|
管道将数据从左到右流经函数,LHS 作为 RHS 函数调用的第一个参数(F#/Elixir 风格):
|
||||||
|
|
||||||
|
```rust
|
||||||
|
fn double(x: i64) -> i64 { return x * 2; }
|
||||||
|
fn add(a: i64, b: i64) -> i64 { return a + b; }
|
||||||
|
|
||||||
|
let result = 10 |> double() |> add(5);
|
||||||
|
// 去糖为: add(double(10), 5) → 25
|
||||||
|
```
|
||||||
|
|
||||||
|
- 管道右侧必须是函数调用(带括号)
|
||||||
|
- 管道优先级低于所有算术运算符
|
||||||
|
|
||||||
|
### 字符串插值
|
||||||
|
|
||||||
|
用 `\(expr)` 在字符串中嵌入表达式(Swift 风格,`\` 与 C 转义字符视觉一致):
|
||||||
|
|
||||||
|
```rust
|
||||||
|
let name = "World";
|
||||||
|
let msg = "Hello, \(name)!";
|
||||||
|
print_str(msg); // Hello, World!
|
||||||
|
```
|
||||||
|
|
||||||
|
- 去糖为字符串拼接: `"Hello, " + name + "!"`
|
||||||
|
- 字面量 `\(` 写作 `\\(`,反斜杠写作 `\\`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 7. 结构体
|
## 7. 结构体
|
||||||
@@ -563,15 +627,17 @@ l_lang.exe source.l --emit-ir
|
|||||||
## 快速参考卡片
|
## 快速参考卡片
|
||||||
|
|
||||||
```
|
```
|
||||||
类型: i64 f64 bool str void struct enum T[N]
|
类型: i32 i64 u64 f64 bool char str void struct enum T[N]
|
||||||
声明: let x = val var x = val
|
声明: let x = val var x = val
|
||||||
let x: Type = val type Alias = Type
|
let x: Type = val type Alias = Type
|
||||||
控制流: if/else while for i in 0 to N match
|
控制流: if/else while for i in 0 to N match guard
|
||||||
函数: fn name(p: T) -> Ret { return expr; }
|
函数: fn name(p: T) -> Ret { return expr; }
|
||||||
|
func(name: val) 命名参数 expr |> func() 管道
|
||||||
结构体: struct Name { f: Type } Name { f: val }
|
结构体: struct Name { f: Type } Name { f: val }
|
||||||
枚举: enum Name { A, B, C } Name::B
|
枚举: enum Name { A, B, C } Name::B
|
||||||
方法: extend T { fn m(self: T) } obj.m()
|
方法: extend T { fn m(self: T) } obj.m()
|
||||||
内建: print_i64 print_f64 print_bool print_str
|
内建: print_i64 print_f64 print_bool print_str
|
||||||
运算符: + - * / % == != < > <= >= && || ! += -= *= /=
|
运算符: + - * / % == != < > <= >= && || ! += -= *= /= |>
|
||||||
|
插值: "Hello, \(name)!"
|
||||||
注释: // 行注释 /* 块注释 */
|
注释: // 行注释 /* 块注释 */
|
||||||
```
|
```
|
||||||
|
|||||||
@@ -0,0 +1,34 @@
|
|||||||
|
@echo off
|
||||||
|
REM L Language 安装包构建脚本
|
||||||
|
REM 前置条件: 已编译 l_lang.exe (cd build && mingw32-make -j4)
|
||||||
|
|
||||||
|
set VERSION=0.6.0
|
||||||
|
set NSIS=D:\Program Files (x86)\NSIS\Bin\makensis.exe
|
||||||
|
|
||||||
|
echo === 构建 L Language %VERSION% 安装包 ===
|
||||||
|
echo.
|
||||||
|
|
||||||
|
REM 1. 确保编译器已编译
|
||||||
|
if not exist "build\l_lang.exe" (
|
||||||
|
echo 错误: build\l_lang.exe 不存在,请先编译
|
||||||
|
exit /b 1
|
||||||
|
)
|
||||||
|
|
||||||
|
REM 2. 复制 LICENSE 到 scripts 目录
|
||||||
|
copy LICENSE scripts\LICENSE.txt >nul 2>&1
|
||||||
|
|
||||||
|
REM 3. 添加 BOM 并构建
|
||||||
|
cd scripts
|
||||||
|
(
|
||||||
|
echo // BOM marker
|
||||||
|
) > _bom.tmp
|
||||||
|
copy /b _bom.tmp + installer.nsi installer_bom.nsi >nul
|
||||||
|
del _bom.tmp
|
||||||
|
|
||||||
|
"%NSIS%" -DVERSION=%VERSION% installer_bom.nsi
|
||||||
|
del installer_bom.nsi
|
||||||
|
cd ..
|
||||||
|
|
||||||
|
echo.
|
||||||
|
echo === 完成 ===
|
||||||
|
echo 安装包: build\L-Language-%VERSION%-setup.exe
|
||||||
@@ -0,0 +1,155 @@
|
|||||||
|
Unicode true
|
||||||
|
; L Language 编译器 Windows 安装包
|
||||||
|
; 构建: makensis -DVERSION=x.y.z installer.nsi
|
||||||
|
|
||||||
|
!ifndef VERSION
|
||||||
|
!define VERSION "0.6.0"
|
||||||
|
!endif
|
||||||
|
|
||||||
|
!define PRODUCT "L Language"
|
||||||
|
!define PUBLISHER "Liu Hangyu (LHY0125)"
|
||||||
|
!define EXE "l_lang.exe"
|
||||||
|
|
||||||
|
Name "${PRODUCT} ${VERSION}"
|
||||||
|
OutFile "..\release\L-Language-${VERSION}-setup.exe"
|
||||||
|
InstallDir "$PROGRAMFILES\L Language"
|
||||||
|
RequestExecutionLevel admin
|
||||||
|
SetCompressor /SOLID lzma
|
||||||
|
SetCompressorDictSize 32
|
||||||
|
|
||||||
|
!include "MUI2.nsh"
|
||||||
|
|
||||||
|
!define MUI_ABORTWARNING
|
||||||
|
!insertmacro MUI_PAGE_WELCOME
|
||||||
|
!insertmacro MUI_PAGE_LICENSE "..\LICENSE"
|
||||||
|
!insertmacro MUI_PAGE_DIRECTORY
|
||||||
|
!insertmacro MUI_PAGE_INSTFILES
|
||||||
|
!insertmacro MUI_PAGE_FINISH
|
||||||
|
|
||||||
|
!insertmacro MUI_UNPAGE_CONFIRM
|
||||||
|
!insertmacro MUI_UNPAGE_INSTFILES
|
||||||
|
!insertmacro MUI_LANGUAGE "SimpChinese"
|
||||||
|
|
||||||
|
; ── 核心文件 ──
|
||||||
|
Section "Install"
|
||||||
|
SetOutPath "$INSTDIR"
|
||||||
|
|
||||||
|
; 编译器
|
||||||
|
File "..\build\${EXE}"
|
||||||
|
; LLVM 运行时 (编译必须)
|
||||||
|
File "D:\settings\Language\LLVM\bin\LLVM-C.dll"
|
||||||
|
; lld 链接器 (.o -> .exe)
|
||||||
|
File "D:\settings\Language\LLVM\bin\ld.lld.exe"
|
||||||
|
; MinGW 线程运行时 DLL
|
||||||
|
File "D:\settings\Language\C\mingw64\bin\libmcfgthread-2.dll"
|
||||||
|
|
||||||
|
; MinGW 链接库 (自包含,无需用户安装 MinGW)
|
||||||
|
SetOutPath "$INSTDIR\mingw_lib"
|
||||||
|
File "..\mingw_lib\crt2.o"
|
||||||
|
File "..\mingw_lib\crtbegin.o"
|
||||||
|
File "..\mingw_lib\crtend.o"
|
||||||
|
File "..\mingw_lib\libmingw32.a"
|
||||||
|
File "..\mingw_lib\libmcfgthread.a"
|
||||||
|
File "..\mingw_lib\libgcc.a"
|
||||||
|
File "..\mingw_lib\libgcc_eh.a"
|
||||||
|
File "..\mingw_lib\libmoldname.a"
|
||||||
|
File "..\mingw_lib\libmingwex.a"
|
||||||
|
File "..\mingw_lib\libmsvcrt.a"
|
||||||
|
File "..\mingw_lib\libadvapi32.a"
|
||||||
|
File "..\mingw_lib\libshell32.a"
|
||||||
|
File "..\mingw_lib\libuser32.a"
|
||||||
|
File "..\mingw_lib\libkernel32.a"
|
||||||
|
File "..\mingw_lib\libntdll.a"
|
||||||
|
|
||||||
|
; 示例程序
|
||||||
|
SetOutPath "$INSTDIR\examples"
|
||||||
|
File "..\test\programs\01_arithmetic.l"
|
||||||
|
File "..\test\programs\02_if_else.l"
|
||||||
|
File "..\test\programs\04_fib_recursive.l"
|
||||||
|
File "..\test\programs\12_struct.l"
|
||||||
|
File "..\test\programs\17_enum.l"
|
||||||
|
File "..\test\programs\27_named_args.l"
|
||||||
|
File "..\test\programs\28_pipe.l"
|
||||||
|
File "..\test\programs\29_interp.l"
|
||||||
|
|
||||||
|
; 示例说明
|
||||||
|
FileOpen $0 "$INSTDIR\examples\README.txt" w
|
||||||
|
FileWrite $0 "L Language 示例程序$\r$\n"
|
||||||
|
FileWrite $0 "==================$\r$\n$\r$\n"
|
||||||
|
FileWrite $0 "01_arithmetic.l - 基本算术运算$\r$\n"
|
||||||
|
FileWrite $0 "02_if_else.l - if/else 分支$\r$\n"
|
||||||
|
FileWrite $0 "04_fib_recursive.l - 递归斐波那契$\r$\n"
|
||||||
|
FileWrite $0 "12_struct.l - 结构体定义和使用$\r$\n"
|
||||||
|
FileWrite $0 "17_enum.l - 枚举类型$\r$\n"
|
||||||
|
FileWrite $0 "27_named_args.l - 命名参数$\r$\n"
|
||||||
|
FileWrite $0 "28_pipe.l - 管道运算符 |>$\r$\n"
|
||||||
|
FileWrite $0 "29_interp.l - 字符串插值$\r$\n$\r$\n"
|
||||||
|
FileWrite $0 "编译运行:$\r$\n"
|
||||||
|
FileWrite $0 ' "$INSTDIR\${EXE}" 文件名.l -o 程序.exe$\r$\n'
|
||||||
|
FileWrite $0 " 程序.exe$\r$\n"
|
||||||
|
FileClose $0
|
||||||
|
|
||||||
|
; 快速入门 bat
|
||||||
|
FileOpen $0 "$INSTDIR\快速入门.bat" w
|
||||||
|
FileWrite $0 '@echo off$\r$\n'
|
||||||
|
FileWrite $0 'title L Language - 快速入门$\r$\n'
|
||||||
|
FileWrite $0 'echo.$\r$\n'
|
||||||
|
FileWrite $0 'echo ===================================$\r$\n'
|
||||||
|
FileWrite $0 'echo L Language ${VERSION} 快速入门$\r$\n'
|
||||||
|
FileWrite $0 'echo ===================================$\r$\n'
|
||||||
|
FileWrite $0 'echo.$\r$\n'
|
||||||
|
FileWrite $0 'echo 编译并运行字符串插值示例:$\r$\n'
|
||||||
|
FileWrite $0 'echo.$\r$\n'
|
||||||
|
FileWrite $0 '"$INSTDIR\${EXE}" "$INSTDIR\examples\29_interp.l" -o "$INSTDIR\hello.exe"$\r$\n'
|
||||||
|
FileWrite $0 'if %errorlevel% equ 0 ($\r$\n'
|
||||||
|
FileWrite $0 ' echo.$\r$\n'
|
||||||
|
FileWrite $0 ' echo --- 程序输出 ---$\r$\n'
|
||||||
|
FileWrite $0 ' "$INSTDIR\hello.exe"$\r$\n'
|
||||||
|
FileWrite $0 ' echo.$\r$\n'
|
||||||
|
FileWrite $0 ' echo 编译运行成功!$\r$\n'
|
||||||
|
FileWrite $0 ') else ($\r$\n'
|
||||||
|
FileWrite $0 ' echo 编译失败,请检查环境。$\r$\n'
|
||||||
|
FileWrite $0 ')$\r$\n'
|
||||||
|
FileWrite $0 'echo.$\r$\n'
|
||||||
|
FileWrite $0 'pause$\r$\n'
|
||||||
|
FileClose $0
|
||||||
|
|
||||||
|
; 开始菜单
|
||||||
|
CreateDirectory "$SMPROGRAMS\${PRODUCT}"
|
||||||
|
CreateShortCut "$SMPROGRAMS\${PRODUCT}\快速入门.lnk" \
|
||||||
|
"$INSTDIR\快速入门.bat" "" "$INSTDIR\快速入门.bat" 0
|
||||||
|
CreateShortCut "$SMPROGRAMS\${PRODUCT}\示例目录.lnk" \
|
||||||
|
"$INSTDIR\examples" "" "$INSTDIR\examples" 0
|
||||||
|
CreateShortCut "$SMPROGRAMS\${PRODUCT}\卸载.lnk" \
|
||||||
|
"$INSTDIR\uninstall.exe" "" "$INSTDIR\uninstall.exe" 0
|
||||||
|
|
||||||
|
; 控制面板注册
|
||||||
|
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\L Language" \
|
||||||
|
"DisplayName" "${PRODUCT} ${VERSION}"
|
||||||
|
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\L Language" \
|
||||||
|
"UninstallString" "$INSTDIR\uninstall.exe"
|
||||||
|
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\L Language" \
|
||||||
|
"DisplayVersion" "${VERSION}"
|
||||||
|
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\L Language" \
|
||||||
|
"Publisher" "${PUBLISHER}"
|
||||||
|
|
||||||
|
WriteUninstaller "$INSTDIR\uninstall.exe"
|
||||||
|
SectionEnd
|
||||||
|
|
||||||
|
; ── 卸载 ──
|
||||||
|
Section "Uninstall"
|
||||||
|
Delete "$INSTDIR\${EXE}"
|
||||||
|
Delete "$INSTDIR\LLVM-C.dll"
|
||||||
|
Delete "$INSTDIR\ld.lld.exe"
|
||||||
|
Delete "$INSTDIR\libmcfgthread-2.dll"
|
||||||
|
Delete "$INSTDIR\快速入门.bat"
|
||||||
|
Delete "$INSTDIR\uninstall.exe"
|
||||||
|
RMDir /r "$INSTDIR\mingw_lib"
|
||||||
|
RMDir /r "$INSTDIR\examples"
|
||||||
|
RMDir "$INSTDIR"
|
||||||
|
|
||||||
|
Delete "$SMPROGRAMS\${PRODUCT}\*"
|
||||||
|
RMDir "$SMPROGRAMS\${PRODUCT}"
|
||||||
|
|
||||||
|
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\L Language"
|
||||||
|
SectionEnd
|
||||||
+74
-2
@@ -12,6 +12,23 @@
|
|||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// 获取 exe 所在目录(用于定位打包的 MinGW 库)
|
||||||
|
static void get_exe_dir(char* buf, size_t size) {
|
||||||
|
#ifdef _WIN32
|
||||||
|
GetModuleFileNameA(NULL, buf, (DWORD)size);
|
||||||
|
// 反斜杠 → 正斜杠(兼容 MSYS2 和 cmd.exe)
|
||||||
|
for (char* p = buf; *p; p++) if (*p == '\\') *p = '/';
|
||||||
|
char* last = strrchr(buf, '/');
|
||||||
|
if (last) *last = '\0';
|
||||||
|
#else
|
||||||
|
buf[0] = '.'; buf[1] = '\0';
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
// 读取整个文件到内存
|
// 读取整个文件到内存
|
||||||
static char* read_file(const char* path, size_t* size) {
|
static char* read_file(const char* path, size_t* size) {
|
||||||
FILE* f = fopen(path, "rb");
|
FILE* f = fopen(path, "rb");
|
||||||
@@ -137,12 +154,67 @@ int main(int argc, char** argv) {
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 调用 gcc 链接(MinGW 环境可用)
|
// 链接:优先安装包自带的 ld.lld + MinGW 库,fallback gcc
|
||||||
|
int ret = -1;
|
||||||
|
char exe_dir[512];
|
||||||
|
get_exe_dir(exe_dir, sizeof(exe_dir));
|
||||||
|
|
||||||
|
// 1) 优先: 安装包自带的 ld.lld + MinGW 库(CreateProcess 避免 shell 转义)
|
||||||
|
{
|
||||||
|
char ld_path[512], crt2[512], crtbegin[512], crtend[512];
|
||||||
|
char lib_dir[512], out_path[512];
|
||||||
|
snprintf(ld_path, sizeof(ld_path), "%s/ld.lld.exe", exe_dir);
|
||||||
|
snprintf(crt2, sizeof(crt2), "%s/mingw_lib/crt2.o", exe_dir);
|
||||||
|
snprintf(crtbegin, sizeof(crtbegin), "%s/mingw_lib/crtbegin.o", exe_dir);
|
||||||
|
snprintf(crtend, sizeof(crtend), "%s/mingw_lib/crtend.o", exe_dir);
|
||||||
|
snprintf(lib_dir, sizeof(lib_dir), "-L%s/mingw_lib", exe_dir);
|
||||||
|
snprintf(out_path, sizeof(out_path), "-o%s", output);
|
||||||
|
|
||||||
|
const char* ld_args[] = {
|
||||||
|
ld_path, "-m", "i386pep",
|
||||||
|
crt2, crtbegin, obj_path,
|
||||||
|
lib_dir,
|
||||||
|
"-lmingw32", "-lmcfgthread", "-lgcc", "-lgcc_eh",
|
||||||
|
"-lmoldname", "-lmingwex", "-lmsvcrt",
|
||||||
|
"-ladvapi32", "-lshell32", "-luser32", "-lkernel32", "-lntdll",
|
||||||
|
crtend, out_path, NULL
|
||||||
|
};
|
||||||
|
int nargs = sizeof(ld_args) / sizeof(ld_args[0]) - 1;
|
||||||
|
|
||||||
|
// 拼成命令行(CreateProcess 需要)
|
||||||
|
char cmd_line[4096] = {0};
|
||||||
|
char* p = cmd_line;
|
||||||
|
for (int i = 0; i < nargs; i++) {
|
||||||
|
if (i > 0) *p++ = ' ';
|
||||||
|
// 路径含空格则加引号
|
||||||
|
bool has_space = strchr(ld_args[i], ' ') != NULL;
|
||||||
|
if (has_space) *p++ = '"';
|
||||||
|
p += strlen(strcpy(p, ld_args[i]));
|
||||||
|
if (has_space) *p++ = '"';
|
||||||
|
}
|
||||||
|
|
||||||
|
STARTUPINFOA si = { sizeof(si) };
|
||||||
|
PROCESS_INFORMATION pi = {0};
|
||||||
|
if (CreateProcessA(NULL, cmd_line, NULL, NULL, FALSE,
|
||||||
|
CREATE_NO_WINDOW, NULL, NULL, &si, &pi)) {
|
||||||
|
WaitForSingleObject(pi.hProcess, INFINITE);
|
||||||
|
DWORD exit_code;
|
||||||
|
GetExitCodeProcess(pi.hProcess, &exit_code);
|
||||||
|
ret = (int)exit_code;
|
||||||
|
CloseHandle(pi.hProcess);
|
||||||
|
CloseHandle(pi.hThread);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2) 最后 fallback: gcc(开发机有 MinGW 时)
|
||||||
|
if (ret != 0) {
|
||||||
char cmd[1024];
|
char cmd[1024];
|
||||||
snprintf(cmd, sizeof(cmd),
|
snprintf(cmd, sizeof(cmd),
|
||||||
"gcc \"%s\" -o \"%s\"",
|
"gcc \"%s\" -o \"%s\"",
|
||||||
obj_path, output);
|
obj_path, output);
|
||||||
int ret = system(cmd);
|
ret = system(cmd);
|
||||||
|
}
|
||||||
|
|
||||||
if (ret != 0) {
|
if (ret != 0) {
|
||||||
fprintf(stderr, "链接失败 (exit code %d)\n", ret);
|
fprintf(stderr, "链接失败 (exit code %d)\n", ret);
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
Reference in New Issue
Block a user