From 70aeb26181577cae1ff4acb30d3244b235e2b477 Mon Sep 17 00:00:00 2001 From: car Date: Sat, 14 Mar 2026 14:29:03 -0400 Subject: initial --- src/main.rs | 124 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 src/main.rs (limited to 'src/main.rs') diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..0bb1740 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,124 @@ +#[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); +} -- cgit v1.2.3