Skip to content

Commit 86dbb73

Browse files
committedMar 16, 2021
tokenizer を整理
1 parent 4844635 commit 86dbb73

File tree

6 files changed

+122
-40
lines changed

6 files changed

+122
-40
lines changed
 

‎.gitignore

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
11
/target
2+
*.s

‎.vscode/launch.json

+19
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,25 @@
44
// 詳細情報は次を確認してください: https://go.microsoft.com/fwlink/?linkid=830387
55
"version": "0.2.0",
66
"configurations": [
7+
{
8+
"type": "lldb",
9+
"request": "launch",
10+
"name": "Debug unit tests in library 'toy_compiler'",
11+
"cargo": {
12+
"args": [
13+
"test",
14+
"--no-run",
15+
"--lib",
16+
"--package=toy_compiler"
17+
],
18+
"filter": {
19+
"name": "toy_compiler",
20+
"kind": "lib"
21+
}
22+
},
23+
"args": [],
24+
"cwd": "${workspaceFolder}"
25+
},
726
{
827
"type": "lldb",
928
"request": "launch",

‎src/compiler.rs

+38
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
use std::process::exit;
2+
use super::tokenizer::*;
3+
4+
pub fn error_exit(error_text: &str) -> ! {
5+
println!("{}", error_text);
6+
exit(1);
7+
}
8+
9+
pub fn expect_number(token_list: &mut TokenList) -> i32 {
10+
let token = token_list.pop_head();
11+
match token {
12+
Some(valid_token) => {
13+
match valid_token.token_kind {
14+
TokenKind::Number(num) => {return num;},
15+
_ => {error_exit("expect number token");}
16+
}
17+
},
18+
None => {
19+
error_exit("expect number token");
20+
},
21+
}
22+
}
23+
24+
pub fn expect_operation(token_list: &mut TokenList) -> TokenKind {
25+
let token = token_list.pop_head();
26+
match token {
27+
Some(valid_token) => {
28+
match valid_token.token_kind {
29+
TokenKind::Add => {return TokenKind::Add;},
30+
TokenKind::Sub => {return TokenKind::Sub;},
31+
_ => {error_exit("expect operation token");}
32+
}
33+
},
34+
None => {
35+
error_exit("expect operation token");
36+
},
37+
}
38+
}

‎src/lib.rs

+31
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
pub mod tokenizer;
2+
pub mod compiler;
3+
4+
#[cfg(test)]
5+
mod tests {
6+
use std::process::Command;
7+
use super::tokenizer::*;
8+
use super::compiler::*;
9+
10+
#[test]
11+
fn binary_test() {
12+
let status = Command::new("sh")
13+
.arg("-c")
14+
.arg("./a.out")
15+
.status()
16+
.expect("failed to execute mkdir").code().unwrap();
17+
assert_eq!(status, 10);
18+
}
19+
20+
#[test]
21+
fn tokenizer_test() {
22+
let input_text = "18 + 21 - 8";
23+
let mut token_list = text_tokenizer(input_text);
24+
assert_eq!(expect_number(&mut token_list), 18);
25+
assert_eq!(expect_operation(&mut token_list), TokenKind::Add);
26+
assert_eq!(expect_number(&mut token_list), 21);
27+
assert_eq!(expect_operation(&mut token_list), TokenKind::Sub);
28+
assert_eq!(expect_number(&mut token_list), 8);
29+
assert!(token_list.is_empty());
30+
}
31+
}

‎src/main.rs

+2-34
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use std::fs;
22
use std::io::{BufWriter, Write};
33

4-
mod tokenizer;
5-
use tokenizer::*;
4+
pub mod compiler;
5+
pub mod tokenizer;
66

77
fn write_header<T: Write>(buf:&mut T) {
88
writeln!(buf, ".intel_syntax noprefix").unwrap();
@@ -16,40 +16,8 @@ fn write_footer<T: Write>(buf:&mut T) {
1616
}
1717

1818
fn main() {
19-
20-
let input_text = "18 + 21 - 8";
21-
let mut tokens = text_tokenizer(input_text);
22-
let token = tokens.pop_head().unwrap();
23-
assert_eq!(token.token_kind, TokenKind::Number(18));
24-
let token = tokens.pop_head().unwrap();
25-
assert_eq!(token.token_kind, TokenKind::Add);
26-
let token = tokens.pop_head().unwrap();
27-
assert_eq!(token.token_kind, TokenKind::Number(21));
28-
let token = tokens.pop_head().unwrap();
29-
assert_eq!(token.token_kind, TokenKind::Sub);
30-
let token = tokens.pop_head().unwrap();
31-
assert_eq!(token.token_kind, TokenKind::Number(8));
32-
let token = tokens.pop_head();
33-
assert!(token.is_none());
34-
35-
3619
let mut file = BufWriter::new(fs::File::create("tmp.s").unwrap());
3720
write_header(&mut file);
3821
writeln!(file, " mov rax, 10").unwrap();
3922
write_footer(&mut file);
4023
}
41-
42-
#[cfg(test)]
43-
mod tests {
44-
use std::process::Command;
45-
46-
#[test]
47-
fn binary_test() {
48-
let status = Command::new("sh")
49-
.arg("-c")
50-
.arg("./a.out")
51-
.status()
52-
.expect("failed to execute mkdir").code().unwrap();
53-
assert_eq!(status, 10);
54-
}
55-
}

‎src/tokenizer.rs

+31-6
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use std::collections::VecDeque;
1+
use std::{collections::VecDeque, iter::FromIterator};
22

33
#[derive(Debug,PartialEq,Eq)]
44
pub enum TokenKind {
@@ -11,13 +11,15 @@ pub enum TokenKind {
1111
#[derive(Debug)]
1212
pub struct Token {
1313
pub token_kind: TokenKind,
14+
pub token_pos: i32,
1415
next: Option<Box<Token>>,
1516
}
1617

1718
impl Token {
18-
fn new() -> Token {
19+
fn new(token_pos: i32) -> Token {
1920
Token{
2021
token_kind: TokenKind::InvalidToken,
22+
token_pos,
2123
next: None,
2224
}
2325
}
@@ -37,26 +39,48 @@ impl TokenList {
3739

3840
pub fn pop_head(&mut self) -> Option<Box<Token>> {
3941
if let Some(mut token) = self.head.take() {
40-
self.head= token.next.take();
42+
self.head = token.next.take();
4143
return Some(token);
4244
} else {
4345
return None;
4446
}
4547
}
48+
49+
pub fn is_empty(&mut self) -> bool {
50+
self.head.is_none()
51+
}
52+
}
53+
54+
impl Drop for TokenList {
55+
fn drop(&mut self) {
56+
let mut token = self.head.take();
57+
loop {
58+
match token {
59+
Some(mut valid_token) => {
60+
let next_token = valid_token.next.take();
61+
token = next_token;
62+
},
63+
None => {break;},
64+
}
65+
}
66+
}
4667
}
4768

69+
// 入力テキストのトークン連結リストを作成する
4870
pub fn text_tokenizer(text: &str) -> TokenList {
49-
let mut char_queue = text.chars().collect::<VecDeque<char>>();
71+
let mut char_queue = VecDeque::from_iter(text.chars());
5072
let mut tokenlist = TokenList::new();
5173
let mut current_token = &mut tokenlist.head;
74+
let mut token_pos = -1;
5275

5376
while !char_queue.is_empty() {
5477
let ch = char_queue.pop_front().unwrap();
78+
token_pos += 1;
5579
if ch == ' ' {
5680
continue;
5781
}
5882

59-
let mut new_token = Token::new();
83+
let mut new_token = Token::new(token_pos);
6084

6185
if ch == '+' {
6286
new_token.token_kind = TokenKind::Add;
@@ -66,6 +90,7 @@ pub fn text_tokenizer(text: &str) -> TokenList {
6690
new_token.token_kind = TokenKind::Sub;
6791
}
6892

93+
// 数字処理の場合
6994
if ch.is_digit(10) {
7095
let mut num: i32 = ch.to_digit(10).unwrap() as i32;
7196
loop {
@@ -83,7 +108,7 @@ pub fn text_tokenizer(text: &str) -> TokenList {
83108
}
84109
new_token.token_kind = TokenKind::Number(num);
85110
}
86-
111+
87112
match current_token {
88113
Some(token) => {
89114
token.next = Some(Box::new(new_token));

0 commit comments

Comments
 (0)
Please sign in to comment.