JavaCC:Token Manager
JavaCC的词法解析被转化为一组词法状态,每个状态都有一个唯一的标识符用于命名。Token Manager(生成的代码)在运行时总是处于状态之一,默认的一个词法状态是DEFAULT。当Token Manager初始化时,默认情况下是以DEFAULT状态开始。也可以在Token Manager 构造时,指定起始词法状态1。
JavaCC的词法解析被转化为一组词法状态,每个状态都有一个唯一的标识符用于命名。Token Manager(生成的代码)在运行时总是处于状态之一,默认的一个词法状态是DEFAULT。当Token Manager初始化时,默认情况下是以DEFAULT状态开始。也可以在Token Manager 构造时,指定起始词法状态1。
上一篇文章我们简单介绍了 JavaCC的语法和使用。本文将以实现一个计算器为例,介绍JavaCC 在实际代码中的使用。
JavaCC 是 java 生态中常用的Parser Generator。特征如下:
JavaCC的工作流程如下:

假设我有两个 github 账号,victor(for personal) 和 superman(for work)。如果我想在同一台电脑上使用这两个账号进行 git push/pull。该如何配置?
如何在 Rust 的多线程中共享值?
ArcMutexRust 既支持了基于系统线程的多线程编程模型,也支持了基于async/await的异步编程模型。Rust 的async编程有有以下特性:
本文将介绍如果基于 vscode 搭建 Rust 开发环境。
先来看一段 Java 代码,Application中有version和 logger。logger 依赖了 Version。
public class Application
{
public Version version;
public Logger logger;
public Application() {
version = new Version(1);
logger = new Logger(version);
}
public static void main(String[] args)
{
Application application = new Application();
application.logger.log("Hello World!");
// console output:
// [version 1] Hello World!
}
class Version {
public int ver;
public Version (int ver){
this.ver = ver;
}
public String toString() {
return String.format("version %d",ver);
}
}
class Logger {
public Version version;
public Logger (Version version){
this.version = version;
}
void log(String msg) {
System.out.println(String.format("[%s] %s",version,msg));
}
}
}那么问题来了,如何在 Rust 中实现相同的代码?
生命周期,简而言之就是引用的有效作用域。在大多数时候,我们无需手动的声明生命周期,因为编译器可以自动进行推导。当多个生命周期存在,且编译器无法推导出某个引用的生命周期时,就需要我们手动标明生命周期。
生命周期的主要作用是避免悬垂引用,它会导致程序引用了本不该引用的数据:
{
let r;
{
let x = 5;
r = &x;
} // ^^ borrowed value does not live long enough
println!("r: {}", r);
}此处 r 就是一个悬垂指针,它引用了提前被释放的变量 x。
为了保证 Rust 的所有权和借用的正确性,Rust 使用了一个借用检查器(Borrow checker),来检查我们程序的借用正确性:
{
let r; // ---------+-- 'a
// |
{ // |
let x = 5; // -+-- 'b |
r = &x; // | |
} // -+ |
// |
println!("r: {}", r); // |
} // ---------+
r 变量被赋予了生命周期 ‘a,x 被赋予了生命周期 ‘b,从图示上可以明显看出生命周期 ‘b 比 ‘a 小很多。在编译期,Rust 会比较两个变量的生命周期,结果发现 r 明明拥有生命周期 ‘a,但是却引用了一个小得多的生命周期 ‘b,在这种情况下,编译器会认为我们的程序存在风险,因此拒绝运行。如果想要编译通过,也很简单,只要 ‘b 比 ‘a 大就好。总之,x 变量只要比 r 活得久,那么 r 就能随意引用 x 且不会存在危险:
{
let x = 5; // ----------+-- 'b
// |
let r = &x; // --+-- 'a |
// | |
println!("r: {}", r); // | |
// --+ |
} // ----------+