diff --git a/src/err.rs b/src/err.rs new file mode 100644 index 0000000..687d503 --- /dev/null +++ b/src/err.rs @@ -0,0 +1,7 @@ +use err_derive::Error; + +#[derive(Debug, Error)] +pub enum ParseError { + #[error(display = "error syntax: {:?}", _0)] + ErrorSyntax(String), +} diff --git a/src/ins.rs b/src/ins.rs new file mode 100644 index 0000000..10a9d49 --- /dev/null +++ b/src/ins.rs @@ -0,0 +1,104 @@ + +#[derive(Debug)] +pub enum InsType { + Path(InsColl), + Node(Instruction), +} + +#[derive(Debug)] +pub struct Ins { + pub c: char, + pub ins_type: InsType, +} + +#[derive(Debug)] +pub struct InsColl { + pub inses: Vec, +} + +pub fn make_instruction_tree() -> InsColl { + InsColl{ inses: vec![ + Ins{ c: '草', ins_type: InsType::Path(InsColl{ inses: vec![ + Ins{ c: '草', ins_type: InsType::Node(Instruction::Push) }, + Ins{ c: '马', ins_type: InsType::Path(InsColl{ inses: vec![ + Ins{ c: '草', ins_type: InsType::Node(Instruction::Dup) }, + Ins{ c: '泥', ins_type: InsType::Node(Instruction::Swap) }, + Ins{ c: '马', ins_type: InsType::Node(Instruction::Pop) } + ]})}, + Ins{ c: '泥', ins_type: InsType::Path(InsColl{ inses: vec![ + Ins{ c: '草', ins_type: InsType::Node(Instruction::CopyN) }, + Ins{ c: '马', ins_type: InsType::Node(Instruction::PopN) } + ]})}, + ]})}, + Ins{ c: '泥', ins_type: InsType::Path(InsColl{ inses: vec![ + Ins{ c: '草', ins_type: InsType::Path(InsColl{ inses: vec![ + Ins{ c: '草', ins_type: InsType::Path(InsColl{ inses: vec![ + Ins{ c: '草', ins_type: InsType::Node(Instruction::Add) }, + Ins{ c: '泥', ins_type: InsType::Node(Instruction::Sub) }, + Ins{ c: '马', ins_type: InsType::Node(Instruction::Mul) }, + ]})}, + Ins{ c: '泥', ins_type: InsType::Path(InsColl{ inses: vec![ + Ins{ c: '草', ins_type: InsType::Node(Instruction::Div) }, + Ins{ c: '泥', ins_type: InsType::Node(Instruction::Mod) }, + ]})}, + ]})}, + Ins{ c: '泥', ins_type: InsType::Path(InsColl{ inses: vec![ + Ins{ c: '草', ins_type: InsType::Node(Instruction::Store) }, + Ins{ c: '泥', ins_type: InsType::Node(Instruction::Retrieve) }, + ]})}, + Ins{ c: '马', ins_type: InsType::Path(InsColl{ inses: vec![ + Ins{ c: '草', ins_type: InsType::Path(InsColl{ inses: vec![ + Ins{ c: '草', ins_type: InsType::Node(Instruction::StdOutChar) }, + Ins{ c: '泥', ins_type: InsType::Node(Instruction::StdOutNum) }, + ]})}, + Ins{ c: '泥', ins_type: InsType::Path(InsColl{ inses: vec![ + Ins{ c: '草', ins_type: InsType::Node(Instruction::StdInChar) }, + Ins{ c: '泥', ins_type: InsType::Node(Instruction::StdInNum) }, + ]})}, + ]})}, + ]})}, + Ins{ c: '马', ins_type: InsType::Path(InsColl{ inses: vec![ + Ins{ c: '草', ins_type: InsType::Path(InsColl{ inses: vec![ + Ins{ c: '草', ins_type: InsType::Node(Instruction::DefineLabel) }, + Ins{ c: '泥', ins_type: InsType::Node(Instruction::CallAtLabel) }, + Ins{ c: '马', ins_type: InsType::Node(Instruction::GotoLabel) }, + ]})}, + Ins{ c: '泥', ins_type: InsType::Path(InsColl{ inses: vec![ + Ins{ c: '草', ins_type: InsType::Node(Instruction::GotoLabelE0) }, + Ins{ c: '泥', ins_type: InsType::Node(Instruction::GotoLabelL0) }, + Ins{ c: '马', ins_type: InsType::Node(Instruction::ReturnCallAt) }, + ]})}, + Ins{ c: '马', ins_type: InsType::Path(InsColl{ inses: vec![ + Ins{ c: '马', ins_type: InsType::Node(Instruction::End) }, + ]})}, + ]})}, + ]} +} + +#[derive(Debug, Clone)] +pub enum Instruction { + Push, + Dup, + CopyN, + Swap, + Pop, + PopN, + Add, + Sub, + Mul, + Div, + Mod, + Store, + Retrieve, + DefineLabel, + CallAtLabel, + GotoLabel, + GotoLabelE0, + GotoLabelL0, + ReturnCallAt, + End, + StdOutChar, + StdOutNum, + StdInChar, + StdInNum, +} diff --git a/src/main.rs b/src/main.rs index e3e450d..7544fdd 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,112 +1,82 @@ -use err_derive::Error; +pub mod err;// TODO ... +mod ins; -#[derive(Debug, Error)] -pub enum ParseError { - #[error(display = "error syntax: {:?}", _0)] - ErrorSyntax(String), -} - -#[derive(Debug)] -enum Instruction { - Push, - Dup, - CopyN, - Swap, - Pop, - PopN, - Add, - Sub, - Mul, - Div, - Mod, - Store, - Retrieve, - DefineLabel, - CallAtLabel, - GotoLabel, - GotoLabelE0, - GotoLabelL0, - ReturnCallAt, - End, - StdOutChar, - StdOutNum, - StdInChar, - StdInNum, -} - -struct ParseChars { - index: usize, - chars: Vec, -} - -impl ParseChars { - fn next(&mut self) -> Option { - let c = self.try_next(); - if c.is_some() { self.index += 1; } - c - } - - fn try_next(&self) -> Option { - self.try_next_n(0_usize) - } - - fn try_next_n(&self, nn: usize) -> Option { - let i = self.index + nn; - if i >= self.chars.len() { - None - } else { - let c = self.chars[i]; - Some(c) - } - } -} +use ins::*; const VALID_INSTRUCTION_CHARS: &str = "草泥马河蟹"; +// https://playsecurity.org/rawfile/grass_mud_horse_language_specification.md +// https://p.rogram.me/grassmudhorse.js/grassmudhorse.js fn main() { let input = "草草草泥马 马草草草泥草草草草泥泥马 草马草 泥马草泥 草草草泥草泥草马 泥马草草 草草草泥马 泥草草草 草马草 草草草泥草泥泥马 泥草草泥 马泥草草泥草草草泥草泥马 马草马草泥草草草草泥泥马 马草草草泥草草草泥草泥马 草马马 马马马"; + + let mut cs = "草草草泥草泥泥马".chars(); + println!("{}", read_number(&mut cs)); println!("{:?}", parse_lang(input)); } -fn parse_lang(lang: &str) -> Result, ParseError> { - let mut r = vec![]; - - let mut cs = ParseChars{ index: 0_usize, chars: lang.chars().filter(|c| { - VALID_INSTRUCTION_CHARS.chars().any(|vic| vic == *c) - }).collect(), }; - while let Some(c) = cs.next() { - let nc = match cs.try_next() { - Some(nc) => nc, None => { - return Err(ParseError::ErrorSyntax( - format!("Syntax error: after {} has no valid char", c) - )); - }, - }; - if c == '草' && nc == '草' { // Push - cs.next(); - // todo parse - continue; +fn read_number(cs: &mut dyn Iterator) -> isize { + let mut is_positive = 1_isize; + if let Some(c) = cs.next() { + if c == '草' { + is_positive = 1; + } else if c == '泥' { + is_positive = -1; + } else { + // Syntax ERROR! } - let nnc = match cs.try_next_n(1) { - Some(nc) => nc, None => { - return Err(ParseError::ErrorSyntax( - format!("Syntax error: after {}{} has no valid char", c, nc) - )); - }, - }; - if c == '草' && nc == '马' || nnc == '草' { // Dup - - } - let nnnc = match cs.try_next_n(2) { - Some(nc) => nc, None => { - return Err(ParseError::ErrorSyntax( - format!("Syntax error: after {}{}{} has no valid char", c, nc, nnc) - )); - }, - }; + } else { + // Syntax ERROR! } - - Ok(r) + let mut num = 0_isize; + while let Some(c) = cs.next() { + if c == '马' { + break; + } else { + num <<= 1; + num += if c == '草' { 0 } else { 1 }; + } + } + is_positive * num } +fn match_instruction(ins_coll: &InsColl, cs: &mut dyn Iterator) -> Option { + if let Some(c) = cs.next() { + for ins in &ins_coll.inses { + if ins.c == c { + match &ins.ins_type { + InsType::Path(ins_coll) => return match_instruction(&ins_coll, cs), + InsType::Node(ins) => { + println!("{:?}", ins); + return Some(ins.clone()); + }, + } + } + } + println!("ERROR!!!! syntax error!"); + } + None +} + +fn parse_lang(lang: &str) {// -> Result, ParseError> { + // let mut r = vec![]; + + let instruction_tree_root = make_instruction_tree(); + + let mut cs = lang.chars().filter(|c| { + VALID_INSTRUCTION_CHARS.chars().any(|vic| vic == *c) + }); + + while let Some(ins) = match_instruction(&instruction_tree_root, &mut cs) { + println!("{:?}", ins); + } +} + +#[test] +fn test_read_number() { + assert_eq!(read_number(&mut "草泥马".chars()), 1); + assert_eq!(read_number(&mut "草泥草草草草泥泥马".chars()), 67); + assert_eq!(read_number(&mut "草泥草泥泥马".chars()), 11); + assert_eq!(read_number(&mut "草泥草草草泥草泥马".chars()), 69); +}