From: Harishankar Date: Thu, 28 May 2020 16:27:56 +0000 (+0530) Subject: First commit X-Git-Tag: 0.1-a~10 X-Git-Url: https://harishankar.org/repos/?p=evpf.git;a=commitdiff_plain;h=a12f1c210f0d76985c641bc1b8a16175c8512045 First commit first commit of postfix expression evaluator --- a12f1c210f0d76985c641bc1b8a16175c8512045 diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..1f7d091 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,56 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "aho-corasick" +version = "0.7.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" +dependencies = [ + "memchr", +] + +[[package]] +name = "evpf" +version = "0.1.0" +dependencies = [ + "regex", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "memchr" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" + +[[package]] +name = "regex" +version = "1.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "226ddd1197737bcb937489322ec1b9edaac1709d46792886e70f2113923585a6" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", + "thread_local", +] + +[[package]] +name = "regex-syntax" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" + +[[package]] +name = "thread_local" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" +dependencies = [ + "lazy_static", +] diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..8615725 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,10 @@ +[package] +name = "evpf" +version = "0.1.0" +authors = ["Harishankar "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +regex="1" diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..dcf215f --- /dev/null +++ b/src/main.rs @@ -0,0 +1,117 @@ +use std::io; +use regex::Regex; + +// describe the operators +enum Operator { + NUM, ADD, SUB, MUL, DIV, +} + +// structure to hold an expression in the stack +struct Expression { + value : f32, + operator : Operator, +} + +// function to compute a result by popping the stack and +// pushing back the result +fn get_result (t : &mut Vec::) { + // pop the stack to get the operator + // if nothing - panic with error + let op = match t.pop () { + Some(x) => x, + None => panic! ("Illegal expression!"), + }; + // pop the stack for last operand + // if nothing - panic with error + let n1 = match t.pop () { + Some (x) => x, + None => panic! ("Illegal expression!"), + }; + // pop the stack for the first operand + // if nothing - panic with error + let n2 = match t.pop () { + Some (x) => x, + None => panic! ("Illegal expression!"), + }; + + let mut res : f32 = 0.0; + + // depending on the operation, set the result + match op.operator { + Operator::ADD => res = n1.value + n2.value, + Operator::SUB => res = n2.value - n1.value, + Operator::MUL => res = n1.value * n2.value, + Operator::DIV => res = n2.value / n1.value, + _ => panic! ("Illegal operator in expression!"), + } + // push the result back to the stack + t.push (Expression {value : res, operator : Operator::NUM }); +} + +// evaluation function +fn evaluate (expr : &str) { + let mut ops = Vec::::new (); + // tokenize the individual words by splitting at whitespace + let words = expr.split_whitespace (); + // regular expression to match a number + let match_num = Regex::new (r"^\d+?.*?\d*?$").unwrap (); + // iterate over the words + for word in words { + match word { + // if the word matches one of +, -, *, / then push it on the stack + // and immediately evaluate the expression by popping the operator + // and the last two operands and push the result back on to the stack + "+" => {ops.push (Expression{ value: 0.0, operator: Operator::ADD }); + get_result (&mut ops) }, + "-" => {ops.push (Expression{ value: 0.0, operator: Operator::SUB }); + get_result (&mut ops) }, + "*" => {ops.push (Expression{ value: 0.0, operator: Operator::MUL}); + get_result (&mut ops)}, + "/" => {ops.push (Expression{ value: 0.0, operator: Operator::DIV}); + get_result (&mut ops) }, + // if word matches a number, push it on to the stack + _ => if match_num.is_match (word) { + let num : f32 = word.parse ().unwrap (); + ops.push (Expression {value: num, operator: Operator::NUM }); + } + // if word doesn't match either operator or number then panic. + else { + panic! ("Error parsing expression! + Must be a number or operator (+,-,* or /)"); + } + } + } + // if the stack has more than one value, it means that the postfix + // expression is not complete - so display the stack status + if ops.len () > 1 { + println! ("Postfix Expression not complete. Current stack: "); + for exp in ops { + println! ("{}", exp.value); + } + } + // stack has only one item which is the result so display it + else { + println! ("Result: {}", ops[0].value); + } + println! (); +} + +fn main() { + // get a line from input and evaluate it + let mut expr = String::new (); + // loop until a blank line is received + loop { + expr.clear (); + println!("Enter an expression (postfix) (blank to quit): "); + // read a line of text + io::stdin().read_line (&mut expr).expect ("Error reading line!"); + // trim the text + let expr = expr.trim (); + // quit if the expression is blank + if expr == "" { + break; + } + + evaluate (&expr); + } +}