Forth
1. Readme
Forth
为 Forth 的一个非常简单的子集,实现一个执行程序.
Forth是一种基于栈的编程语言。为 Forth 的一小部分子集,实现一个非常基本的执行器。
您的执行器必须支持以下关键字:
+
,-
,*
,/
(整数运算)DUP
,DROP
,SWAP
,OVER
(栈操作)
您的执行器还必须支持使用惯用语法,定义新单词:: word-name definition ;
.
为简单起见,您需要支持的唯一数据类型是,至少 16 位大小的有符号整数。
您应该对语法使用以下规则:一个 number 是一个或多个(ASCII)数字的序列,单词是一个或多个字母,数字,符号或标点符号的序列,而不是数字。(Forth 可能使用稍微不同的规则,但这已足够接近。)
单词不区分大小写。
2. 开始你的表演
pub type Value = i32; pub type ForthResult = Result<(), Error>; pub struct Forth; #[derive(Debug, PartialEq)] pub enum Error { DivisionByZero, StackUnderflow, UnknownWord, InvalidWord, } impl Forth { pub fn new() -> Forth { unimplemented!() } pub fn stack(&self) -> Vec<Value> { unimplemented!() } pub fn eval(&mut self, input: &str) -> ForthResult { unimplemented!("result of evaluating '{}'", input) } }
3. 测试代码查看
# #![allow(unused_variables)] #fn main() { #[test] fn no_input_no_stack() { assert_eq!(Vec::<Value>::new(), Forth::new().stack()); } #[test] //#[ignore] fn numbers_just_get_pushed_onto_the_stack() { let mut f = Forth::new(); assert!(f.eval("1 2 3 4 5 -1").is_ok()); assert_eq!(vec![1, 2, 3, 4, 5, -1], f.stack()); } #[test] //#[ignore] fn non_word_characters_are_separators() { let mut f = Forth::new(); // Note the Ogham Space Mark ( ), this is a spacing character. assert!(f.eval("1\u{0000}2\u{0001}3\n4\r5 6\t7").is_ok()); assert_eq!(vec![1, 2, 3, 4, 5, 6, 7], f.stack()); } #[test] //#[ignore] fn basic_arithmetic_1() { let mut f = Forth::new(); assert!(f.eval("1 2 + 4 -").is_ok()); assert_eq!(vec![-1], f.stack()); } #[test] //#[ignore] fn basic_arithmetic_2() { let mut f = Forth::new(); assert!(f.eval("2 4 * 3 /").is_ok()); assert_eq!(vec![2], f.stack()); } #[test] //#[ignore] fn addition_error() { let mut f = Forth::new(); assert_eq!(Err(Error::StackUnderflow), f.eval("+")); } #[test] //#[ignore] fn subtraction_error() { let mut f = Forth::new(); assert_eq!(Err(Error::StackUnderflow), f.eval("-")); } #[test] //#[ignore] fn multiplication_error() { let mut f = Forth::new(); assert_eq!(Err(Error::StackUnderflow), f.eval("*")); } #[test] //#[ignore] fn division_error() { let mut f = Forth::new(); assert_eq!(Err(Error::StackUnderflow), f.eval("/")); } #[test] //#[ignore] fn division_by_zero() { let mut f = Forth::new(); assert_eq!(Err(Error::DivisionByZero), f.eval("4 2 2 - /")); } #[test] //#[ignore] fn dup() { let mut f = Forth::new(); assert!(f.eval("1 DUP").is_ok()); assert_eq!(vec![1, 1], f.stack()); } #[test] //#[ignore] fn dup_case_insensitive() { let mut f = Forth::new(); assert!(f.eval("1 Dup").is_ok()); assert_eq!(vec![1, 1], f.stack()); } #[test] //#[ignore] fn dup_error() { let mut f = Forth::new(); assert_eq!(Err(Error::StackUnderflow), f.eval("dup")); } #[test] //#[ignore] fn drop() { let mut f = Forth::new(); assert!(f.eval("1 drop").is_ok()); assert_eq!(Vec::<Value>::new(), f.stack()); } #[test] //#[ignore] fn drop_with_two() { let mut f = Forth::new(); assert!(f.eval("1 2 drop").is_ok()); assert_eq!(vec![1], f.stack()); } #[test] //#[ignore] fn drop_error() { let mut f = Forth::new(); assert_eq!(Err(Error::StackUnderflow), f.eval("drop")); } #[test] //#[ignore] fn swap() { let mut f = Forth::new(); assert!(f.eval("1 2 swap").is_ok()); assert_eq!(vec![2, 1], f.stack()); } #[test] //#[ignore] fn swap_with_three() { let mut f = Forth::new(); assert!(f.eval("1 2 3 swap").is_ok()); assert_eq!(vec![1, 3, 2], f.stack()); } #[test] //#[ignore] fn swap_error() { let mut f = Forth::new(); assert_eq!(Err(Error::StackUnderflow), f.eval("1 swap")); assert_eq!(Err(Error::StackUnderflow), f.eval("swap")); } #[test] //#[ignore] fn over() { let mut f = Forth::new(); assert!(f.eval("1 2 over").is_ok()); assert_eq!(vec![1, 2, 1], f.stack()); } #[test] //#[ignore] fn over_with_three() { let mut f = Forth::new(); assert!(f.eval("1 2 3 over").is_ok()); assert_eq!(vec![1, 2, 3, 2], f.stack()); } #[test] //#[ignore] fn over_error() { let mut f = Forth::new(); assert_eq!(Err(Error::StackUnderflow), f.eval("1 over")); assert_eq!(Err(Error::StackUnderflow), f.eval("over")); } #[test] //#[ignore] fn defining_a_new_word() { let mut f = Forth::new(); assert!(f.eval(": CoUnT 1 2 3 ;").is_ok()); assert!(f.eval("count COUNT").is_ok()); assert_eq!(vec![1, 2, 3, 1, 2, 3], f.stack()); } #[test] //#[ignore] fn redefining_an_existing_word() { let mut f = Forth::new(); assert!(f.eval(": foo dup ;").is_ok()); assert!(f.eval(": foo dup dup ;").is_ok()); assert!(f.eval("1 foo").is_ok()); assert_eq!(vec![1, 1, 1], f.stack()); } #[test] //#[ignore] fn redefining_an_existing_built_in_word() { let mut f = Forth::new(); assert!(f.eval(": swap dup ;").is_ok()); assert!(f.eval("1 swap").is_ok()); assert_eq!(vec![1, 1], f.stack()); } #[test] //#[ignore] fn defining_words_with_odd_characters() { let mut f = Forth::new(); assert!(f.eval(": € 220371 ; €").is_ok()); assert_eq!(vec![220371], f.stack()); } #[test] //#[ignore] fn defining_a_number() { let mut f = Forth::new(); assert_eq!(Err(Error::InvalidWord), f.eval(": 1 2 ;")); } #[test] //#[ignore] fn malformed_word_definition() { let mut f = Forth::new(); assert_eq!(Err(Error::InvalidWord), f.eval(":")); assert_eq!(Err(Error::InvalidWord), f.eval(": foo")); assert_eq!(Err(Error::InvalidWord), f.eval(": foo 1")); } #[test] //#[ignore] fn calling_non_existing_word() { let mut f = Forth::new(); assert_eq!(Err(Error::UnknownWord), f.eval("1 foo")); } #}
4. 答案
# #![allow(unused_variables)] #fn main() { use std::collections::HashMap; use std::collections::LinkedList; use std::str::FromStr; use Term::*; pub type Value = i32; pub type ForthResult = Result<(), Error>; type StackResult<T> = Result<T, Error>; type Stack = LinkedList<Value>; type Code = LinkedList<Term>; type Definitions = HashMap<String, Code>; pub struct Forth { code: Code, defs: Definitions, stack: Stack, } #[derive(Debug, PartialEq)] pub enum Error { DivisionByZero, StackUnderflow, UnknownWord, InvalidWord, } #[derive(Debug, Clone)] enum Term { Number(Value), Word(String), StartDefinition, EndDefinition, } impl FromStr for Term { type Err = (); fn from_str(s: &str) -> Result<Term, ()> { match s { ":" => Ok(StartDefinition), ";" => Ok(EndDefinition), _ => Err(()), }.or_else(|_| Value::from_str(s).map(Number)) .or_else(|_| Ok(Word(s.to_ascii_lowercase()))) } } impl Forth { pub fn new() -> Forth { Forth { code: LinkedList::new(), defs: HashMap::new(), stack: LinkedList::new(), } } pub fn stack(&self) -> Vec<Value> { self.stack.iter().cloned().collect() } pub fn eval(&mut self, input: &str) -> ForthResult { let mut new_code = Forth::into_code(input); self.code.append(&mut new_code); self.run() } fn run(&mut self) -> ForthResult { while let Some(term) = self.code.pop_front() { try!(self.step_term(term)) } Forth::ok() } fn step_term(&mut self, term: Term) -> ForthResult { match term { Number(value) => self.push(value), Word(word) => self.step_word(word), StartDefinition => self.store_definition(), EndDefinition => Err(Error::InvalidWord), } } fn step_word(&mut self, word: String) -> ForthResult { self.defs .get(&word) .ok_or(Error::UnknownWord) .map(Clone::clone) .map(|mut code| self.code.append(&mut code)) .or_else(|_| self.step_built_in(&word)) } fn step_built_in(&mut self, word: &String) -> ForthResult { match word.as_ref() { "+" => self.bin_op(|(a, b)| Ok(a + b)), "-" => self.bin_op(|(a, b)| Ok(a - b)), "*" => self.bin_op(|(a, b)| Ok(a * b)), "/" => self.bin_op(|(a, b)| a.checked_div(b).ok_or(Error::DivisionByZero)), "dup" => self.pop().and_then(|a| self.push(a).and(self.push(a))), "drop" => self.pop().and(Forth::ok()), "swap" => self.pop_two() .and_then(|(a, b)| self.push(b).and(self.push(a))), "over" => self.pop_two() .and_then(|(a, b)| self.push(a).and(self.push(b)).and(self.push(a))), _ => Err(Error::UnknownWord), } } fn store_definition(&mut self) -> ForthResult { let mut def = LinkedList::new(); loop { match self.code.pop_front() { Some(EndDefinition) => break, Some(term) => def.push_back(term), None => return Err(Error::InvalidWord), } } if let Some(Word(name)) = def.pop_front() { self.store_word(name, def) } else { Err(Error::InvalidWord) } } fn push(&mut self, value: Value) -> ForthResult { self.stack.push_back(value); Forth::ok() } fn pop(&mut self) -> StackResult<Value> { self.stack.pop_back().ok_or(Error::StackUnderflow) } fn pop_two(&mut self) -> StackResult<(Value, Value)> { self.pop().and_then(|b| self.pop().and_then(|a| Ok((a, b)))) } fn bin_op<F>(&mut self, op: F) -> ForthResult where F: FnOnce((Value, Value)) -> StackResult<Value>, { self.pop_two() .and_then(op) .and_then(|value| self.push(value)) } fn store_word(&mut self, name: String, code: Code) -> ForthResult { self.defs.insert(name, code); Forth::ok() } fn into_code(input: &str) -> LinkedList<Term> { input .split(|c: char| c.is_whitespace() || c.is_control()) .map(Term::from_str) .filter(Result::is_ok) .map(Result::unwrap) .collect() } fn ok() -> ForthResult { Ok(()) } } #}