1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
/*字句リスト*/
use std::char;

#[derive(Debug, PartialEq, Clone)]
pub enum Token {
    Number(f64),
    Times,
    Div,
    Frac,
    Plus,
    Minus,
    LParen,
    RParen,
    LBrace,
    RBrace,
}

/*字句解析器の構造定義*/
pub struct Lexer {
    input: Vec<char>,
    position: usize,
}

/*字句解析器*/
impl Lexer {
    pub fn init(input: Vec<char>) -> Lexer {
        Lexer { input, position: 0 }
    }
    //token関数に構造体Lexerを渡す
    pub fn token(&mut self) -> Result<Option<Token>, String> {
        while self.curr().is_some() && self.curr().unwrap().is_whitespace() {
            self.next();
        }
        let token = if self.curr().is_some() && Self::is_number(self.curr().unwrap()) {
            //数字を読み込んだ場合
            let mut number = vec![*self.curr().unwrap()];
            while self.peek().is_some() && Self::is_number(self.peek().unwrap()) {
                self.next();
                number.push(*self.curr().unwrap());
            }
            Ok(String::from_iter(number)
                .parse::<f64>()
                .ok()
                .map(Token::Number))
        } else if self.curr() == Some(&'\\') {
            //コマンドを読み込んだ場合
            let mut command = vec![*self.curr().unwrap()];
            while self.peek().is_some() && self.peek().unwrap().is_ascii_alphabetic() {
                self.next();
                command.push(*self.curr().unwrap());
            }
            match String::from_iter(command).as_str() {
                "\\times" => Ok(Some(Token::Times)),
                "\\div" => Ok(Some(Token::Div)),
                "\\frac" => Ok(Some(Token::Frac)),
                _ => Err(String::from("unknown command")),
            }
        } else {
            //それ以外を読み込んだ場合
            match self.curr() {
                Some('+') => Ok(Some(Token::Plus)),
                Some('-') => Ok(Some(Token::Minus)),
                Some('(') => Ok(Some(Token::LParen)),
                Some(')') => Ok(Some(Token::RParen)),
                Some('{') => Ok(Some(Token::LBrace)),
                Some('}') => Ok(Some(Token::RBrace)),
                None => Ok(None),
                _ => Err(String::from("unknown character")),
            }
        };
        self.next();
        token
    }
    fn next(&mut self) {
        self.position += 1
    }
    fn curr(&mut self) -> Option<&char> {
        self.input.get(self.position)
    }
    fn peek(&mut self) -> Option<&char> {
        self.input.get(self.position + 1)
    }
    fn is_number(c: &char) -> bool {
        c.is_ascii_digit() || c == &'.'
    }
}