Rust语法分析库garando_syntax的使用,提供高效语法解析与代码生成功能

以下是关于Rust语法分析库garando_syntax的使用说明和示例:

garando_syntax是Rust编译器相关库的稳定版本移植,包含以下组件:

  • libsyntax => garando_syntax
  • libsyntax_pos => garando_pos
  • librustc_errors => garando_errors

该库可以在最新的稳定版Rust上使用。

安装方法:

  1. 在项目目录中运行以下Cargo命令:
cargo add garando_syntax
  1. 或者在Cargo.toml中添加:
garando_syntax = "0.1.1"

许可证:

  • Apache License 2.0
  • MIT license

完整示例代码:

use garando_syntax::parse;
use garando_syntax::source_map::FileName;
use garando_syntax::ast;
use garando_syntax::visit::Visitor;

// 定义AST访问者结构体
struct MyVisitor;

impl Visitor for MyVisitor {
    // 访问函数定义
    fn visit_fn(&mut self, f: &ast::FnDecl, s: Span, _: &ast::Ident) {
        println!("Found function at span: {:?}", s);
        // 在这里可以处理函数定义的AST节点
    }
}

fn main() {
    // 要分析的Rust代码
    let code = r#"
        fn hello_world() {
            println!("Hello, world!");
        }
    "#;
    
    // 创建文件名标识
    let filename = FileName::Custom("example.rs".to_string());
    
    // 解析代码
    let krate = parse::parse_crate_from_source_str(filename, code.to_string())
        .expect("Failed to parse code");
    
    // 创建访问者并遍历AST
    let mut visitor = MyVisitor;
    visitor.visit_crate(&krate);
    
    // 代码生成示例
    // 这里可以使用garando_syntax的API生成新的AST节点
    // 然后使用相关功能输出为Rust代码
}

这个示例展示了:

  1. 如何使用garando_syntax解析Rust代码
  2. 如何创建AST访问者来遍历和分析代码
  3. 基本的AST操作模式

下面是更完整的示例代码,展示了更多功能:

use garando_syntax::parse;
use garando_syntax::source_map::{FileName, Span};
use garando_syntax::ast;
use garando_syntax::visit::{self, Visitor};
use garando_syntax::print::pprust;

// 自定义访问者结构体
struct CodeAnalyzer {
    function_count: usize,
    variable_count: usize,
}

impl Visitor for CodeAnalyzer {
    // 访问函数定义
    fn visit_fn(&mut self, f: &ast::FnDecl, _: Span, _: &ast::Ident) {
        self.function_count += 1;
        visit::walk_fn(self, f);
    }
    
    // 访问变量声明
    fn visit_local(&mut self, l: &ast::Local) {
        self.variable_count += 1;
        visit::walk_local(self, l);
    }
}

fn main() {
    // 要分析的Rust代码
    let code = r#"
        fn main() {
            let x = 5;
            let y = 10;
            println!("Sum: {}", x + y);
        }
        
        fn helper() -> i32 {
            42
        }
    "#;
    
    // 解析代码
    let filename = FileName::Custom("analysis.rs".to_string());
    let krate = parse::parse_crate_from_source_str(filename, code.to_string())
        .expect("解析代码失败");
    
    // 创建分析器并遍历AST
    let mut analyzer = CodeAnalyzer {
        function_count: 0,
        variable_count: 0,
    };
    analyzer.visit_crate(&krate);
    
    println!("分析结果:");
    println!("函数数量: {}", analyzer.function_count);
    println!("变量数量: {}", analyzer.variable_count);
    
    // 代码生成示例
    let new_fn = ast::Item {
        ident: ast::Ident::from_str("generated_fn"),
        attrs: Vec::new(),
        id: ast::DUMMY_NODE_ID,
        node: ast::ItemKind::Fn(
            ast::FnDecl {
                inputs: Vec::new(),
                output: ast::FunctionRetTy::Default(ast::DUMMY_SP),
                variadic: false,
            },
            ast::Generics::default(),
            ast::Block {
                stmts: vec![
                    ast::Stmt {
                        id: ast::DUMMY_NODE_ID,
                        node: ast::StmtKind::Expr(ast::Expr {
                            id: ast::DUMMY_NODE_ID,
                            node: ast::ExprKind::Lit(ast::Lit {
                                token: ast::token::Lit {
                                    kind: ast::token::LitKind::Integer,
                                    symbol: "42".into(),
                                    suffix: None,
                                },
                                span: ast::DUMMY_SP,
                            }),
                            span: ast::DUMMY_SP,
                            attrs: ast::AttrVec::new(),
                        }),
                        span: ast::DUMMY_SP,
                    },
                ],
                id: ast::DUMMY_NODE_ID,
                rules: ast::BlockCheckMode::Default,
                span: ast::DUMMY_SP,
                recovered: false,
            },
            ast::DUMMY_SP,
        ),
        vis: ast::Visibility::Inherited,
        span: ast::DUMMY_SP,
        tokens: None,
    };
    
    println!("\n生成的函数代码:");
    println!("{}", pprust::item_to_string(&new_fn));
}

这个完整示例展示了:

  1. 更复杂的AST访问者实现
  2. 代码统计功能
  3. AST节点的构建和代码生成
  4. 使用pprust打印生成的代码

1 回复

garando_syntax - Rust高效语法解析与代码生成库

简介

garando_syntax 是一个用于 Rust 的语法分析库,专注于提供高效的语法解析和代码生成功能。它特别适合构建编译器、解释器、代码转换工具和其他需要语法分析能力的应用程序。

主要特性

  • 高性能的语法解析能力
  • 灵活的抽象语法树(AST)构建
  • 代码生成功能
  • 易于扩展的语法规则
  • 良好的错误报告机制

安装

在 Cargo.toml 中添加依赖:

[dependencies]
garando_syntax = "0.1.0"  # 请使用最新版本

完整示例

下面是一个完整的数学表达式解析和计算示例:

use garando_syntax::{Grammar, Parser, Rule, ast::{AST, ASTVisitor}};
use std::fmt;

// 定义自定义AST节点类型
#[derive(Debug, Clone)]
enum ExprNode {
    Number(f64),
    BinaryOp(String, Box<ExprNode>, Box<ExprNode>),
}

impl ASTNode for ExprNode {
    fn kind(&self) -> ASTKind {
        match self {
            ExprNode::Number(_) => ASTKind::Terminal,
            ExprNode::BinaryOp(_, _, _) => ASTKind::NonTerminal,
        }
    }
}

impl fmt::Display for ExprNode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        match self {
            ExprNode::Number(n) => write!(f, "{}", n),
            ExprNode::BinaryOp(op, left, right) => {
                write!(f, "({} {} {})", left, op, right)
            }
        }
    }
}

// 定义计算器Visitor
struct Calculator;

impl ASTVisitor<f64> for Calculator {
    fn visit(&mut self, node: &AST) -> f64 {
        match node.downcast_ref::<ExprNode>() {
            Some(ExprNode::Number(n)) => *n,
            Some(ExprNode::BinaryOp(op, left, right)) => {
                let left_val = self.visit(left);
                let right_val = self.visit(right);
                match op.as_str() {
                    "+" => left_val + right_val,
                    "-" => left_val - right_val,
                    "*" => left_val * right_val,
                    "/" => left_val / right_val,
                    _ => panic!("未知操作符: {}", op),
                }
            }
            None => panic!("未知节点类型"),
        }
    }
}

fn main() {
    // 定义数学表达式语法
    let grammar = Grammar::new()
        .rule(Rule::new("expression")
            .production(["term", "+", "expression"])
            .production(["term", "-", "expression"])
            .production(["term"]))
        .rule(Rule::new("term")
            .production(["factor", "*", "term"])
            .production(["factor", "/", "term"])
            .production(["factor"]))
        .rule(Rule::new("factor")
            .production(["(", "expression", ")"])
            .production(["number"]));

    // 创建解析器
    let parser = Parser::new(grammar);
    let input = "3 + 4 * (2 - 1)";
    
    // 解析输入
    match parser.parse(input) {
        Ok(ast) => {
            println!("解析成功,生成的AST: {}", ast);
            
            // 计算表达式值
            let mut calculator = Calculator;
            let result = calculator.visit(&ast);
            println!("计算结果: {} = {}", input, result);
        },
        Err(e) => println!("解析错误: {}", e),
    }
}

代码说明

  1. AST节点定义:定义了ExprNode枚举来表示表达式节点,包含数字和二元操作两种类型。

  2. ASTNode实现:为ExprNode实现了ASTNode trait,指定节点类型(终结符或非终结符)。

  3. Visitor模式:实现了Calculator结构体作为Visitor,用于遍历AST并计算表达式值。

  4. 语法规则:定义了基本的数学表达式语法,支持加减乘除和括号优先级。

  5. 解析流程

    • 创建语法规则
    • 初始化解析器
    • 解析输入字符串
    • 成功时计算表达式值

这个示例展示了garando_syntax库的核心功能,包括语法定义、解析输入、构建AST和使用Visitor模式处理AST。

回到顶部