Skip to content

Instantly share code, notes, and snippets.

@sozysozbot
Last active November 24, 2022 10:27
Show Gist options
  • Save sozysozbot/27383570b9d01d91736f7de294df75a8 to your computer and use it in GitHub Desktop.
Save sozysozbot/27383570b9d01d91736f7de294df75a8 to your computer and use it in GitHub Desktop.
#[test]
fn test_eat_primary() {
assert_eq!(eat_primary("3+5"), (3, "+5"));
assert_eq!(eat_primary("8-5*4+3"), (8, "-5*4+3"));
}
// 先頭から数字を一個食って、「食った数字と食い残した文字列」を返す
fn eat_primary(s: &str) -> (i32, &str) {
if s.starts_with('0') { return (0, &s[1..]); }
if s.starts_with('1') { return (1, &s[1..]); }
if s.starts_with('2') { return (2, &s[1..]); }
if s.starts_with('3') { return (3, &s[1..]); }
if s.starts_with('4') { return (4, &s[1..]); }
if s.starts_with('5') { return (5, &s[1..]); }
if s.starts_with('6') { return (6, &s[1..]); }
if s.starts_with('7') { return (7, &s[1..]); }
if s.starts_with('8') { return (8, &s[1..]); }
if s.starts_with('9') { return (9, &s[1..]); }
if s.starts_with('(') {
let (result, remaining) = eat_expression(&s[1..]);
if remaining.starts_with(')') {
(result, &remaining[1..])
} else {
panic!("`{}` を読もうとしましたが、左カッコに対応する右カッコが見当たりません", s);
}
} else {
panic!("`{}` の先頭の文字を処理できませんでした", s);
}
}
#[test]
fn test_eat_multiplicative() {
assert_eq!(eat_multiplicative("3+7"), (3, "+7"));
assert_eq!(eat_multiplicative("3*5+7"), (15, "+7"));
assert_eq!(eat_multiplicative("3*5*7+7"), (105, "+7"));
}
fn eat_multiplicative(s: &str) -> (i32, &str) {
// まず primary を食う
let (mut result, mut remaining) = eat_primary(s);
// "*" の後に primary が来る構造が0回以上繰り返される
loop {
// "*" が来ないなら、食うのをやめる
if !remaining.starts_with('*') { break; }
// 先頭の * を削って、もう一個 primary を食べる
let (result2, remaining2) = eat_primary(&remaining[1..]);
// 計算結果がほしいので、どんどん掛け算していく
result *= result2;
remaining = remaining2;
}
(result, remaining)
}
#[test]
fn test_eat_expression() {
assert_eq!(eat_expression("3-5+7"), (5, ""));
assert_eq!(eat_expression("3*5+7"), (22, ""));
assert_eq!(eat_expression("3*5+7*4"), (43, ""));
assert_eq!(eat_expression("3*5+7*4-2*3*5"), (13, ""));
assert_eq!(eat_expression("3*(5+7-3)*(6-(3-(2+(4))+5))"), (3*(5+7-3)*(6-(3-(2+(4))+5)), ""));
}
fn eat_expression(s: &str) -> (i32, &str) {
let (mut result, mut remaining) = eat_multiplicative(s);
// "+" か "-" の後に multiplicative が来る構造が0回以上繰り返される
loop {
// "+" も "-" も来ないなら、食うのをやめる
if !remaining.starts_with('+') && !remaining.starts_with('-') { break; }
let is_plus = remaining.starts_with('+');
// 先頭の + または - を削って、もう一個 multiplicative を食べる
let (result2, remaining2) = eat_multiplicative(&remaining[1..]);
// 計算結果がほしいので、どんどん足し引きしていく
if is_plus {
result += result2;
} else {
result -= result2;
}
remaining = remaining2;
}
(result, remaining)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment