Added Rust program

This commit is contained in:
Win 2025-01-28 23:03:11 +07:00
parent 7f3d00c9a1
commit ed43edbf66
99 changed files with 117 additions and 47 deletions
spring-2025/sen-109/00020/eval
src
target
.rustc_info.json
debug
.fingerprint
deps
expression-eval
incremental
expression_eval-16koc7cbt8j5g
s-h3vetfhp14-0cun7bq-a4hzx5p4bc0jrj2zogp0qiogt
s-h43izi3beg-03307x0-0adozqk4du5bq6ryvq6kccm7s
s-h43izi3beg-03307x0.lock
expression_eval-2fso3c9c9bihx
s-h3vfkaw83u-1jyxmd8-b5n56l5jq1lokywnzz4ujtt4v
s-h43izluwgw-1ugb4h6-84qbqgj8gbqajfzdqju042592
08pgswn8j4hu9ybi8abvh57au.o0c6g7sldd3exu9s48jfttki90.o15j6qy9frgp1xbfti1k48c5c9.o1mwtyr2k2shuhp7xgk08r2z5p.o1rl7fpfc6luhqfa3ufvptegn8.o2keq9sxt0n8agc81eil11shsg.o2rlmtj2vjupuqqjrwbu8l3xlo.o382ijxh3grgv552ob5uelq2uk.o39puzlb9mce25p0as0x5evyn6.o3c8bq39ob6qxnbckq35me0niy.o3vvo5xsje6j43txjolfdcgazh.o3yifum6ghmsrip53y8sl7g9dq.o4jh67iglpxok1pb34g2hjk4jt.o4lwzkf4p1aeoa6da00a8g776w.o4ub9lbi7lclgj0gab1zlkzo7g.o4y2iau04tt7rv0f1txia43lj1.o52g621zcqmutyccnn3bu3vsrd.o5ftc06egl57lsi6ipwiq4dbhp.o5lvm4niyga2myy4r98ywix5u8.o5n8vy1hqiubqa2uvz0cafp6en.o6bssn7oc6s41acdboahrzbl32.o6f0v2hk171x7pnsuaxfmc9crf.o6kpu3mxs32hsm2b1x7l4oy55n.o6sl8btd0ubwg2cbfe50kujpch.o6xo2a2lbn7xyf7r074bg4zoar.o7471g5x9fgui593s248l5svdu.o74ih1cukp1rpexwazw6dw045z.o7i8ydzfzgrxxy0j2qi6wgw7jp.o7pd0mgtbszp4g1z2dm0mc4rem.o7ycdppjae19p61ax3ijt07wud.o8ccaqstbw9sbjj2lpwochti46.o92t9rw30capr4frxwtik5kuqf.o9bfh9r13qeswv79ah47kft4c5.o9cmsk184bps9osgs631x3zm1h.oa9qn17ut5qbbtjr2oqn6dtepp.oado2c9kjvypdg4vi2nhoqfl37.oag631e06inf0mfv54l2j4mwkw.oayrhtfusc8zafykqmfys4rv1o.oazcavq8gmxd2grtiend9zvptb.ob2x1eijj6u2cb0gvlrfor5g54.ob2xlx7cof0i2h5gnuk5i7konz.ob5dmgoxoe4zvu54md4kg45dgz.obfkdckbcymf1emzkooqlr9qwg.obhzazune8595y3atqcy845hy7.obi4fajxcfkoeiyst9m1v6ueku.objdlqr48h2bzf65zve9lw0poi.oc3z8th0zdcoxl1z74xweovpok.od3xbpz47aseah5s9bkxx4eeab.od3z60t2cfv6mo0i2hehz3e7l1.odep-graph.bine0k98ls8grkgt02cfvs0l8ye7.oe2mgnikbrsf9nsf0u74bt071z.oeeoq6ejjltrq0xy3l0iafuvty.oeiqh8j51i448ndgx3uqfxiauk.oezdroniuut6davkyco2o4xlii.oquery-cache.binwork-products.bin
s-h43izluwgw-1ugb4h6.lock
expression_eval-3k9pz3px1jven
s-h3vetfhoyf-1vlh7di-bwam55ycf8v52qx2e8cvakuaw
s-h43izi389v-123bwy9-5u2q1lpai4u4iv8hirp9x34qr
s-h43izi389v-123bwy9.lock

View File

@ -23,8 +23,8 @@ fn evaluate(expr: String) -> Result<f64, ParseError> {
fn main() {
println!("Hello! Welcome to Arithmetic expression evaluator.");
println!("You can calculate value for expression such as 2*3+(4-5)+2^3/4. ");
println!("Allowed numbers: positive, negative and decimals.");
println!("Supported operations: Add, Subtract, Multiply, Divide, PowerOf(^). ");
println!("Allowed numbers: positive, negative, and decimals.");
println!("Supported operations: Add, Subtract, Multiply, Divide, PowerOf(^), Bitwise Operations: &, |. ");
println!("Enter your arithmetic expression below:");
loop {
let mut input = String::new();

View File

@ -18,6 +18,7 @@ pub enum Node {
Divide(Box<Node>, Box<Node>),
Caret(Box<Node>, Box<Node>),
Negative(Box<Node>),
Number(f64),
}
@ -26,10 +27,16 @@ pub fn eval(expr: Node) -> Result<f64, Box<dyn error::Error>> {
use self::Node::*;
match expr {
Number(i) => Ok(i),
Add(expr1, expr2) => Ok(eval(*expr1)? + eval(*expr2)?),
// TODO: complete the match expression to evaluate the numeric value
_ => panic!()
And(expr1, expr2) => Ok((eval(*expr1)? as i32 & eval(*expr2)? as i32).into()),
Or(expr1, expr2) => Ok((eval(*expr1)? as i32 | eval(*expr2)? as i32).into()),
Add(expr1, expr2) => Ok(eval(*expr1)? + eval(*expr2)?),
Subtract(expr1, expr2) => Ok(eval(*expr1)? - eval(*expr2)?),
Multiply(expr1, expr2) => Ok(eval(*expr1)? * eval(*expr2)?),
Divide(expr1, expr2) => Ok(eval(*expr1)? / eval(*expr2)?),
Negative(expr1) => Ok(-(eval(*expr1)?)),
Caret(expr1, expr2) => Ok(eval(*expr1)?.powf(eval(*expr2)?)),
}
}

View File

@ -36,8 +36,8 @@ impl<'a> Parser<'a> {
pub fn parse(&mut self) -> Result<Node, ParseError> {
let ast = self.generate_ast(OperPrec::DefaultZero);
match ast {
// TODO: Replace this with proper handling of return value from generate_ast result
_ => panic!()
Ok(ast) => Ok(ast),
Err(e) => Err(e),
}
}
}
@ -87,9 +87,15 @@ impl<'a> Parser<'a> {
Token::LeftParen => {
self.get_next_token()?;
// TODO: Replace the following code to check for matching parenthesis;
// also convert (x)(y) to x times y
let expr = self.generate_ast(OperPrec::DefaultZero)?;
let _ = self.check_paren(Token::RightParen);
if self.current_token == Token::LeftParen
{
let right = self.generate_ast(OperPrec::MulDiv)?;
return Ok(Node::Multiply(Box::new(expr), Box::new(right)));
}
Ok(expr)
}
_ => Err(ParseError::UnableToParse("Unable to parse".to_string())),
@ -110,15 +116,57 @@ impl<'a> Parser<'a> {
}
// Construct Operator AST nodes
fn convert_token_to_node(&mut self, left_expr: Node) -> Result<Node, ParseError> {
match self.current_token {
Token::Add => {
fn convert_token_to_node(&mut self, left_expr: Node) -> Result<Node, ParseError>
{
match self.current_token
{
Token::And =>
{
self.get_next_token()?;
let right_expr = self.generate_ast(OperPrec::AndOr)?;
Ok(Node::And(Box::new(left_expr), Box::new(right_expr)))
},
Token::Or =>
{
self.get_next_token()?;
let right_expr = self.generate_ast(OperPrec::AndOr)?;
Ok(Node::Or(Box::new(left_expr), Box::new(right_expr)))
},
Token::Add =>
{
self.get_next_token()?;
//Get right-side expression
let right_expr = self.generate_ast(OperPrec::AddSub)?;
Ok(Node::Add(Box::new(left_expr), Box::new(right_expr)))
}
// TODO: Complete the node construction for other tokens
Token::Subtract =>
{
self.get_next_token()?;
let right_expr = self.generate_ast(OperPrec::AddSub)?;
Ok(Node::Subtract(Box::new(left_expr), Box::new(right_expr)))
}
Token::Multiply =>
{
self.get_next_token()?;
let right_expr = self.generate_ast(OperPrec::MulDiv)?;
Ok(Node::Multiply(Box::new(left_expr), Box::new(right_expr)))
}
Token::Divide =>
{
self.get_next_token()?;
let right_expr = self.generate_ast(OperPrec::MulDiv)?;
Ok(Node::Divide(Box::new(left_expr), Box::new(right_expr)))
}
Token::Caret =>
{
self.get_next_token()?;
let right_expr = self.generate_ast(OperPrec::Power)?;
Ok(Node::Caret(Box::new(left_expr), Box::new(right_expr)))
}
_ => Err(ParseError::InvalidOperator(format!(
"Please enter valid operator {:?}",

View File

@ -41,7 +41,6 @@ impl Token {
Add | Subtract => AddSub,
Multiply | Divide => MulDiv,
Caret => Power,
_ => DefaultZero,
}
}

View File

@ -1,23 +1,23 @@
/// This module reads characters in arithmetic expression and converts them to tokens.
/// The allowed tokens are defined in ast module.
// Standard lib
use std::iter::Peekable;
use std::str::Chars;
//Other internal modules
use super::token::Token;
// Other structs
// Tokenizer struct contains a Peekable iterator on the arithmetic expression
pub struct Tokenizer<'a> {
pub struct Tokenizer<'a>
{
expr: Peekable<Chars<'a>>,
}
// Constructs a new instance of Tokenizer
impl<'a> Tokenizer<'a> {
pub fn new(new_expr: &'a str) -> Self {
Tokenizer {
impl<'a> Tokenizer<'a>
{
pub fn new(new_expr: &'a str) -> Self
{
Tokenizer
{
expr: new_expr.chars().peekable(),
}
}
@ -26,21 +26,45 @@ impl<'a> Tokenizer<'a> {
// Implement Iterator trait for Tokenizer struct.
// With this, we can use next() method on tokenizer to retrieve the next token from arithmetic expression
impl<'a> Iterator for Tokenizer<'a> {
impl<'a> Iterator for Tokenizer<'a>
{
type Item = Token;
fn next(&mut self) -> Option<Token> {
fn next(&mut self) -> Option<Token>
{
let next_char = self.expr.next();
match next_char {
match next_char
{
Some('0'..='9') => {
// TODO: Iterate & peeking through the next characters to create Num token
// Make sure to return None if the value is not parsable
None
let mut number = next_char?.to_string();
while let Some(next_char) = self.expr.peek()
{
if next_char.is_numeric() || next_char == &'.'
{
number.push(self.expr.next()?);
}
else if next_char == &'('
{
return None;
}
else
{
break;
}
}
Some(Token::Num(number.parse::<f64>().unwrap()))
},
// TODO: return the appropriate tokens for available symbols
Some('&') => Some(Token::And),
Some('|') => Some(Token::Or),
Some('+') => Some(Token::Add),
Some('-') => Some(Token::Subtract),
Some('*') => Some(Token::Multiply),
Some('/') => Some(Token::Divide),
Some('^') => Some(Token::Caret),
Some('(') => Some(Token::LeftParen),
Some(')') => Some(Token::RightParen),
None => Some(Token::EOF),
Some(_) => None,
}
@ -49,21 +73,25 @@ impl<'a> Iterator for Tokenizer<'a> {
// Unit tests
#[cfg(test)]
mod tests {
mod tests
{
use super::*;
#[test]
fn test_positive_integer() {
fn test_positive_integer()
{
let mut tokenizer = Tokenizer::new("34");
assert_eq!(tokenizer.next().unwrap(), Token::Num(34.0))
}
#[test]
fn test_decimal_number() {
fn test_decimal_number()
{
let mut tokenizer = Tokenizer::new("34.5");
assert_eq!(tokenizer.next().unwrap(), Token::Num(34.5))
}
#[test]
fn test_invalid_char() {
fn test_invalid_char()
{
let mut tokenizer = Tokenizer::new("#$%");
assert_eq!(tokenizer.next(), None);
}

View File

@ -1 +1 @@
{"rustc_fingerprint":15625702514836887422,"outputs":{"15729799797837862367":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/usr/local/rustup/toolchains/1.83.0-x86_64-unknown-linux-gnu\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n","stderr":""},"4614504638168534921":{"success":true,"status":"","code":0,"stdout":"rustc 1.83.0 (90b35a623 2024-11-26)\nbinary: rustc\ncommit-hash: 90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf\ncommit-date: 2024-11-26\nhost: x86_64-unknown-linux-gnu\nrelease: 1.83.0\nLLVM version: 19.1.1\n","stderr":""}},"successes":{}}
{"rustc_fingerprint":14404728096486143510,"outputs":{"4614504638168534921":{"success":true,"status":"","code":0,"stdout":"rustc 1.83.0 (90b35a623 2024-11-26)\nbinary: rustc\ncommit-hash: 90b35a6239c3d8bdabc530a6a0816f7ff89a0aaf\ncommit-date: 2024-11-26\nhost: x86_64-unknown-linux-gnu\nrelease: 1.83.0\nLLVM version: 19.1.1\n","stderr":""},"15729799797837862367":{"success":true,"status":"","code":0,"stdout":"___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/usr/local/rustup/toolchains/1.83.0-x86_64-unknown-linux-gnu\noff\npacked\nunpacked\n___\ndebug_assertions\npanic=\"unwind\"\nproc_macro\ntarget_abi=\"\"\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_has_atomic=\"16\"\ntarget_has_atomic=\"32\"\ntarget_has_atomic=\"64\"\ntarget_has_atomic=\"8\"\ntarget_has_atomic=\"ptr\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\ntarget_vendor=\"unknown\"\nunix\n","stderr":""}},"successes":{}}