Rust词法分析器库lrlex的使用:高效构建自定义编程语言解析工具

Rust词法分析器库lrlex的使用:高效构建自定义编程语言解析工具

lrlexlex/flex的部分替代品。它接受一个输入字符串并根据.l文件将其分割成词素(lexemes)。虽然许多现实世界的语言有超出lrlex能力的特殊情况,但当适用时,它是表达词法分析的非常便捷的方式。

示例使用

lrlex提供了一个简单的命令行界面,可以检查你的词法规则是否如预期工作:

$ cat C.java
class C {
    int x = 0;
}
$ cargo run --lrlex java.l /tmp/C.java
    Finished dev [unoptimized + debuginfo] target(s) in 0.18s
     Running `target/debug/lrlex ../grammars/java7/java.l /tmp/C.java`
CLASS class
IDENTIFIER C
LBRACE {
INT int
IDENTIFIER x
EQ =
INTEGER_LITERAL 0
SEMICOLON ;
RBRACE }

完整示例

下面是一个完整的示例,展示如何使用lrlex构建一个简单的词法分析器:

  1. 首先添加依赖到Cargo.toml:
lrlex = "0.13.10"
lrpar = "0.13.10"
  1. 创建词法规则文件calc.l
%%
[0-9]+ "INTEGER"  // 匹配数字并标记为INTEGER
\+ "ADD"          // 匹配加号并标记为ADD
\* "MUL"          // 匹配乘号并标记为MUL
\( "LPAR"         // 匹配左括号并标记为LPAR
\) "RPAR"         // 匹配右括号并标记为RPAR
[\ \t\n]+ ;       // 忽略空格、制表符和换行符
  1. 创建解析规则文件calc.y
%%
start: i64;  // 起始规则返回i64类型

// 表达式规则
Expr: i64 = { 
      Term '+' Term => Ok($1? + $3?),  // 加法运算
      Term } ;                         // 或单个Term

// 项规则
Term: i64 = {
      Factor '*' Factor => Ok($1? * $3?),  // 乘法运算
      Factor } ;                          // 或单个Factor

// 因子规则
Factor: i64 = {
      'INTEGER' => Ok($1.parse().unwrap()),  // 解析整数
      '(' Expr ')' => Ok($2?) } ;            // 或括号表达式
  1. 主程序main.rs
use lrlex::lrlex_mod;
use lrpar::lrpar_mod;

// 使用lrlex_mod!和lrpar_mod!宏生成词法分析器和解析器模块
lrlex_mod!("calc.l");  // 生成calc_l模块
lrpar_mod!("calc.y");  // 生成calc_y模块

fn main() {
    // 获取词法分析器定义和解析器
    let lexerdef = calc_l::lexerdef();
    let parser = calc_y::parser();
    
    // 输入表达式
    let input = "2 + 3 * (4 + 5)";
    
    // 词法分析
    let lexer = lexerdef.lexer(&input);
    // 解析并获取结果和错误
    let (res, errs) = parser.parse(&lexer);
    
    // 处理错误
    for e in errs {
        println!("{}", e.pp(&lexer, &calc_y::token_epp));
    }
    
    // 处理结果
    match res {
        Some(Ok(r)) => println!("计算结果: {}", r),
        _ => println!("无法计算表达式")
    }
}

这个示例展示了如何:

  1. 定义简单的算术表达式词法规则
  2. 创建相应的解析规则
  3. 在Rust程序中使用生成的词法分析器和解析器
  4. 处理输入表达式并输出计算结果

lrlex特别适合需要快速构建原型或处理相对简单语法的场景,它能够大大简化词法分析器的开发工作。


1 回复

Rust词法分析器库lrlex的使用:高效构建自定义编程语言解析工具

以下是基于提供内容整理的完整示例demo,展示如何使用lrlex构建一个简单的计算器解析器:

完整示例代码

1. 项目结构

calculator/
├── Cargo.toml
├── src/
│   ├── main.rs
├── calc.l  # 词法规则文件
└── calc.y  # 语法规则文件

2. Cargo.toml配置

[package]
name = "calculator"
version = "0.1.0"
edition = "2021"

[dependencies]
lrlex = "0.7.0"
lrpar = "0.7.0"

3. calc.l 词法规则文件

%[%
use std::str::FromStr;
%]%

%%
[0-9]+    "INT"   => Ok(Some(YaccLexValue::new(i64::from_str(yytext).unwrap())))
"+"       "PLUS"  => Ok(Some(YaccLexValue::new(())))
"-"       "MINUS" => Ok(Some(YaccLexValue::new(())))
"*"       "MUL"   => Ok(Some(YaccLexValue::new(())))
"/"       "DIV"   => Ok(Some(YaccLexValue::new(())))
"("       "LPAR"  => Ok(Some(YaccLexValue::new(())))
")"       "RPAR"  => Ok(Some(YaccLexValue::new(())))
[\t\n ]+          => Ok(None)  // 忽略空白字符
.                 => Err(lex::LexError::new(yytext.to_owned()))  // 其他字符报错
%%

4. calc.y 语法规则文件

%start Expr
%avoid_insert "INT"

%%
Expr -> Result<i64, ()>:
      Expr 'PLUS' Term { Ok($1? + $3?) }
    | Expr 'MINUS' Term { Ok($1? - $3?) }
    | Term { $1 }
    ;

Term -> Result<i64, ()>:
      Term 'MUL' Factor { Ok($1? * $3?) }
    | Term 'DIV' Factor { Ok($1? / $3?) }
    | Factor { $1 }
    ;

Factor -> Result<i64, ()>:
      'LPAR' Expr 'RPAR' { $2 }
    | 'INT' { Ok($1) }
    ;
%%

5. src/main.rs 主程序

use lrlex::lrlex_mod;
use lrpar::lrpar_mod;

// 生成词法分析器和解析器模块
lrlex_mod!("calc.l");
lrpar_mod!("calc.y");

use calc_lex::Lexer;
use calc_y::parse;

fn main() {
    // 示例输入表达式
    let inputs = vec![
        "1 + 2 * 3",
        "(4 + 5) * 6",
        "10 / 2 - 3",
        "2 * (3 + 4)",
    ];

    for input in inputs {
        println!("计算表达式: {}", input);
        
        // 创建词法分析器
        let lexer = Lexer::new(input);
        
        // 解析表达式
        let res = parse(lexer);
        
        // 处理解析结果
        match res {
            Ok(Some(val)) => println!("结果: {}\n", val),
            Ok(None) => println!("错误: 没有输入\n"),
            Err(e) => println!("解析错误: {:?}\n", e),
        }
    }
}

6. 构建和运行

  1. 在项目目录下运行:
cargo build
cargo run
  1. 预期输出示例:
计算表达式: 1 + 2 * 3
结果: 7

计算表达式: (4 + 5) * 6
结果: 54

计算表达式: 10 / 2 - 3
结果: 2

计算表达式: 2 * (3 + 4)
结果: 14

关键点说明

  1. 词法分析器(calc.l)

    • 定义了数字、运算符和括号的识别规则
    • 使用正则表达式匹配各种词法单元
    • 对匹配到的文本进行转换(如将字符串数字转为i64)
  2. 语法分析器(calc.y)

    • 定义了表达式的语法结构
    • 处理运算符优先级(乘除高于加减)
    • 支持括号改变运算顺序
  3. 错误处理

    • 词法分析阶段会报告无法识别的字符
    • 语法分析阶段会报告语法错误

这个完整示例展示了如何使用lrlex和lrpar构建一个功能完整的计算器,包括词法分析、语法分析和表达式求值。开发者可以基于此框架扩展更复杂的语言特性。

回到顶部