Rokiのチラ裏

学生による学習のログ

数式をRecursive Descent Parsing

数式(四則演算記号 +, -, *, /、括弧、数値のみから成る式)の解析が知人間で少し話題になってたので自分もrustで書いてみる。数式をBNFで表現してからコードに落とし込んだ結果、以下のようになった。面倒なので、unwrap_orをチェックしていない。

fn num(exp:&'static str,i:&mut usize)->i32{
    let mut result:i32=exp.chars().nth(*i).unwrap_or('A').to_digit(10).unwrap_or(0) as i32;
    *i+=1;
    while exp.chars().nth(*i).unwrap_or('A').is_digit(10) {
        result=result*10+exp.chars().nth(*i).unwrap_or('A').to_digit(10).unwrap_or(0)  as i32;
        *i+=1;
    }
    result
}

fn factor(exp:&'static str,i:&mut usize)->i32{
    if exp.chars().nth(*i).unwrap_or('A').is_digit(10) {
        return num(exp,i);
    }
    *i+=1;
    let result:i32=analyze(exp,i);
    *i+=1;
    result
}

fn term(exp:&'static str,i:&mut usize)->i32{
    let mut result:i32=factor(exp,i);
    while exp.chars().nth(*i).unwrap_or('A')=='*' || exp.chars().nth(*i).unwrap_or('A')=='/' {
        let op:char=exp.chars().nth(*i).unwrap_or('A');
        *i+=1;
        let tmp:i32=factor(exp,i);
        if op=='*'{
            result*=tmp;
        } else if op=='/' {
            result/=tmp;
        }
    
    }
    result
}

fn analyze(exp:&'static str,i:&mut usize)->i32{
    let mut result:i32=term(exp,i);
    while exp.chars().nth(*i).unwrap_or('A')=='+' || exp.chars().nth(*i).unwrap_or('A')=='-' {
        let op:char=exp.chars().nth(*i).unwrap_or('A');
        *i+=1;
        let tmp:i32=term(exp,i);
        if op=='+' {
            result+=tmp;
        } else if op=='-' {
            result-=tmp;
        }
    }
    result
}

fn main(){
    let exp:&'static str="(3+20)*6/(2+1)-2*2";
    let mut i:usize=0;
    println!("{}",analyze(&exp,&mut i));
}

output:

42