Skip to content

Instantly share code, notes, and snippets.

@zesterer
Created January 25, 2019 16:08
Show Gist options
  • Save zesterer/0e1b2dd30cdccd09dc812cec6341fa94 to your computer and use it in GitHub Desktop.
Save zesterer/0e1b2dd30cdccd09dc812cec6341fa94 to your computer and use it in GitHub Desktop.
RPN Interpreter
#[derive(Debug)]
enum Error {
InvalidToken(String),
InvalidProgram,
}
#[derive(Debug)]
enum Token {
Add,
Sub,
Mul,
Div,
Number(i32),
}
fn lex(code: &str) -> Result<Vec<Token>, Error> {
let mut tokens = vec![];
for substring in code
.split(' ')
.filter(|s| s.len() > 0)
{
match substring {
"+" => tokens.push(Token::Add),
"-" => tokens.push(Token::Sub),
"*" => tokens.push(Token::Mul),
"/" => tokens.push(Token::Div),
n => if let Ok(n) = n.parse::<i32>() {
tokens.push(Token::Number(n));
} else {
return Err(Error::InvalidToken(substring.to_owned()));
},
}
}
Ok(tokens)
}
fn eval(tokens: &[Token]) -> Result<(i32, usize), Error> {
if let Some(first_token) = tokens.first() {
match first_token {
Token::Add => {
let (a, a_skip) = eval(&tokens[1..])?;
let (b, b_skip) = eval(&tokens[1 + a_skip..])?;
Ok((a + b, 1 + a_skip + b_skip))
},
Token::Sub => {
let (a, a_skip) = eval(&tokens[1..])?;
let (b, b_skip) = eval(&tokens[1 + a_skip..])?;
Ok((a - b, 1 + a_skip + b_skip))
},
Token::Mul => {
let (a, a_skip) = eval(&tokens[1..])?;
let (b, b_skip) = eval(&tokens[1 + a_skip..])?;
Ok((a * b, 1 + a_skip + b_skip))
},
Token::Div => {
let (a, a_skip) = eval(&tokens[1..])?;
let (b, b_skip) = eval(&tokens[1 + a_skip..])?;
Ok((a / b, 1 + a_skip + b_skip))
},
Token::Number(n) => Ok((*n, 1)),
}
} else {
Err(Error::InvalidProgram)
}
}
fn main() {
let s = "- + 5 * 8 12 * 42 2";
let tokens = lex(s).unwrap();
println!("Tokens: {:?}", tokens);
let result = eval(&tokens);
println!("Result: {:?}", result);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment