#[derive(Debug, PartialEq)] enum Token { Number(f64), Operator(char), Function(String), Variable(String), RightParen, LeftParen } #[derive(Debug, PartialEq)] enum TokenizerError { TooManyDots(String), ConstantNotFound(String), BadCharacter(char) } fn str_to_const(s: &str) -> Option { match s { "PI" => Some(std::f64::consts::PI), "E" => Some(std::f64::consts::E), _ => None } } fn tokenize(input: &str) -> Result, TokenizerError> { let mut tokens = Vec::new(); let mut chars = input.chars().peekable(); while let Some(&ch) = chars.peek() { match ch { '0'..='9' => { let mut num = String::new(); let mut has_dot = false; while let Some(&c) = chars.peek() { if c.is_ascii_digit() || (c == '.' && !has_dot) { num.push(c); chars.next(); has_dot |= c == '.'; } else if c == '.' && has_dot { return Err(TokenizerError::TooManyDots(num)); } else { break; } } tokens.push(Token::Number(num.parse().unwrap())); } '+' | '-' | '*' | '/' | '%' | '^' => { chars.next(); tokens.push(Token::Operator(ch)); } 'a'..='z' | '_' => { let mut pt: Option = None; let mut s = String::new(); while let Some(&c) = chars.peek() { match c { 'a'..='z' | 'A'..='Z' | '0'..='9' | '_' => { s.push(c); chars.next(); } '(' => { pt = Some(Token::Function(s.clone())); break; } _ => { break; } } } tokens.push(match pt { Some(token) => token, None => Token::Variable(s.clone()) }); } 'A'..='Z' => { let mut s = String::new(); while let Some(&c @ ('A'..='Z' | '_')) = chars.peek() { s.push(c); chars.next(); } let n = str_to_const(&s).ok_or(TokenizerError::ConstantNotFound(s))?; tokens.push(Token::Number(n)); } c if c.is_whitespace() || c == ',' => { while let Some(&c) = chars.peek() { if c.is_whitespace() { chars.next(); } else { break; } } } '(' => { chars.next(); tokens.push(Token::RightParen); } ')' => { chars.next(); tokens.push(Token::LeftParen); } _ => { return Err(TokenizerError::BadCharacter(ch)); } } } Ok(tokens) } fn main() { let input = "x + 4 * (3 - sin((y+PI)) / 2.123)^2"; println!("{}", input); let tokens = tokenize(input).unwrap(); println!("{:#?}", tokens); }