mirror of
https://github.com/kmc7468/cs220.git
synced 2025-12-12 21:08:45 +00:00
Assignment 4 Done
This commit is contained in:
@@ -27,7 +27,26 @@ impl Context {
|
|||||||
|
|
||||||
/// Calculates the given expression. (We assume the absence of overflow.)
|
/// Calculates the given expression. (We assume the absence of overflow.)
|
||||||
pub fn calc_expression(&self, expression: &Expression) -> Result<f64> {
|
pub fn calc_expression(&self, expression: &Expression) -> Result<f64> {
|
||||||
todo!("fill here")
|
match expression {
|
||||||
|
Expression::Num(value) => Ok(*value),
|
||||||
|
Expression::Variable(name) => self
|
||||||
|
.variables
|
||||||
|
.get(name)
|
||||||
|
.copied()
|
||||||
|
.ok_or(anyhow!("Unknown variable")),
|
||||||
|
Expression::BinOp { op, lhs, rhs } => {
|
||||||
|
let lhs = self.calc_expression(lhs)?;
|
||||||
|
let rhs = self.calc_expression(rhs)?;
|
||||||
|
match op {
|
||||||
|
BinOp::Add => Ok(lhs + rhs),
|
||||||
|
BinOp::Subtract => Ok(lhs - rhs),
|
||||||
|
BinOp::Multiply => Ok(lhs * rhs),
|
||||||
|
BinOp::Divide if rhs == 0.0 => Err(anyhow!("Division by zero")),
|
||||||
|
BinOp::Divide => Ok(lhs / rhs),
|
||||||
|
BinOp::Power => Ok(lhs.powf(rhs)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Calculates the given command. (We assume the absence of overflow.)
|
/// Calculates the given command. (We assume the absence of overflow.)
|
||||||
@@ -43,6 +62,14 @@ impl Context {
|
|||||||
///
|
///
|
||||||
/// After calculating commad `3 ^ 2` => Context's variables = `{($0,8),(v,1),($1,9)}`
|
/// After calculating commad `3 ^ 2` => Context's variables = `{($0,8),(v,1),($1,9)}`
|
||||||
pub fn calc_command(&mut self, command: &Command) -> Result<(String, f64)> {
|
pub fn calc_command(&mut self, command: &Command) -> Result<(String, f64)> {
|
||||||
todo!("fill here")
|
let value = self.calc_expression(&command.expression)?;
|
||||||
|
let name = command.variable.clone().unwrap_or_else(|| {
|
||||||
|
let name = format!("${}", self.anonymous_counter);
|
||||||
|
self.anonymous_counter += 1;
|
||||||
|
name
|
||||||
|
});
|
||||||
|
|
||||||
|
_ = self.variables.insert(name.clone(), value);
|
||||||
|
Ok((name, value))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -14,11 +14,19 @@ use super::syntax::*;
|
|||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
#[allow(missing_debug_implementations)]
|
#[allow(missing_debug_implementations)]
|
||||||
mod inner {
|
mod inner {
|
||||||
|
use pest::pratt_parser::{Assoc::*, *};
|
||||||
use pest_derive::*;
|
use pest_derive::*;
|
||||||
|
|
||||||
#[derive(Parser)]
|
#[derive(Parser)]
|
||||||
#[grammar = "assignments/assignment04/syntax.pest"]
|
#[grammar = "assignments/assignment04/syntax.pest"]
|
||||||
pub(crate) struct SyntaxParser;
|
pub(crate) struct SyntaxParser;
|
||||||
|
|
||||||
|
lazy_static::lazy_static! {
|
||||||
|
pub static ref PRATT_PARSER: PrattParser<Rule> = PrattParser::new()
|
||||||
|
.op(Op::infix(Rule::add, Left) | Op::infix(Rule::subtract, Left))
|
||||||
|
.op(Op::infix(Rule::multiply, Left) | Op::infix(Rule::divide, Left))
|
||||||
|
.op(Op::infix(Rule::power, Right));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
use inner::*;
|
use inner::*;
|
||||||
@@ -32,5 +40,51 @@ use inner::*;
|
|||||||
/// e.g. `1+2+3` should be parsed into `(1+2)+3`, not `1+(2+3)` because the associativity of
|
/// e.g. `1+2+3` should be parsed into `(1+2)+3`, not `1+(2+3)` because the associativity of
|
||||||
/// plus("add" in our hw) operator is `Left`.
|
/// plus("add" in our hw) operator is `Left`.
|
||||||
pub fn parse_command(line: &str) -> Result<Command> {
|
pub fn parse_command(line: &str) -> Result<Command> {
|
||||||
todo!("fill here")
|
let mut variable: Option<&str> = None;
|
||||||
|
let mut expression: Option<Expression> = None;
|
||||||
|
|
||||||
|
for pair in SyntaxParser::parse(Rule::command, line)? {
|
||||||
|
match pair.as_rule() {
|
||||||
|
Rule::var => variable = Some(pair.as_str()),
|
||||||
|
Rule::expr => expression = Some(parse_expression(pair.into_inner())?),
|
||||||
|
Rule::EOI => {}
|
||||||
|
_ => unreachable!(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(Command {
|
||||||
|
variable: variable.map(|s| s.to_string()),
|
||||||
|
expression: expression.unwrap(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Parses expression.
|
||||||
|
pub fn parse_expression(pairs: Pairs<'_, Rule>) -> Result<Expression> {
|
||||||
|
let mut first_term: Option<Expression> = None;
|
||||||
|
let mut operation: Option<BinOp> = None;
|
||||||
|
let mut second_term: Option<Expression> = None;
|
||||||
|
|
||||||
|
PRATT_PARSER
|
||||||
|
.map_primary(|primary| match primary.as_rule() {
|
||||||
|
Rule::num => Ok(Expression::Num(primary.as_str().parse()?)),
|
||||||
|
Rule::var => Ok(Expression::Variable(primary.as_str().to_string())),
|
||||||
|
Rule::expr => Ok(parse_expression(primary.into_inner())?),
|
||||||
|
_ => unreachable!(),
|
||||||
|
})
|
||||||
|
.map_infix(|lhs, op, rhs| {
|
||||||
|
let op = match op.as_rule() {
|
||||||
|
Rule::add => BinOp::Add,
|
||||||
|
Rule::subtract => BinOp::Subtract,
|
||||||
|
Rule::multiply => BinOp::Multiply,
|
||||||
|
Rule::divide => BinOp::Divide,
|
||||||
|
Rule::power => BinOp::Power,
|
||||||
|
_ => unreachable!(),
|
||||||
|
};
|
||||||
|
Ok(Expression::BinOp {
|
||||||
|
op,
|
||||||
|
lhs: Box::new(lhs?),
|
||||||
|
rhs: Box::new(rhs?),
|
||||||
|
})
|
||||||
|
})
|
||||||
|
.parse(pairs)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user