diff --git a/src/main.rs b/src/main.rs index 5542ad9..425d79e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -8,6 +8,9 @@ enum RegExp { Kleene(Box), } + +// Derivatives + fn is_nullable (r : &RegExp) -> bool { match r { RegExp::Epsilon => true, @@ -43,22 +46,102 @@ fn derivative(r : &RegExp, a : char) -> RegExp { } } -fn regexp_match(r : RegExp, s : &String) -> bool { - let chrs = s.chars(); - let mut rs : RegExp = r; - for c in chrs { - println!("Computing der({:?}, {:?}) ...", rs, c); - rs = derivative(&rs, c); +impl RegExp { + fn match_string(self : RegExp, s : &String) -> bool { + let chrs = s.chars(); + let mut rs : RegExp = self; + for c in chrs { + rs = derivative(&rs, c); + } + is_nullable(&rs) } - println!("Result: {:?}", rs); - is_nullable(&rs) } -fn main() { - let r1 = RegExp::Concat(Box::new( RegExp::Char('a')), Box::new( RegExp::Char('b'))); - let r2 = RegExp::Kleene(Box::new(r1.clone())); - let r3 = RegExp::Concat(Box::new(RegExp::Union(Box::new(r1.clone()), Box::new(RegExp::Char('c')))), Box::new(r2.clone())); - let inp = String::from("c"); - let res = regexp_match(r3.clone(), &inp); - println!("match {:?}, {:?} = {:?}", r3, inp, res); +use std::iter::Peekable; +use std::str::Chars; + +enum ParseError { + EatMismatch(char), + EndOfString, + Heh +} + +fn eat(str : &mut Peekable, c : char) -> Result { + match str.next_if(|&x| x == c) { + Some(c) => Ok(c), + None => Err(ParseError::EatMismatch(c)) + } +} + +fn term(str : &mut Peekable) -> Result { + let mut result = RegExp::Epsilon; + loop { + match str.peek() { + Some(&c) if (c != ')') & (c != '|') => { + let r = factor(str)?; + result = RegExp::Concat(Box::new(result), Box::new(r)) + }, + _ => { break; } + } + } + Ok(result) +} + +fn regex(str : &mut Peekable) -> Result { + let t = term(str)?; + match str.peek() { + Some('|') => { + let _ = eat(str, '|'); + let r = regex(str)?; + Ok(RegExp::Union(Box::new(t), Box::new(r))) + }, + _ => Ok(t) + } +} + +fn factor(str : &mut Peekable) -> Result { + let mut result = base(str)?; + loop { + match str.peek() { + Some(&c) if (c == '*') => { + let _ = eat(str, '*')?; + result = RegExp::Kleene(Box::new(result)) + }, + _ => { break; } + } + } + Ok(result) +} + +fn base(str : &mut Peekable) -> Result { + match str.peek() { + Some(&c) => { + if c == '(' { + let _ = eat(str, '(')?; + let r = regex(str)?; + let _ = eat(str, ')')?; + Ok(r) + } else { + let _ = eat(str, c)?; + Ok(RegExp::Char(c)) + } + }, + None => Err(ParseError::EndOfString) + } +} + +impl RegExp { + fn from(str : String) -> RegExp { + match regex(&mut str.chars().peekable()) { + Ok(r) => r, + _ => panic!("Ooooo") + } + } +} +fn main() { + let s1 = RegExp::from(String::from("(ab|c)(ab)*")); + let inp = String::from("abab"); + let res = s1.clone().match_string(&inp); + println!("match {:?}, {:?} = {:?}", s1, inp, res); + }