use std::collections::HashMap;
pub type Value = i32;
pub type Result = std::result::Result<(), Error>;
type Stackop = fn(&mut Forth);
pub struct Builtin {
stack_min: usize,
func: Stackop
}
pub struct Forth {
v: Vec<Value>,
f: HashMap<String,usize>,
b: HashMap<String,Builtin>,
s: Vec<Vec<String>>,
func: Vec<String>,
}
#[derive(Debug, PartialEq)]
pub enum Error {
DivisionByZero,
StackUnderflow,
UnknownWord,
InvalidWord,
}
impl Forth {
pub fn op_drop(&mut self) {
self.v.pop();
}
pub fn op_dup(&mut self) {
let temp = self.v[self.v.len() - 1];
self.v.push(temp);
}
pub fn op_over(&mut self) {
let temp = self.v[self.v.len() - 2];
self.v.push(temp);
}
pub fn op_swap(&mut self) {
let size = self.v.len();
let temp = self.v[size - 2];
self.v[size - 2] = self.v[size - 1];
self.v[size - 1] = temp;
}
pub fn new() -> Forth {
let mut temp: Vec<Vec<String>> = Vec::new();
temp.push(Vec::new());
let mut ftab: HashMap::<String,Builtin> = HashMap::new();
ftab.insert("drop".to_string(), Builtin{stack_min:1,func:Self::op_drop});
ftab.insert("dup" .to_string(), Builtin{stack_min:1,func:Self::op_dup});
ftab.insert("over".to_string(), Builtin{stack_min:2,func:Self::op_over});
ftab.insert("swap".to_string(), Builtin{stack_min:2,func:Self::op_swap});
Forth{v: Vec::<Value>::new(), f: HashMap::new(), b:ftab, s: temp, func: Vec::new()}
}
pub fn stack(&self) -> &[Value] {
&self.v
}
pub fn eval(&mut self, input: &str) -> Result {
self.v.clear();
self.s[0].clear();
println!("\neval({})", input);
// Parse the input text and store it in a vector
{
let temp: Vec<&str> = input.split(' ').collect();
let n = temp.len() as i32;
for x in 0..n as usize {
self.s[0].push(String::from(temp[x]));
}
}
Self::exec(self, 0)
}
pub fn exec(&mut self, sx: usize) -> Result {
let n: usize = self.s[sx].len();
let mut collecting = false;
// User-defined functions store the function name at index 0,
// so start with 1 unless it's the primary input line (sx == 0)
let lo:usize = if sx == 0 {0} else {1};
for x in lo..n as usize {
let word = &self.s[sx][x];
if word == ";" {
if collecting {
collecting = false;
let index: usize = self.s.len(); // 1 for main + 1 for each function
self.s.push(Vec::<String>::new()); // Create vec for new user-def function
for item in self.func.iter() {
if self.s[index].len() > 0 && self.appropriate(&item,index)
{
let sx = *self.f.get(item).unwrap();
let n = self.s[sx].len();
for x in 1..n as usize {
let symbol = self.s[sx][x].clone();
self.s[index].push(symbol);
}
}
else {
self.s[index].push(item.to_string());
}
}
self.f.insert(self.s[index][0].clone().to_lowercase(), index);
self.func.clear();
continue;
}
continue;
}
if collecting {
self.func.push(String::from(word));
continue;
}
if word == ":" {
// There must be at least 3 more operands after a colon
if self.s[sx].len() < x + 4 {return Err(Error::InvalidWord);}
// In this implementation, numbers are not allowed to be function
// names.
match self.s[sx][x+1].parse::<Value>() {
Ok(_) => { return Err(Error::InvalidWord); },
_ => ()
}
// It's not a number, so we can proceed.
collecting = true;
self.func.clear();
continue;
}
// Integer values are just pushed onto the stack
match word.parse::<Value>() {
Ok(value) => { self.v.push(value); continue; },
_ => {}
}
// User-defined functions
let lower = word.to_lowercase();
if self.f.contains_key(&lower) {
let sx = *self.f.get(&lower).unwrap();
match Self::exec(self, sx) {
Ok(_) => continue,
Err(e) => return Err(e)
};
}
// Binary arithmetic operators
if Self::is_op(word) {
if self.v.len() < 2 {
return Err(Error::StackUnderflow);
}
let b = self.v.pop().unwrap();
let a = self.v.pop().unwrap();
let c = match word.as_str() {
"+" => a + b,
"-" => a - b,
"*" => a * b,
"/" => {if b == 0 {return Err(Error::DivisionByZero);} a / b},
_ => 0
};
self.v.push(c);
continue;
}
// Built-in functions
let p = self.b.get(&lower);
match p {
Some(param) => {
if self.v.len() < param.stack_min {
return Err(Error::StackUnderflow);
}
(param.func)(self);
continue;
},
_ => { return Err(Error::UnknownWord); }
}
} // end loop
Ok(())
}
fn is_op(input: &str) -> bool {
match input {"+"|"-"|"*"|"/" => true, _ => false}
}
fn appropriate(&self, item:&str, index:usize) -> bool
{
// Is it appropriate to emit the previous definition of a user-defined function?
if self.s[index][0] == item {
true // Yes because we are redefining a previously defined function
}
else {
if index >= self.s.len() {
false // Guard to be sure index is meaningful
}
else {
if let Some(&sx) = self.f.get(item) {
// Yes if the previous definition is a single term
// and therefore will not increase storage requirements.
// Length 2 means 1 for the function name and 1 for its definition.
self.s[sx].len() == 2
}
else {
false
}
}
}
}
}
fn main() {
let cmd = [
": f over over + ;",
"1 1 f f f f f f f f f f f"
];
let mut f = Forth::new();
for line in cmd {
f.eval(line);
println!("stack = {:?}", f.stack());
}
}
Comments
0 B
|👍
/👎
0 B
|👍
/👎