From a050178c692c59861cb0fb9666321fbef7578039 Mon Sep 17 00:00:00 2001 From: NerdyPepper Date: Thu, 21 Mar 2019 10:54:29 +0530 Subject: refactor into modules --- src/lex/mod.rs | 145 +++++++++++++++++++++++++++++++++ src/main.rs | 241 ++----------------------------------------------------- src/parse/mod.rs | 96 ++++++++++++++++++++++ 3 files changed, 247 insertions(+), 235 deletions(-) create mode 100644 src/lex/mod.rs create mode 100644 src/parse/mod.rs diff --git a/src/lex/mod.rs b/src/lex/mod.rs new file mode 100644 index 0000000..af5ff06 --- /dev/null +++ b/src/lex/mod.rs @@ -0,0 +1,145 @@ +use std::f64; +#[derive(Debug, Copy, Clone, PartialEq)] +pub struct Operator { + token: char, + pub operation: fn(f64, f64) -> f64, + pub precedence: u8, + pub is_left_associative: bool, +} + +impl Operator { + fn token_from_op(token: char, operation: fn(f64, f64) -> f64, precedence: u8, is_left_associative: bool) -> Token { + Token::Operator( + Operator { + token, + operation, + precedence, + is_left_associative + } + ) + } + pub fn operate(self, x: f64, y: f64) -> f64 { + (self.operation)(x, y) + } +} + +#[derive(Debug, Clone, PartialEq)] +pub struct Function { + token: String, + relation: fn(f64) -> f64, +} + +impl Function { + fn token_from_fn(token: String, relation: fn(f64) -> f64) -> Token { + Token::Function( + Function { + token, + relation + } + ) + } + pub fn apply(self, arg: f64) -> f64 { + (self.relation)(arg) + } +} + + +#[derive(Debug, Clone, PartialEq)] +pub enum Token { + Operator(Operator), + Num(f64), + Function(Function), + LParen, + RParen +} + +pub fn lexer(input: &str) -> Result, String> { + let mut num_vec: String = String::new(); + let mut char_vec: String = String::new(); + let mut result: Vec = vec![]; + for letter in input.chars() { + match letter { + '0'...'9' | '.' => { + num_vec.push(letter); + }, + 'a'...'z' | 'A'...'Z' => { + let parse_num = num_vec.parse::().ok(); + if let Some(x) = parse_num { + result.push(Token::Num(x)); + result.push(Operator::token_from_op('*', |x, y| x * y, 3, true)); + num_vec.clear(); + } + char_vec.push(letter); + }, + '+' | '-' | '/' | '*' | '^' => { + let parse_num = num_vec.parse::().ok(); + if let Some(x) = parse_num { + result.push(Token::Num(x)); + num_vec.clear(); + } + let operator_token: Token = match letter { + '+' => Operator::token_from_op('+', |x, y| x + y, 2, true), + '-' => Operator::token_from_op('-', |x, y| x - y, 2, true), + '/' => Operator::token_from_op('/', |x, y| x / y, 3, true), + '*' => Operator::token_from_op('*', |x, y| x * y, 3, true), + '^' => Operator::token_from_op('^', |x, y| x.powf(y), 4, false), + _ => panic!("unexpected op whuuu"), + }; + result.push(operator_token); + }, + '(' => { + if char_vec.len() > 0 { + let funct = char_vec.clone(); + match &funct[..] { + "sin" | "sine" => result.push(Function::token_from_fn("sin".into(), |x| x.to_radians().sin())), + "cos" | "cosine" => result.push(Function::token_from_fn("cos".into(), |x| x.to_radians().cos())), + "tan" | "tangent" => result.push(Function::token_from_fn("tan".into(), |x| x.to_radians().tan())), + "csc" | "cosec" => result.push(Function::token_from_fn("csc".into(), |x| 1f64 / x.to_radians().sin())), + "sec" | "secant" => result.push(Function::token_from_fn("sec".into(), |x| 1f64 / x.to_radians().cos())), + "cot" | "cotangent" => result.push(Function::token_from_fn("cot".into(), |x| 1f64 / x.to_radians().tan())), + "ln" => result.push(Function::token_from_fn("ln".into(), |x| x.ln())), + "log" => result.push(Function::token_from_fn("log".into(), |x| x.log10())), + "sqrt" => result.push(Function::token_from_fn("sqrt".into(), |x| x.sqrt())), + _ => return Err(format!("Unexpected function {}", funct)) + } + char_vec.clear(); + } else { + let parse_num = num_vec.parse::().ok(); + if let Some(x) = parse_num { + result.push(Token::Num(x)); + result.push(Operator::token_from_op('*', |x, y| x * y, 3, true)); + num_vec.clear(); + } + } + + if let Some(x) = result.last() { + match x { + Token::RParen => { + result.push(Operator::token_from_op('*', |x, y| x * y, 3, true)); + }, + _ => {} + }; + } + result.push(Token::LParen); + }, + ')' => { + let parse_num = num_vec.parse::().ok(); + if let Some(x) = parse_num { + result.push(Token::Num(x)); + num_vec.clear(); + } + result.push(Token::RParen); + } + ' ' => {} + _ => { + return Err(format!("Unexpected character: {}", letter)) + } + } + } + let parse_num = num_vec.parse::().ok(); + if let Some(x) = parse_num { + result.push(Token::Num(x)); + num_vec.clear(); + } + Ok(result) +} diff --git a/src/main.rs b/src/main.rs index 71251e2..63d0eb2 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,57 +1,11 @@ +use std::io::{ stdin }; use std::f64; -#[derive(Debug, Copy, Clone, PartialEq)] -pub struct Operator { - token: char, - operation: fn(f64, f64) -> f64, - precedence: u8, - is_left_associative: bool, -} - -#[derive(Debug, Clone, PartialEq)] -pub struct Function { - token: String, - relation: fn(f64) -> f64, -} - -#[derive(Debug, Clone, PartialEq)] -pub enum Token { - Operator(Operator), - Num(f64), - Function(Function), - LParen, - RParen -} - -impl Operator { - fn token_from_op(token: char, operation: fn(f64, f64) -> f64, precedence: u8, is_left_associative: bool) -> Token { - Token::Operator( - Operator { - token, - operation, - precedence, - is_left_associative - } - ) - } - fn operate(self, x: f64, y: f64) -> f64 { - (self.operation)(x, y) - } -} +mod lex; +use crate::lex::*; -impl Function { - fn token_from_fn(token: String, relation: fn(f64) -> f64) -> Token { - Token::Function( - Function { - token, - relation - } - ) - } - fn apply(self, arg: f64) -> f64 { - (self.relation)(arg) - } -} +mod parse; +use crate::parse::*; fn main() { loop { @@ -69,191 +23,8 @@ fn main() { let postfixed = to_postfix(lexed.unwrap()); let evaled = eval_postfix(postfixed.unwrap()); println!("ans: {}", evaled.unwrap()); + println!(); } } -fn lexer(input: &str) -> Result, String> { - let mut num_vec: String = String::new(); - let mut char_vec: String = String::new(); - let mut result: Vec = vec![]; - for letter in input.chars() { - match letter { - '0'...'9' | '.' => { - num_vec.push(letter); - }, - 'a'...'z' | 'A'...'Z' => { - let parse_num = num_vec.parse::().ok(); - if let Some(x) = parse_num { - result.push(Token::Num(x)); - result.push(Operator::token_from_op('*', |x, y| x * y, 3, true)); - num_vec.clear(); - } - char_vec.push(letter); - }, - '+' | '-' | '/' | '*' | '^' => { - let parse_num = num_vec.parse::().ok(); - if let Some(x) = parse_num { - result.push(Token::Num(x)); - num_vec.clear(); - } - let operator_token: Token = match letter { - '+' => Operator::token_from_op('+', |x, y| x + y, 2, true), - '-' => Operator::token_from_op('-', |x, y| x - y, 2, true), - '/' => Operator::token_from_op('/', |x, y| x / y, 3, true), - '*' => Operator::token_from_op('*', |x, y| x * y, 3, true), - '^' => Operator::token_from_op('^', |x, y| x.powf(y), 4, false), - _ => panic!("unexpected op whuuu"), - }; - result.push(operator_token); - }, - '(' => { - if char_vec.len() > 0 { - let funct = char_vec.clone(); - match &funct[..] { - "sin" | "sine" => result.push(Function::token_from_fn("sin".into(), |x| x.to_radians().sin())), - "cos" | "cosine" => result.push(Function::token_from_fn("cos".into(), |x| x.to_radians().cos())), - "tan" | "tangent" => result.push(Function::token_from_fn("tan".into(), |x| x.to_radians().tan())), - "csc" | "cosec" => result.push(Function::token_from_fn("csc".into(), |x| 1f64 / x.to_radians().sin())), - "sec" | "secant" => result.push(Function::token_from_fn("sec".into(), |x| 1f64 / x.to_radians().cos())), - "cot" | "cotangent" => result.push(Function::token_from_fn("cot".into(), |x| 1f64 / x.to_radians().tan())), - "ln" => result.push(Function::token_from_fn("ln".into(), |x| x.ln())), - "log" => result.push(Function::token_from_fn("log".into(), |x| x.log10())), - _ => {} - } - char_vec.clear(); - } else { - let parse_num = num_vec.parse::().ok(); - if let Some(x) = parse_num { - result.push(Token::Num(x)); - result.push(Operator::token_from_op('*', |x, y| x * y, 3, true)); - num_vec.clear(); - } - } - if let Some(x) = result.last() { - match x { - Token::RParen => { - result.push(Operator::token_from_op('*', |x, y| x * y, 3, true)); - }, - _ => {} - }; - } - result.push(Token::LParen); - }, - ')' => { - let parse_num = num_vec.parse::().ok(); - if let Some(x) = parse_num { - result.push(Token::Num(x)); - num_vec.clear(); - } - result.push(Token::RParen); - } - ' ' => {} - _ => { - return Err(format!("Unexpected character: {}", letter)) - } - } - } - let parse_num = num_vec.parse::().ok(); - if let Some(x) = parse_num { - result.push(Token::Num(x)); - num_vec.clear(); - } - Ok(result) -} - -fn to_postfix(tokens: Vec) -> Result, String> { - let mut postfixed: Vec = vec![]; - let mut op_stack: Vec = vec![]; - for token in tokens { - match token { - Token::Num(_) => { - postfixed.push(token); - }, - Token::Function(_) => { - op_stack.push(token); - } - Token::Operator(current_op) => { - while let Some(top_op) = op_stack.last() { - match top_op { - Token::LParen => { - break; - } - Token::Operator(x) => { - let tp = x.precedence; - let cp = current_op.precedence; - if tp > cp || (tp == cp && x.is_left_associative) { - postfixed.push(op_stack.pop().unwrap()); - } else { - break; - } - } - Token::Function(_) => { - postfixed.push(op_stack.pop().unwrap()); - } - _ => { - return Err(format!("{:?} must not be on operator stack", top_op)) - } - } - } - op_stack.push(token); - }, - Token::LParen => { - op_stack.push(token); - }, - Token::RParen => { - let mut push_until_paren: bool = false; - while let Some(token) = op_stack.pop() { - if token == Token::LParen { - push_until_paren = true; - break; - } - postfixed.push(token) - } - if !push_until_paren { - return Err(String::from("Mismatched ')'")); - } - } - - } - } - while let Some(op) = op_stack.pop() { - postfixed.push(op); - } - Ok(postfixed) -} - -fn eval_postfix(postfixed: Vec) -> Result { - let mut num_stack: Vec = vec![]; - for token in postfixed { - match token { - Token::Num(n) => { - num_stack.push(n); - }, - Token::Operator(op) => { - if let Some(n2) = num_stack.pop() { - if let Some(n1) = num_stack.pop() { - num_stack.push(op.operate(n1, n2)) - } else { - return Err(format!("Too many operators, Too little operands")) - } - } else { - return Err(format!("Too many operators, Too little operands")) - } - }, - Token::Function(funct) => { - if let Some(arg) = num_stack.pop() { - num_stack.push(funct.apply(arg)) - } - } - _ => { - return Err(format!("Yo nibba how did this get here")) - } - } - } - if num_stack.len() == 1 { - Ok(num_stack.pop().unwrap()) - } else { - Err(format!("Parser Error")) - } -} diff --git a/src/parse/mod.rs b/src/parse/mod.rs new file mode 100644 index 0000000..e5c28e6 --- /dev/null +++ b/src/parse/mod.rs @@ -0,0 +1,96 @@ +use crate::lex::Token; + +pub fn to_postfix(tokens: Vec) -> Result, String> { + let mut postfixed: Vec = vec![]; + let mut op_stack: Vec = vec![]; + for token in tokens { + match token { + Token::Num(_) => { + postfixed.push(token); + }, + Token::Function(_) => { + op_stack.push(token); + } + Token::Operator(current_op) => { + while let Some(top_op) = op_stack.last() { + match top_op { + Token::LParen => { + break; + } + Token::Operator(x) => { + let tp = x.precedence; + let cp = current_op.precedence; + if tp > cp || (tp == cp && x.is_left_associative) { + postfixed.push(op_stack.pop().unwrap()); + } else { + break; + } + } + Token::Function(_) => { + postfixed.push(op_stack.pop().unwrap()); + } + _ => { + return Err(format!("{:?} must not be on operator stack", top_op)) + } + } + } + op_stack.push(token); + }, + Token::LParen => { + op_stack.push(token); + }, + Token::RParen => { + let mut push_until_paren: bool = false; + while let Some(token) = op_stack.pop() { + if token == Token::LParen { + push_until_paren = true; + break; + } + postfixed.push(token) + } + if !push_until_paren { + return Err(String::from("Mismatched ')'")); + } + } + } + } + while let Some(op) = op_stack.pop() { + postfixed.push(op); + } + Ok(postfixed) +} + +pub fn eval_postfix(postfixed: Vec) -> Result { + let mut num_stack: Vec = vec![]; + for token in postfixed { + match token { + Token::Num(n) => { + num_stack.push(n); + }, + Token::Operator(op) => { + if let Some(n2) = num_stack.pop() { + if let Some(n1) = num_stack.pop() { + num_stack.push(op.operate(n1, n2)) + } else { + return Err(format!("Too many operators, Too little operands")) + } + } else { + return Err(format!("Too many operators, Too little operands")) + } + }, + Token::Function(funct) => { + if let Some(arg) = num_stack.pop() { + num_stack.push(funct.apply(arg)) + } + } + _ => { + return Err(format!("Yo nibba how did this get here")) + } + } + } + if num_stack.len() == 1 { + Ok(num_stack.pop().unwrap()) + } else { + Err(format!("Parser Error")) + } +} -- cgit v1.2.3