Skip to content

Instantly share code, notes, and snippets.

@alphaKAI
Last active July 18, 2019 00:27
Show Gist options
  • Save alphaKAI/d38f473a432cb9bde81b51863050467f to your computer and use it in GitHub Desktop.
Save alphaKAI/d38f473a432cb9bde81b51863050467f to your computer and use it in GitHub Desktop.
Stack Machine VM based calculator in Rust
#[derive(Debug, Copy, Clone, PartialEq)]
enum VMIns {
Push(i32),
Add,
Sub,
Mul,
Div,
Println,
}
fn exec(code: &Vec<VMIns>) {
let mut pc = 0;
let mut stack = Vec::new();
loop {
if pc < code.len() {
let ins = code[pc];
match ins {
VMIns::Push(x) => {
stack.push(x);
}
VMIns::Add | VMIns::Sub | VMIns::Mul | VMIns::Div => {
let (y, x) = match (stack.pop(), stack.pop()) {
(Some(y), Some(x)) => (y, x),
_ => panic!("stack is empty"),
};
match ins {
VMIns::Add => stack.push(x + y),
VMIns::Sub => stack.push(x - y),
VMIns::Mul => stack.push(x * y),
VMIns::Div => match y {
0 => panic!("can't divied by zero"),
_ => stack.push(x / y),
},
_ => unreachable!(),
}
}
VMIns::Println => {
let v = stack.pop().unwrap();
println!("{}", v)
}
_ => unreachable!(),
}
pc += 1;
} else {
break;
}
}
}
#[derive(Debug, Copy, Clone, PartialEq)]
enum Token {
Num(i32),
Add,
Sub,
Mul,
Div,
LParen,
RParen,
}
impl Token {
fn to_VMIns(token: Token) -> VMIns {
match token {
Token::Num(x) => VMIns::Push(x),
Token::Add => VMIns::Add,
Token::Sub => VMIns::Sub,
Token::Mul => VMIns::Mul,
Token::Div => VMIns::Div,
_ => unreachable!(),
}
}
fn get_priority(token: Token) -> i32 {
match token {
Token::Add => 1,
Token::Sub => 1,
Token::Mul => 2,
Token::Div => 3,
Token::LParen => 0,
_ => panic!("unknown priority for {:?}", token),
}
}
}
fn parse_number(cs: &Vec<char>, cs_size: usize, i: &mut usize) -> i32 {
let mut tmp = Vec::new();
while *i < cs_size && cs[*i].is_digit(10) {
let c = cs[*i];
tmp.push(c);
*i += 1;
}
let mut s = String::new();
for ch in tmp.iter() {
s.push(*ch);
}
return s.parse().unwrap();
}
fn tokenize(src: String) -> Vec<Token> {
let mut i = 0;
let mut stack = Vec::new();
let cs: Vec<char> = src.chars().collect();
let cs_size = cs.len();
loop {
if !(i < cs_size) {
break;
}
let c = cs[i];
match c {
' ' => i += 1,
'0'..='9' => {
stack.push(Token::Num(parse_number(&cs, cs_size, &mut i)));
}
'+' => {
stack.push(Token::Add);
i += 1;
}
'-' => {
let j = i + 1;
if j < cs_size && cs[j].is_digit(10) {
i += 1;
stack.push(Token::Num(-1 * parse_number(&cs, cs_size, &mut i)));
} else {
stack.push(Token::Sub);
i += 1;
}
}
'*' => {
stack.push(Token::Mul);
i += 1;
}
'/' => {
stack.push(Token::Div);
i += 1;
}
'(' => {
stack.push(Token::LParen);
i += 1;
}
')' => {
stack.push(Token::RParen);
i += 1;
}
_ => panic!("unknown char given {}", c),
}
}
return stack;
}
fn parse_expr(tokens: Vec<Token>) -> Vec<VMIns> {
let mut code = Vec::new();
let mut opstack = Vec::new();
fn proc_op(e: Token, opstack: &mut Vec<Token>, code: &mut Vec<VMIns>) {
if opstack.is_empty() {
opstack.push(e);
} else {
let top = opstack.last().unwrap();
let top_priority = Token::get_priority(*top);
let e_priority = Token::get_priority(e);
if top_priority < e_priority {
opstack.push(e);
} else {
while let Some(top) = opstack.last() {
let top_priority = Token::get_priority(*top);
if top_priority < e_priority {
break;
} else {
code.push(Token::to_VMIns(opstack.pop().unwrap()));
}
}
opstack.push(e);
}
}
}
for &e in tokens.iter() {
match e {
Token::Add | Token::Sub | Token::Mul | Token::Div => {
proc_op(e, &mut opstack, &mut code)
}
Token::Num(_) => code.push(Token::to_VMIns(e)),
Token::RParen => {
while let Some(v) = opstack.pop() {
if v == Token::LParen {
break;
}
code.push(Token::to_VMIns(v));
}
}
Token::LParen => opstack.push(Token::LParen),
}
}
while let Some(e) = opstack.pop() {
code.push(Token::to_VMIns(e))
}
code.push(VMIns::Println);
return code;
}
fn main() {
println!("please input formula : ");
let mut s = String::new();
std::io::stdin()
.read_line(&mut s)
.expect("Failed to read line");
let tokens = tokenize(s.trim().to_string());
let code = parse_expr(tokens);
println!("code : {:?}", code);
exec(&code);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment