From 55f7068e91182dfe458fad41c3251388ea461569 Mon Sep 17 00:00:00 2001 From: JSDurand Date: Thu, 10 Aug 2023 11:15:53 +0800 Subject: Add an example 'bfinterp' My plan is to build a little interpreter for an esoteric programming language as the most basic application of this package, before embarking on some more ambitious applications. --- examples/bfinterp.rs | 84 ++++++++++++++++++++++++++++++++++++++++++++++++ test-data/brainfuck.abnf | 4 +++ 2 files changed, 88 insertions(+) create mode 100644 examples/bfinterp.rs create mode 100644 test-data/brainfuck.abnf diff --git a/examples/bfinterp.rs b/examples/bfinterp.rs new file mode 100644 index 0000000..d5a0c2a --- /dev/null +++ b/examples/bfinterp.rs @@ -0,0 +1,84 @@ +fn main() -> Result<(), Box> { + let input_str = if let Some(string) = std::env::args().skip(1).next() { + string + } else { + return Err("An input program is required.".into()); + }; + + let input = tokenize(&input_str)?; + + let grammar_string = "brainfuck = *unit + +unit = \">\" / \"<\" / \"+\" / \"-\" / \",\" / \";\" / + \"[\" brainfuck \"]\""; + + let grammar: grammar::Grammar = grammar_string.parse().map_err(|err| format!("{err}"))?; + + println!("grammar = {grammar}"); + + let atom: chain::atom::DefaultAtom = + chain::atom::DefaultAtom::from_grammar(grammar).map_err(|err| format!("{err}"))?; + + // atom.print_viz("nfa.gv")?; + + use chain::Chain; + + let mut chain: chain::default::DefaultChain = + chain::default::DefaultChain::unit(atom).map_err(|err| format!("{err}"))?; + + // let input = [0, 1, 6, 2, 6, 3, 4, 6, 5, 2, 7, 4, 7, 3, 2, 7, 2]; + + for (index, token) in input.iter().copied().enumerate() { + chain.chain(token, index, false)?; + // if (5..=12).contains(&index) { + // chain.print_current(&format!("chain {index}.gv"))?; + // } + } + + let _extracted = chain.end_of_input(input.len(), input[input.len() - 1])?; + + // use graph::Graph; + + // extracted.print_viz("bf.gv")?; + + Ok(()) +} + +fn tokenize(input: &str) -> Result, String> { + let mut result: Vec = Vec::with_capacity(input.len()); + + for (index, c) in input.chars().enumerate() { + match c { + '>' => { + result.push(0); + } + '<' => { + result.push(1); + } + '+' => { + result.push(2); + } + '-' => { + result.push(3); + } + ',' => { + result.push(4); + } + ';' => { + result.push(5); + } + '[' => { + result.push(6); + } + ']' => { + result.push(7); + } + ' ' | '\t' | '\n' | '\r' => {} + _ => { + return Err(format!("Unknown character {c} at {index}")); + } + } + } + + Ok(result) +} diff --git a/test-data/brainfuck.abnf b/test-data/brainfuck.abnf new file mode 100644 index 0000000..df3d1da --- /dev/null +++ b/test-data/brainfuck.abnf @@ -0,0 +1,4 @@ +brainfuck = *unit + +unit = ">" / "<" / "+" / "-" / "," / ";" / + "[" brainfuck "]" -- cgit v1.2.3-18-g5258