2017-02-07 11 views
0

У меня проблемы с делением моего кода на модули, у меня много ошибок компиляции, но я что-то пробовал. Одна файловая программа работает и оценивает выражения с четырьмя основными математическими операторами (+ - * /), вложенными в круглые скобки или нет.Как разделить мою программу в модулях?

Я новичок в Rust, поэтому у меня возникли проблемы с пониманием модульной системы, и я хочу, чтобы вы помогли мне понять это и сделать это хорошо с самого начала.

Вот код (все файлы находятся в папке/Src проекта груза):

Operator.rs

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

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

RuntimeContext.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 
} 

lexer.rs

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) 
    } 
} 

main.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); 
    } 
} 

ответ

4

На данный момент это немного беспорядок. Я бы рекомендовал начать с созданием дополнительного lib.rs файла в папке src и объявить все модули и внешние ящики в нем:

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

extern crate regex; 

внимание на слегка измененные имена модулей (это также относится и к именам файлов); в соответствии с ржавчиной книги:

имена модулей следуют соглашениям для других идентификаторов Rust: lower_snake_case.

Впоследствии вы можете просто use их в своем main.rs. Я рекомендую прочитать «Книга ржавчины» chapter on Crates and Modules.

 Смежные вопросы

  • Нет связанных вопросов^_^