From fedfee3524304fbab4375c6f2859a0cbffd027a6 Mon Sep 17 00:00:00 2001 From: BHznJNs <441768875@qq.com> Date: Sun, 12 Mar 2023 12:27:59 +0800 Subject: [PATCH] Script mode support & comment support --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 15 ++++++++- src/compiler/tokenizer.rs | 5 ++- src/exec/attempt.rs | 23 +++++++++++++ src/exec/mod.rs | 3 ++ src/exec/repl.rs | 36 ++++++++++++++++++++ src/exec/run_script.rs | 62 +++++++++++++++++++++++++++++++++++ src/main.rs | 69 +++++++++++++++------------------------ 9 files changed, 170 insertions(+), 47 deletions(-) create mode 100644 src/exec/attempt.rs create mode 100644 src/exec/mod.rs create mode 100644 src/exec/repl.rs create mode 100644 src/exec/run_script.rs diff --git a/Cargo.lock b/Cargo.lock index 07bbe3b..c3d4218 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,4 +4,4 @@ version = 3 [[package]] name = "calculator" -version = "1.1.1" +version = "1.2.0" diff --git a/Cargo.toml b/Cargo.toml index 136561d..8b6bd22 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "calculator" -version = "1.1.1" +version = "1.2.0" edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html diff --git a/README.md b/README.md index 9ade844..03390cd 100644 --- a/README.md +++ b/README.md @@ -20,7 +20,7 @@ An simple command-line calculator program writen with Rust. = 1 ``` -- Goto supported +- Goto support ```text > a = 10 @@ -33,6 +33,19 @@ An simple command-line calculator program writen with Rust. = 31 ``` +- Comment support + +```text +> 1 + 1 # plus += 2 +``` + +- Script execute support + +```text +calculator.exe script +``` + ## Build-ins - Functions diff --git a/src/compiler/tokenizer.rs b/src/compiler/tokenizer.rs index 53b7d16..94f2db7 100644 --- a/src/compiler/tokenizer.rs +++ b/src/compiler/tokenizer.rs @@ -120,6 +120,7 @@ pub fn tokenizer(source: String) -> Result { const POWER_ASCII : u8 = 94; const EQUAL_ASCII : u8 = 61; + const NUMBER_SIGN_ASCII : u8 = 35; const SPACE_ASCII : u8 = 32; const RETURN_ASCII : u8 = 13; @@ -208,7 +209,9 @@ pub fn tokenizer(source: String) -> Result { }, SPACE_ASCII => {}, - RETURN_ASCII => { break; }, + // comment symbol + NUMBER_SIGN_ASCII => { break }, + RETURN_ASCII => { break }, _ => { println!("Unknown token: '{}' at index {}.", current as char, index); return Err(()); diff --git a/src/exec/attempt.rs b/src/exec/attempt.rs new file mode 100644 index 0000000..d844b02 --- /dev/null +++ b/src/exec/attempt.rs @@ -0,0 +1,23 @@ +use std::collections::HashMap; + +use crate::compiler::compile; +use crate::computer::compute; +use crate::public::number::Number; +use crate::public::ast::ASTNode; + +pub fn attempt( + input: String, + build_in_funcs: &HashMap<&str, fn(f64) -> f64>, + variables: &mut HashMap, + goto_statements: &mut HashMap, +) -> Result { + let root_node = compile::compile(input)?; + let result_num = compute::compute( + root_node, + build_in_funcs, + variables, + goto_statements, + )?; + + Ok(result_num) +} \ No newline at end of file diff --git a/src/exec/mod.rs b/src/exec/mod.rs new file mode 100644 index 0000000..ee819d1 --- /dev/null +++ b/src/exec/mod.rs @@ -0,0 +1,3 @@ +pub mod attempt; +pub mod repl; +pub mod run_script; \ No newline at end of file diff --git a/src/exec/repl.rs b/src/exec/repl.rs new file mode 100644 index 0000000..4de590d --- /dev/null +++ b/src/exec/repl.rs @@ -0,0 +1,36 @@ +use std::collections::HashMap; +use std::io::{self, Write}; + +use super::attempt::attempt; +use crate::public::number::Number; +use crate::public::ast::ASTNode; + +pub fn repl( + build_in_funcs: &HashMap<&str, fn(f64) -> f64>, + variables: &mut HashMap, + goto_statements: &mut HashMap, +) -> ! { + // print program name and version + println!("Calculator.rs v1.2.0"); + + loop { + print!("> "); + io::stdout().flush().unwrap(); + + let mut input = String::new(); + std::io::stdin() + .read_line(&mut input) + .unwrap(); + + let result = attempt( + input, + build_in_funcs, + variables, + goto_statements, + ); + + if let Ok(num) = result { + println!("= {}", num); + } + } +} \ No newline at end of file diff --git a/src/exec/run_script.rs b/src/exec/run_script.rs new file mode 100644 index 0000000..0539f48 --- /dev/null +++ b/src/exec/run_script.rs @@ -0,0 +1,62 @@ +use std::collections::HashMap; +use std::fs::File; +use std::io::{self, BufRead}; + +use crate::exec::attempt::attempt; +use crate::public::number::Number; +use crate::public::ast::ASTNode; + +type FileBuf = io::BufReader; +fn read_lines(path: String) -> io::Result> { + let file = File::open(path)?; + Ok(io::BufReader::new(file).lines()) +} + +pub fn run_script( + path: String, + build_in_funcs: &HashMap<&str, fn(f64) -> f64>, + variables: &mut HashMap, + goto_statements: &mut HashMap, +) { + let mut script_lines = + if let Ok(lines) = read_lines(path) { + lines + } else { + println!("Invalid file."); + return + }; + + // cache last compute result, + // when the loop ends, + // print the final result. + let mut last_result = Number::NotANumber; + loop { + match script_lines.next() { + Some(item) => { + let mut script_line = + if let Ok(line) = item { + line + } else { + String::new() + }; + script_line.push('\r'); + + last_result = + if let Ok(res_number) = attempt( + script_line, + build_in_funcs, + variables, + goto_statements + ) { + res_number + } else { + Number::NotANumber + }; + }, + None => { + println!("{}", last_result); + break; + }, + } + } +} \ No newline at end of file diff --git a/src/main.rs b/src/main.rs index fd733ca..320b9b9 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,60 +1,43 @@ mod public; mod compiler; mod computer; +mod exec; +use std::env; use std::collections::HashMap; -use std::io::{self, Write}; use public::ast::ASTNode; -use public::number::Number; use public::build_in; -use compiler::compile; -use computer::compute; +use exec::repl::repl; +use exec::run_script::run_script; -fn attempt( - input: String, - build_in_funcs: &HashMap<&str, fn(f64) -> f64>, - variables: &mut HashMap, - goto_statements: &mut HashMap -) -> Result { - let root_node = compile::compile(input)?; - let result_num = compute::compute( - root_node, - build_in_funcs, - variables, - goto_statements, - )?; - - Ok(result_num) -} - -fn main() -> ! { +fn main() { let build_in_inst = build_in::BuildIn::init(); let build_in_funcs = build_in::build_in_funcs(&build_in_inst); let mut variables = build_in::variables(&build_in_inst); let mut goto_statements = HashMap::::new(); - // print program name and version - println!("Calculator.rs v1.1.1"); - - loop { - print!("> "); - io::stdout().flush().unwrap(); - - let mut input = String::new(); - std::io::stdin() - .read_line(&mut input) - .unwrap(); - - let result = attempt( - input, - &build_in_funcs, - &mut variables, - &mut goto_statements, - ); - - if let Ok(num) = result { - println!("= {}", num); + let args: Vec = env::args().collect(); + match args.len() { + 1 => { + // REPL mode + repl( + &build_in_funcs, + &mut variables, + &mut goto_statements, + ); + }, + 2 => { + // script mode + run_script( + args[1].to_owned(), + &build_in_funcs, + &mut variables, + &mut goto_statements, + ); + }, + _ => { + println!("Too many args."); } } } \ No newline at end of file