Skip to content

Commit cc3856c

Browse files
committed
Add learning-rust
1 parent 5666f17 commit cc3856c

File tree

1 file changed

+167
-0
lines changed

1 file changed

+167
-0
lines changed

learning-rust/calc.rs

+167
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
use std::io::{self, Read, Write};
2+
use std::process::exit;
3+
use std::error::Error;
4+
use std::fmt;
5+
6+
// 型宣言 ////////////////////////////////////////////////////////////////////////
7+
8+
// ParseError -----------------------------------
9+
10+
#[derive(Debug)]
11+
struct ParseError {
12+
message: String,
13+
}
14+
15+
impl Error for ParseError {
16+
fn description(&self) -> &str {
17+
return &self.message;
18+
}
19+
}
20+
21+
impl fmt::Display for ParseError {
22+
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
23+
write!(f, "ParseError: {}", self.message)
24+
}
25+
}
26+
27+
// Node -----------------------------------------
28+
29+
#[derive(Debug)]
30+
enum Node {
31+
Integer(i64),
32+
Add(Box<Node>, Box<Node>),
33+
Mul(Box<Node>, Box<Node>),
34+
}
35+
36+
// alias ----------------------------------------
37+
38+
type ParseState<'a> = (Node, &'a str);
39+
type ParseResult<'a> = Result<ParseState<'a>, ParseError>;
40+
41+
// パース関数 ////////////////////////////////////////////////////////////////////
42+
43+
fn uncons(s: &str) -> (char, &str) {
44+
let mut it = s.chars();
45+
if let Some(ch) = it.next() {
46+
(ch, it.as_str())
47+
} else {
48+
('\0', s)
49+
}
50+
}
51+
52+
// digit ::= [0-9]
53+
fn parse_digit(s: &str) -> Result<(i64, &str), ParseError> {
54+
let (ch, rest) = uncons(s);
55+
match ch.to_digit(10) {
56+
Some(d) => Ok((d as i64, rest)),
57+
None => Err(ParseError{ message: "expected a digit".to_owned() }),
58+
}
59+
}
60+
61+
// integer ::= digit | integer digit
62+
fn parse_integer(s: &str) -> ParseResult {
63+
64+
fn iter(s: &str, acc: i64) -> ParseResult {
65+
match parse_digit(s) {
66+
Ok((d, rest)) => iter(rest, 10 * acc + d),
67+
Err(_) => Ok((Node::Integer(acc), s)),
68+
}
69+
}
70+
71+
let (d, rest) = parse_digit(s)?;
72+
iter(rest, d)
73+
}
74+
75+
// factor ::= integer | '(' expression ')'
76+
fn parse_factor(s: &str) -> ParseResult {
77+
let (ch, rest1) = uncons(s);
78+
match ch {
79+
'(' => {
80+
let (expr, rest2) = parse_expression(rest1)?;
81+
let (ch3, rest3) = uncons(rest2);
82+
if ch3 != ')' {
83+
return Err(ParseError{ message: "missing ')'".to_owned() });
84+
}
85+
Ok((expr, rest3))
86+
},
87+
_ => parse_integer(s),
88+
}
89+
}
90+
91+
// term ::= factor | term '*' factor
92+
fn parse_term(s: &str) -> ParseResult {
93+
94+
fn iter(s: &str, acc: Node) -> ParseResult {
95+
let (ch, rest1) = uncons(s);
96+
match ch {
97+
'*' => {
98+
let (rhs, rest2) = parse_factor(rest1)?;
99+
iter(rest2, Node::Mul(Box::new(acc), Box::new(rhs)))
100+
},
101+
_ => Ok((acc, s)),
102+
}
103+
}
104+
105+
let (factor, rest) = parse_factor(s)?;
106+
iter(rest, factor)
107+
}
108+
109+
// expression := term | expression '+' term
110+
fn parse_expression(s: &str) -> ParseResult {
111+
112+
fn iter(s: &str, acc: Node) -> ParseResult {
113+
let (ch, rest1) = uncons(s);
114+
match ch {
115+
'+' => {
116+
let (rhs, rest2) = parse_term(rest1)?;
117+
iter(rest2, Node::Add(Box::new(acc), Box::new(rhs)))
118+
},
119+
_ => Ok((acc, s)),
120+
}
121+
}
122+
123+
let (term, rest) = parse_term(s)?;
124+
iter(rest, term)
125+
}
126+
127+
// 評価器 ////////////////////////////////////////////////////////////////////////
128+
129+
fn eval(node: &Node) -> i64 {
130+
match node {
131+
&Node::Integer(x) => x,
132+
&Node::Add(ref lhs, ref rhs) => eval(lhs) + eval(rhs),
133+
&Node::Mul(ref lhs, ref rhs) => eval(lhs) * eval(rhs),
134+
}
135+
}
136+
137+
// その他 ////////////////////////////////////////////////////////////////////////
138+
139+
fn print_answer(answer: i64) {
140+
println!("Answer = {}", answer);
141+
}
142+
143+
fn read_input() -> io::Result<String> {
144+
let mut buffer = String::new();
145+
io::stdin().read_to_string(&mut buffer)?;
146+
return Ok(buffer);
147+
}
148+
149+
// TODO: あとで綺麗にする。
150+
fn do_main() -> Result<(), Box<Error>> {
151+
let input = try!(read_input());
152+
let (node, rest) = try!(parse_expression(input.trim()));
153+
if !rest.is_empty() {
154+
let e = ParseError{ message: "unexpected token".to_owned() };
155+
return Err(From::from(e));
156+
}
157+
let answer = eval(&node);
158+
print_answer(answer);
159+
Ok(())
160+
}
161+
162+
fn main() {
163+
exit(match do_main() {
164+
Ok(_) => 0,
165+
Err(e) => { writeln!(io::stderr(), "Error: {:?}", e).unwrap(); 1 },
166+
});
167+
}

0 commit comments

Comments
 (0)