开始之前
在写编译器之前,先把项目基本结构搭一下,Rust 创建项目真的非常友好,只要
$ cargo new lox-rs --bin
复制代码
就能创建一个 bin
项目,然后我是直接使用最新的 nightly 版本的 Rust 编译器,因为写这种应用基本上不会碰到啥编译器的 bug,所以可以放心使用 nightly 版。
为了让代码风格统一,先建个 rustfmt.toml,内容不多,其他保持默认,这些要特殊规范一下。
max_width = 120
fn_call_width = 100
tab_spaces = 2
复制代码
等需要提交的时候,用 rustfmt 格式化一下代码。
Cargo.toml 补上几个第三方依赖,还有当前本地的 core 包,里面就是我们需要实现的编译器源码。
[package]
name = "lox-rs"
version = "0.1.0"
edition = "2021"
authors = ["Limit Liu <limitliu@qq.com>"]
[workspace]
[dependencies]
core = { path = "core" }
ansi_term = "0.12"
rustyline = "9.0.0"
getopts = "0.2"
复制代码
最终我们的项目结构长这样
$ tree -L 4
.
├── Cargo.lock
├── Cargo.toml
├── core
│ ├── Cargo.toml
│ └── src
│ ├── common
│ │ └── mod.rs
│ ├── lexer
│ │ └── mod.rs
│ ├── lib.rs
│ └── parser
│ └── mod.rs
├── rustfmt.toml
└── src
├── lib.rs
├── main.rs
├── repl.rs
└── run.rs
6 directories, 12 files
复制代码
ansi_term 包是用于在终端显示颜色的,还有实现语言的 REPL,用上 rustyline 会比较简单,不然就需要自己手动实现诸如方向键之类的操作,非常麻烦,getopts 就是终端命令程序跟参数相关的包。其实现在 Rust 很快要出 edition 2021 了,nightly 已经可以直接使用 edition 2021。
我个人是尽量不用第三方库去实现一些功能的,不过一些终端相关的,细节太多,影响项目主题的学习。像 GC 这块内容,也是有现成的包可用,直接用确实很省事,不过那样就学不到它的实现了,还是自己手撸更有意思。
然后在 main.rs 里面填充内容,现在主要实现得是可以跟终端进行简单的交互
use getopts::Options;
use std::env;
use lox_rs::repl;
use lox_rs::run;
fn print_usage(program: &str, opts: Options) {
let brief = format!(
"Usage: {} [OPTIONS] COMMAND [PARAMS]
Commands:
repl\t\tlaunch repl
run INPUT\t\tlaunch a script file",
program
);
print!("{}", opts.usage(&brief));
}
fn main() {
let args: Vec<String> = env::args().collect();
let program = args.first().unwrap();
let mut opts = Options::new();
opts.optflag("h", "help", "print this help menu");
let matches = opts.parse(&args[1..]).unwrap();
if matches.opt_present("h") || matches.free.is_empty() {
print_usage(program, opts);
return;
}
let command = matches.free[0].as_str();
match command {
"repl" => repl::main(),
"run" => match matches.free.get(1) {
Some(p) => run::main(p),
_ => print_usage(program, opts),
},
_ => print_usage(program, opts),
}
}
复制代码
在 repl.rs 跟 run.rs 里面先暂时这样
// repl
pub fn main() {
println!("The Lox programming language REPL");
}
// run
pub fn main(p: &str) {}
复制代码
现在用 cargo run 一下这个项目,编译通过后,警告先不关注了,commit and push 到 git 托管平台去。
后续把 core 的内容填充后,还要再完善一下 cli 的一些操作。