286 lines
6.9 KiB
Rust
286 lines
6.9 KiB
Rust
use std::io::stdin;
|
|
|
|
#[derive(Debug, Clone, Copy)]
|
|
enum Token {
|
|
NUM(usize),
|
|
PLUS,
|
|
TIMES,
|
|
MINUS,
|
|
DIV,
|
|
EQUAL,
|
|
Err,
|
|
}
|
|
|
|
impl ToString for Token {
|
|
fn to_string(&self) -> String {
|
|
match self {
|
|
Token::NUM(x) => x.to_string(),
|
|
Token::PLUS => "+".to_string(),
|
|
Token::MINUS => "-".to_string(),
|
|
Token::TIMES => "x".to_string(),
|
|
Token::DIV => "/".to_string(),
|
|
Token::EQUAL => "=".to_string(),
|
|
Token::Err => "Err".to_string(),
|
|
}
|
|
}
|
|
}
|
|
|
|
fn convert(num: i64) -> String {
|
|
let mut s = String::new();
|
|
for ch in num.to_string().chars() {
|
|
match ch {
|
|
'0' => s.push_str("ZERO"),
|
|
'1' => s.push_str("ONE"),
|
|
'2' => s.push_str("TWO"),
|
|
'3' => s.push_str("THREE"),
|
|
'4' => s.push_str("FOUR"),
|
|
'5' => s.push_str("FIVE"),
|
|
'6' => s.push_str("SIX"),
|
|
'7' => s.push_str("SEVEN"),
|
|
'8' => s.push_str("EIGHT"),
|
|
'9' => s.push_str("NINE"),
|
|
'-' => s.push('-'),
|
|
_ => panic!("Invalid Number"),
|
|
}
|
|
}
|
|
s
|
|
}
|
|
|
|
fn priority(tok: Token) -> usize {
|
|
match tok {
|
|
Token::NUM(_) => 0,
|
|
Token::PLUS | Token::MINUS => 1,
|
|
Token::TIMES | Token::DIV => 2,
|
|
Token::EQUAL => 3,
|
|
Token::Err => 100,
|
|
}
|
|
}
|
|
|
|
#[allow(unused_assignments)]
|
|
fn lex(s: String) -> Option<Vec<Token>> {
|
|
let mut lexed = vec![];
|
|
|
|
let mut iter = s.chars();
|
|
let mut curr: char = '\n';
|
|
let mut next: char = '\n';
|
|
curr = iter.next().unwrap();
|
|
next = iter.next().unwrap();
|
|
|
|
let mut skip = 0;
|
|
loop {
|
|
if skip <= 0 {
|
|
let mut tok = Token::Err;
|
|
match (curr, next) {
|
|
('\n', _) => {
|
|
break;
|
|
}
|
|
('O', 'N') => {
|
|
skip = 3;
|
|
tok = Token::NUM(1);
|
|
}
|
|
('T', 'W') => {
|
|
skip = 3;
|
|
tok = Token::NUM(2);
|
|
}
|
|
('T', 'H') => {
|
|
skip = 5;
|
|
tok = Token::NUM(3);
|
|
}
|
|
('F', 'O') => {
|
|
skip = 4;
|
|
tok = Token::NUM(4);
|
|
}
|
|
('F', 'I') => {
|
|
skip = 4;
|
|
tok = Token::NUM(5);
|
|
}
|
|
('S', 'I') => {
|
|
skip = 3;
|
|
tok = Token::NUM(6);
|
|
}
|
|
('S', 'E') => {
|
|
skip = 5;
|
|
tok = Token::NUM(7);
|
|
}
|
|
('E', 'I') => {
|
|
skip = 5;
|
|
tok = Token::NUM(8);
|
|
}
|
|
('N', 'I') => {
|
|
skip = 4;
|
|
tok = Token::NUM(9);
|
|
}
|
|
('Z', 'E') => {
|
|
skip = 4;
|
|
tok = Token::NUM(0);
|
|
}
|
|
('+', _) => {
|
|
tok = Token::PLUS;
|
|
}
|
|
('-', _) => {
|
|
tok = Token::MINUS;
|
|
}
|
|
('x', _) => {
|
|
tok = Token::TIMES;
|
|
}
|
|
('/', _) => {
|
|
tok = Token::DIV;
|
|
}
|
|
('=', _) => {
|
|
tok = Token::EQUAL;
|
|
}
|
|
|
|
_ => {
|
|
return None;
|
|
}
|
|
}
|
|
|
|
match tok {
|
|
Token::NUM(x) => {
|
|
let last = lexed.last();
|
|
match last {
|
|
Some(&Token::NUM(y)) => {
|
|
lexed.pop();
|
|
lexed.push(Token::NUM(y * 10 + x));
|
|
}
|
|
_ => {
|
|
lexed.push(tok);
|
|
}
|
|
}
|
|
}
|
|
_ => {
|
|
lexed.push(tok);
|
|
}
|
|
}
|
|
}
|
|
// next
|
|
if skip > 0 {
|
|
skip -= 1;
|
|
}
|
|
match iter.next() {
|
|
Some(ch) => {
|
|
curr = next;
|
|
next = ch;
|
|
}
|
|
None => {
|
|
if next == '\n' || next == '\0' {
|
|
next = '\0';
|
|
curr = '\n';
|
|
} else {
|
|
curr = next;
|
|
next = '\n';
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ON
|
|
// TW
|
|
// TH
|
|
// FO
|
|
// FI
|
|
// SI
|
|
// SE
|
|
// EI
|
|
// NI
|
|
// ZE
|
|
|
|
Some(lexed)
|
|
}
|
|
|
|
fn eval(op: Token, num_stack: &mut Vec<i64>) -> bool {
|
|
let (a, b) = match (num_stack.pop(), num_stack.pop()) {
|
|
(Some(x), Some(y)) => (y, x),
|
|
_ => {
|
|
return false;
|
|
}
|
|
};
|
|
|
|
match op {
|
|
Token::PLUS => {
|
|
num_stack.push(a + b);
|
|
}
|
|
Token::MINUS => {
|
|
num_stack.push(a - b);
|
|
}
|
|
Token::TIMES => {
|
|
num_stack.push(a * b);
|
|
}
|
|
Token::DIV => {
|
|
num_stack.push(a / b);
|
|
}
|
|
_ => {
|
|
return false;
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
fn parse(lexed: &Vec<Token>) -> Option<i64> {
|
|
let mut op_stack: Vec<Token> = vec![];
|
|
let mut num_stack: Vec<i64> = vec![];
|
|
for &token in lexed {
|
|
match token {
|
|
Token::NUM(x) => {
|
|
num_stack.push(x as i64);
|
|
}
|
|
Token::PLUS | Token::MINUS | Token::TIMES | Token::DIV => {
|
|
let p = priority(token);
|
|
while let Some(&top) = op_stack.last() {
|
|
if priority(top) > p {
|
|
if !eval(op_stack.pop().unwrap(), &mut num_stack) {
|
|
return None;
|
|
}
|
|
} else {
|
|
break;
|
|
}
|
|
}
|
|
op_stack.push(token);
|
|
}
|
|
Token::EQUAL => {
|
|
while let Some(op) = op_stack.pop() {
|
|
if !eval(op, &mut num_stack) {
|
|
return None;
|
|
}
|
|
}
|
|
}
|
|
Token::Err => {
|
|
panic!("Invalid Token");
|
|
}
|
|
}
|
|
}
|
|
if (num_stack.len() == 1) {
|
|
return num_stack.pop();
|
|
} else {
|
|
return None;
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
let mut s = String::new();
|
|
|
|
stdin().read_line(&mut s).unwrap();
|
|
|
|
let s = s.trim_ascii_end().to_string();
|
|
|
|
let lexed = lex(s);
|
|
if lexed.is_none() {
|
|
println!("Madness!");
|
|
return;
|
|
}
|
|
let lexed = lexed.unwrap();
|
|
|
|
let parsed = parse(&lexed);
|
|
|
|
|
|
if parsed.is_none() {
|
|
println!("Madness!");
|
|
} else {
|
|
for tok in lexed {
|
|
print!("{}", tok.to_string());
|
|
}
|
|
print!("\n");
|
|
println!("{}", convert(parsed.unwrap()));
|
|
}
|
|
}
|