回答編集履歴

3

またバグ修正

2016/10/17 11:52

投稿

KSwordOfHaste
KSwordOfHaste

スコア18394

test CHANGED
@@ -140,7 +140,7 @@
140
140
 
141
141
  t.nextToken();
142
142
 
143
- return unaryExpression(t);
143
+ return -unaryExpression(t);
144
144
 
145
145
  case "(": {
146
146
 

2

バグ orz

2016/10/17 11:52

投稿

KSwordOfHaste
KSwordOfHaste

スコア18394

test CHANGED
@@ -148,7 +148,7 @@
148
148
 
149
149
  int result = additiveExpression(t);
150
150
 
151
- if (!t.nextToken.equals(")")
151
+ if (!t.currentToken.equals(")")
152
152
 
153
153
  throw new RuntimeException("syntax error");
154
154
 

1

例を追記

2016/10/17 11:46

投稿

KSwordOfHaste
KSwordOfHaste

スコア18394

test CHANGED
@@ -3,3 +3,175 @@
3
3
 
4
4
 
5
5
  「再帰下降構文解析」のキーワードでいくつかヒットすると思いますのでご自分が書いているコードと照らし合わせ、手頃なコード例が載っているサイトを探してみるとよいと思います。
6
+
7
+
8
+
9
+ 追記:
10
+
11
+
12
+
13
+ 優先順位ありの計算機をつくりたいとのことなので(再帰を使わなくても達成できますが)簡単な再帰下降構文解析の例を書いてみます。エッセンスを示すだけなので細かな処理は端折ります。数式の計算だと構文規則が割合単純なため演算子の優先順に従い直感的に書けます。(すみませんが動かしてないのでバグあったらゴメンナサイ)
14
+
15
+
16
+
17
+ ```java
18
+
19
+ // この方法ではトークンを1つ先読みできることが前提なのでこういうTokenizerがあると思ってください
20
+
21
+ // 簡単のために最後に必ず'='などの式の終わりを示すトークンがあると仮定します。
22
+
23
+ class Tokenizer extends StringTokenizer {
24
+
25
+ string currentToken;
26
+
27
+
28
+
29
+ string nextToken() {
30
+
31
+ string result = currentToken;
32
+
33
+ currentToken = nextToken();
34
+
35
+ return result;
36
+
37
+ }
38
+
39
+ }
40
+
41
+
42
+
43
+ class Calculation {
44
+
45
+ // ここが計算の入り口です
46
+
47
+ int evalExpression(Tokenizer t) {
48
+
49
+ t.nextToken(); // 常に1個だけトークンを先読みしておく。以降全て同じ
50
+
51
+ return additiveExpression(t);
52
+
53
+ }
54
+
55
+
56
+
57
+ // 加減算の式の計算:'+'や'-'がある限り計算します
58
+
59
+ int additiveExpression(Tokenizer t) {
60
+
61
+ int result = multiplicativeExpression(t);
62
+
63
+ for (;;) {
64
+
65
+ switch (t.currentToken) {
66
+
67
+ case "+":
68
+
69
+ t.nextToken();
70
+
71
+ result += multiplicativeExpression(t);
72
+
73
+ break;
74
+
75
+ case "-":
76
+
77
+ t.nextToken();
78
+
79
+ result -= multiplicativeExpression(t);
80
+
81
+ break;
82
+
83
+ case "=":
84
+
85
+ return result;
86
+
87
+ default:
88
+
89
+ throw new RuntimeException("syntax error");
90
+
91
+ }
92
+
93
+ }
94
+
95
+
96
+
97
+ // 乗除算の式の計算:'*'や'/'がある限り計算します
98
+
99
+ int multiplicativeExpression(Tokenizer t) {
100
+
101
+ int result = unaryExpression(t);
102
+
103
+ for (;;) {
104
+
105
+ switch (t.currentToken) {
106
+
107
+ case "*":
108
+
109
+ t.nextToken();
110
+
111
+ result *= unaryExpression(t);
112
+
113
+ break;
114
+
115
+ case "/":
116
+
117
+ t.nextToken();
118
+
119
+ result /= unaryExpression(t);
120
+
121
+ break;
122
+
123
+ default:
124
+
125
+ return result;
126
+
127
+ }
128
+
129
+ }
130
+
131
+
132
+
133
+ // 単項演算子、括弧、または数字の計算
134
+
135
+ int unaryExpression(Tokenizer t) {
136
+
137
+ switch (t.currentToken) {
138
+
139
+ case "-":
140
+
141
+ t.nextToken();
142
+
143
+ return unaryExpression(t);
144
+
145
+ case "(": {
146
+
147
+ t.nextToken();
148
+
149
+ int result = additiveExpression(t);
150
+
151
+ if (!t.nextToken.equals(")")
152
+
153
+ throw new RuntimeException("syntax error");
154
+
155
+ t.nextToken();
156
+
157
+ return result;
158
+
159
+ }
160
+
161
+ default: {
162
+
163
+ int result = Integer.parseInt(t.currentToken);
164
+
165
+ t.nextToken();
166
+
167
+ return result;
168
+
169
+ }
170
+
171
+ }
172
+
173
+ }
174
+
175
+ }
176
+
177
+ ```