teratail header banner
teratail header banner
質問するログイン新規登録

回答編集履歴

3

またバグ修正

2016/10/17 11:52

投稿

KSwordOfHaste
KSwordOfHaste

スコア18404

answer CHANGED
@@ -69,7 +69,7 @@
69
69
  switch (t.currentToken) {
70
70
  case "-":
71
71
  t.nextToken();
72
- return unaryExpression(t);
72
+ return -unaryExpression(t);
73
73
  case "(": {
74
74
  t.nextToken();
75
75
  int result = additiveExpression(t);

2

バグ orz

2016/10/17 11:52

投稿

KSwordOfHaste
KSwordOfHaste

スコア18404

answer CHANGED
@@ -73,7 +73,7 @@
73
73
  case "(": {
74
74
  t.nextToken();
75
75
  int result = additiveExpression(t);
76
- if (!t.nextToken.equals(")")
76
+ if (!t.currentToken.equals(")")
77
77
  throw new RuntimeException("syntax error");
78
78
  t.nextToken();
79
79
  return result;

1

例を追記

2016/10/17 11:46

投稿

KSwordOfHaste
KSwordOfHaste

スコア18404

answer CHANGED
@@ -1,3 +1,89 @@
1
1
  よく目にする一般的な数式の場合、単項演算子(-)は2項演算子(+,-,*,/)より優先度が高いというのを利用して再帰下降構文解析という手法を使うとよいと思います。単項演算子だけでなく括弧による優先順の変更や'*','/'を'+','-'よりも優先度を高くしたいといったことの実現にもうまくはまります。
2
2
 
3
- 「再帰下降構文解析」のキーワードでいくつかヒットすると思いますのでご自分が書いているコードと照らし合わせ、手頃なコード例が載っているサイトを探してみるとよいと思います。
3
+ 「再帰下降構文解析」のキーワードでいくつかヒットすると思いますのでご自分が書いているコードと照らし合わせ、手頃なコード例が載っているサイトを探してみるとよいと思います。
4
+
5
+ 追記:
6
+
7
+ 優先順位ありの計算機をつくりたいとのことなので(再帰を使わなくても達成できますが)簡単な再帰下降構文解析の例を書いてみます。エッセンスを示すだけなので細かな処理は端折ります。数式の計算だと構文規則が割合単純なため演算子の優先順に従い直感的に書けます。(すみませんが動かしてないのでバグあったらゴメンナサイ)
8
+
9
+ ```java
10
+ // この方法ではトークンを1つ先読みできることが前提なのでこういうTokenizerがあると思ってください
11
+ // 簡単のために最後に必ず'='などの式の終わりを示すトークンがあると仮定します。
12
+ class Tokenizer extends StringTokenizer {
13
+ string currentToken;
14
+
15
+ string nextToken() {
16
+ string result = currentToken;
17
+ currentToken = nextToken();
18
+ return result;
19
+ }
20
+ }
21
+
22
+ class Calculation {
23
+ // ここが計算の入り口です
24
+ int evalExpression(Tokenizer t) {
25
+ t.nextToken(); // 常に1個だけトークンを先読みしておく。以降全て同じ
26
+ return additiveExpression(t);
27
+ }
28
+
29
+ // 加減算の式の計算:'+'や'-'がある限り計算します
30
+ int additiveExpression(Tokenizer t) {
31
+ int result = multiplicativeExpression(t);
32
+ for (;;) {
33
+ switch (t.currentToken) {
34
+ case "+":
35
+ t.nextToken();
36
+ result += multiplicativeExpression(t);
37
+ break;
38
+ case "-":
39
+ t.nextToken();
40
+ result -= multiplicativeExpression(t);
41
+ break;
42
+ case "=":
43
+ return result;
44
+ default:
45
+ throw new RuntimeException("syntax error");
46
+ }
47
+ }
48
+
49
+ // 乗除算の式の計算:'*'や'/'がある限り計算します
50
+ int multiplicativeExpression(Tokenizer t) {
51
+ int result = unaryExpression(t);
52
+ for (;;) {
53
+ switch (t.currentToken) {
54
+ case "*":
55
+ t.nextToken();
56
+ result *= unaryExpression(t);
57
+ break;
58
+ case "/":
59
+ t.nextToken();
60
+ result /= unaryExpression(t);
61
+ break;
62
+ default:
63
+ return result;
64
+ }
65
+ }
66
+
67
+ // 単項演算子、括弧、または数字の計算
68
+ int unaryExpression(Tokenizer t) {
69
+ switch (t.currentToken) {
70
+ case "-":
71
+ t.nextToken();
72
+ return unaryExpression(t);
73
+ case "(": {
74
+ t.nextToken();
75
+ int result = additiveExpression(t);
76
+ if (!t.nextToken.equals(")")
77
+ throw new RuntimeException("syntax error");
78
+ t.nextToken();
79
+ return result;
80
+ }
81
+ default: {
82
+ int result = Integer.parseInt(t.currentToken);
83
+ t.nextToken();
84
+ return result;
85
+ }
86
+ }
87
+ }
88
+ }
89
+ ```