module - 如何将我的程序划分为模块?

标签 module rust

我在将代码划分为模块时遇到问题,我有很多编译错误,但我已经尝试了一些方法。单文件程序使用四个基本数学运算符 (+-*/) 计算表达式,嵌套或不嵌套。

我是 Rust 的新手,所以我在理解模块系统时遇到了困难,我希望你能帮助我理解它并从头开始做好。

这是代码(所有文件都在 cargo 项目的 src/文件夹中):

运算符.rs

// An attribute to hide warnings for unused code.
#![allow(dead_code)]

pub enum Operator {
    Plus,
    Minus,
    Mul,
    Div,
}

运行时上下文.rs

pub struct RuntimeContext;

token .rs

// An attribute to hide warnings for unused code.
#![allow(dead_code)]

#[derive(Debug, PartialEq)]
pub enum Token {
    IllegalToken, // invalid token, error
    TokPlus, // +
    TokMinus, // -
    TokMul, // *
    TokDiv, // /
    TokOparen, // (
    TokCparen, // )
    TokFloating, // number
    TokEos, // end of string
}

词法分析器

pub use Token;

mod lexer {
    use Token::Token;
    use Token::Token::*;
    use regex::Regex;

    pub fn lexer(input: &str) -> Vec<(Token, Option<f64>)> {
        let re = Regex::new(r"([-+*/)(])|([0-9]+\.[0-9]+)|([0-9]+)").unwrap();
        let mut tokens_and_values: Vec<(Token, Option<f64>)> = Vec::new();
        let mut number: f64;

        for cap in re.captures_iter(&input) {
            let cap1 = cap.get(1);
            let cap2 = cap.get(2);
            let cap3 = cap.get(3);
            if cap1.is_some() {
                tokens_and_values.push((match cap1.unwrap().as_str() {
                                            "+" => Token::TokPlus,
                                            "-" => Token::TokMinus,
                                            "*" => Token::TokMul,
                                            "/" => Token::TokDiv,
                                            "(" => Token::TokOparen,
                                            ")" => Token::TokCparen,
                                            _ => Token::IllegalToken,
                                        },
                                        None));
            } else if cap2.is_some() {
                number = cap2.unwrap().as_str().parse().unwrap();
                tokens_and_values.push((Token::TokFloating, Some(number)));
            } else if cap3.is_some() {
                number = cap3.unwrap().as_str().parse().unwrap();
                tokens_and_values.push((Token::TokFloating, Some(number)));
            }
            //println!("{:?}", cap);
        }
        tokens_and_values.push((TokEos, None));
        tokens_and_values
    }
}

recursive_descent_parser.rs

pub use Token;
pub use Operator;

mod recursive_descent_parser {
    use Token::Token;
    use Token::Token::*;
    use Operator::Operator::*;

    pub fn recursive_descent_parser(input: &str) -> Box<Exp> {
        let tokens_and_values = lexer(&input);
        fn expr(tokens_and_values: &Vec<(Token, Option<f64>)>, mut index: &mut usize) -> Box<Exp> {
            // println!("index = {}", index);
            let term = term(&tokens_and_values, index);

            match tokens_and_values[*index] {
                (TokPlus, None) => {
                    *index += 1;
                    Box::new(BinaryExp {
                        exp1: term,
                        exp2: expr(&tokens_and_values, &mut index),
                        op: Plus,
                    })
                }
                (TokMinus, None) => {
                    *index += 1;
                    Box::new(BinaryExp {
                        exp1: term,
                        exp2: expr(&tokens_and_values, &mut index),
                        op: Minus,
                    })
                }
                _ => term, 
            }
        }

        // <Term> ::= <Factor> | <Factor> {*|/} <Term>
        fn term(tokens_and_values: &Vec<(Token, Option<f64>)>, mut index: &mut usize) -> Box<Exp> {
            // println!("index = {}", index);
            let factor = factor(&tokens_and_values, index);
            //*index += 1;
            match tokens_and_values[*index] {
                (TokMul, None) => {
                    *index += 1;
                    Box::new(BinaryExp {
                        exp1: factor,
                        exp2: term(&tokens_and_values, &mut index),
                        op: Mul,
                    })
                }
                (TokDiv, None) => {
                    *index += 1;
                    Box::new(BinaryExp {
                        exp1: factor,
                        exp2: term(&tokens_and_values, &mut index),
                        op: Div,
                    })
                }
                _ => factor,
            }
        }

        // <Factor>::= <number> | ( <Expr> ) | {+|-} <Factor>
        fn factor(tokens_and_values: &Vec<(Token, Option<f64>)>,
                  mut index: &mut usize)
                  -> Box<Exp> {
            //println!("index = {}", index);

            match tokens_and_values[*index].1 {
                Some(num) => {
                    *index += 1;
                    return Box::new(NumericConstant { value: num });
                }
                None => {}
            };

            //println!("number = {}", number);
            match tokens_and_values[*index] {
                (TokOparen, None) => {
                    // println!("oparen");
                    *index += 1;
                    let result = Box::new(expr(&tokens_and_values, &mut index));

                    if tokens_and_values[*index].0 != TokCparen {
                        println!("unclosed paren");
                    }

                    *index += 1;
                    result
                }
                (TokPlus, None) => {
                    *index += 1;
                    Box::new(UnaryExp {
                        exp1: factor(&tokens_and_values, &mut index),
                        op: Plus,
                    })
                }
                (TokMinus, None) => {
                    *index += 1;
                    Box::new(UnaryExp {
                        exp1: factor(&tokens_and_values, index),
                        op: Minus,
                    })
                }
                _ => return Box::new(NumericConstant { value: 288 as f64 }),
            }
        }
        let mut index = 0;
        expr(&tokens_and_values, &mut index)
    }
}

主要.rs

use Operator;
use Token;
use RuntimeContext;
use lexer;
use recursive_descent_parser;

extern crate regex;
use regex::Regex;

use std::ops::Deref;
use std::cmp::PartialEq;

trait Exp {
    fn evaluate(&self, &mut RuntimeContext) -> f64;
}

impl Exp for Box<Exp> {
    fn evaluate(&self, runtime_context: &mut RuntimeContext) -> f64 {
        self.deref().evaluate(runtime_context)
    }
}

struct NumericConstant {
    value: f64, 
    // marker: PhantomData<T>,
}

impl Exp for NumericConstant {
    fn evaluate(&self, runtime_context: &mut RuntimeContext) -> f64 {
        self.value
    }
}

impl Exp for Box<NumericConstant> {
    fn evaluate(&self, runtime_context: &mut RuntimeContext) -> f64 {
        self.deref().value
    }
}

struct BinaryExp<T: Exp, U: Exp> {
    exp1: T,
    exp2: U,
    op: Operator,
}

impl<T: Exp, U: Exp> Exp for BinaryExp<T, U> {
    fn evaluate(&self, runtime_context: &mut RuntimeContext) -> f64 {
        use Operator::*;
        match self.op {
            Plus => self.exp1.evaluate(runtime_context) + self.exp2.evaluate(runtime_context),
            Minus => self.exp1.evaluate(runtime_context) - self.exp2.evaluate(runtime_context),
            Mul => self.exp1.evaluate(runtime_context) * self.exp2.evaluate(runtime_context),
            Div => self.exp1.evaluate(runtime_context) / self.exp2.evaluate(runtime_context),
        }
    }
}

struct UnaryExp<T: Exp> {
    exp1: T,
    op: Operator,
}

impl<T: Exp> Exp for UnaryExp<T> {
    fn evaluate(&self, runtime_context: &mut RuntimeContext) -> f64 {
        use Operator::*;
        match self.op {
            Minus => -self.exp1.evaluate(runtime_context),
            _ => self.exp1.evaluate(runtime_context),
        }
    }
}

fn main() {
    use Operator::*;

    let expressions = vec!["2+2",
                           "5*10",
                           "(2+5)*10",
                           "(10 + (30 + 50 ))",
                           "(100 / 25)",
                           "(25 * 4 * 8)",
                           "25 * 4 * 8 + 100 / 25",
                           "-2*3+3",
                           "(25 * 4 * 8) + (100 / 25)"];

    for expression in expressions {
        //println!("{}", );
        //println!("{:?}", lexer(&expression));
        let parsed = recursive_descent_parser(expression);
        let mut runtime_context = RuntimeContext;
        let result = parsed.evaluate(&mut runtime_context);
        println!("{} = {}", &expression, result);
    }
}

最佳答案

此时有点乱。我建议从在 src 文件夹中创建一个额外的 lib.rs 文件开始,并在其中声明所有模块和外部 crate:

pub mod operator;
pub mod token;
pub mod runtime_context;
pub mod lexer;
pub mod recursive_descent_parser;

extern crate regex;

注意稍微修改的模块名称(这也适用于它们的文件名);根据 The Rust Book:

Module names follow the conventions for other Rust identifiers: lower_snake_case.

之后您可以在main.rs使用它们。我推荐阅读 The Rust Book 的 chapter on Crates and Modules .

关于module - 如何将我的程序划分为模块?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42091347/

相关文章:

c# - 在模块之间转换枚举

JavaScript 模块

php - 解析错误,期望 activecollab 模型类中出现 `T_PAAMAYIM_NEKUDOTAYIM' 错误

c - 如果静态编译的代码想要访问内核模块代码中的变量,模块必须静态编译吗?

rust - 创建后如何更改 PistonWindow 的分辨率?

python - 用于搜索 mysql 或 postgresql 的库?

rust - 使用 Emscripten 目标从 Rust 创建 web worker

c++ - 如何将 C++ 程序链接到 Rust 程序,然后将该 Rust 程序链接回 C++ 程序? (cpp -> rust -> cpp)

docker - 为什么 setuid 被丢弃在 Alpine 容器中的 execve 上?

rust - 从 rust 封闭返回错误并使类型满意