• R/O
  • SSH
  • HTTPS

npl: コミット


コミットメタ情報

リビジョン64 (tree)
日時2017-09-10 00:48:57
作者tamiya25

ログメッセージ

stackテスト、calc言語

変更サマリ

差分

--- trunk/npl/test/stack/test2.c (revision 0)
+++ trunk/npl/test/stack/test2.c (revision 64)
@@ -0,0 +1,82 @@
1+// enter と leave。
2+//
3+// npl_stack_enter() は現在のスタックに、
4+// 新しいローカルなスタックを作る。
5+// (以前に積まれた内容を保存した上で、
6+// 新しい空のスタックにする。)
7+//
8+// npl_stack_leave() はローカルなスタック
9+// を抜け、以前の内容に戻す。
10+//
11+// これらは何重にもネスト可能。
12+
13+#include <stdio.h>
14+#include <stdlib.h>
15+#include <string.h>
16+#include "../../npl.h"
17+
18+void push_int(npl_stack_t *s, int i)
19+{
20+ if (npl_stack_push(s, sizeof(int), &i)) {
21+ fprintf(stderr, "push_int() failed.\n");
22+ exit(1);
23+ }
24+}
25+
26+// スタックから int 型のデータを取り出し、表示。
27+void show_stack(npl_stack_t *s)
28+{
29+ int i;
30+
31+ while (!npl_stack_pop(s, sizeof(int), &i))
32+ printf("%d\n", i);
33+}
34+
35+int main(void)
36+{
37+ npl_stack_t *s;
38+
39+ if (npl_init()) {
40+ fprintf(stderr, "npl_init() failed.\n");
41+ exit(1);
42+ }
43+
44+ // 新しいスタック・オブジェクトを作成する
45+ if ((s = npl_stack_new()) == NULL) {
46+ fprintf(stderr, "npl_stack_new() failed.\n");
47+ exit(1);
48+ }
49+
50+ // スタック操作
51+ push_int(s, 1);
52+ push_int(s, 2);
53+ push_int(s, 3);
54+
55+ npl_stack_enter(s);
56+ push_int(s, 10);
57+ push_int(s, 20);
58+ push_int(s, 30);
59+
60+ npl_stack_enter(s);
61+ push_int(s, 100);
62+
63+ npl_stack_enter(s);
64+ push_int(s, 2000);
65+
66+ npl_stack_leave(s);
67+ npl_stack_leave(s);
68+
69+ // 現在の(ローカルの)スタックの中を表示。
70+ show_stack(s);
71+
72+ // オブジェクトは、もう参照しない
73+ npl_object_unref(NPL_OBJECT(s));
74+
75+ if (npl_final()) {
76+ fprintf(stderr, "npl_final() failed.\n");
77+ exit(1);
78+ }
79+
80+ return 0;
81+}
82+
--- trunk/npl/test/stack/calc.c (revision 0)
+++ trunk/npl/test/stack/calc.c (revision 64)
@@ -0,0 +1,489 @@
1+// calc.c
2+//
3+// 簡易なスタック式電卓。
4+//
5+// 数式の文字列を解析、
6+// 中置記法から後置記法へコンパイル、
7+// そして、計算の実行まで行う。
8+
9+#include <stdio.h>
10+#include <stdlib.h>
11+#include <string.h>
12+#include <limits.h>
13+#include "../../npl.h"
14+
15+typedef struct Code Code;
16+
17+// スタックに積まれる内容物
18+struct Code {
19+ int code; // 0: num 1: op 2: ( 3: )
20+
21+ union {
22+ // 数値
23+ int num;
24+
25+ // 演算子。
26+ // 0: + 1: - 2: * 3: / 4: %
27+ // 5: 単項+ 6: 単項-
28+ int op;
29+ };
30+};
31+
32+void push_num(npl_stack_t *s, int num)
33+{
34+ Code c;
35+
36+ c.code = 0;
37+ c.num = num;
38+
39+ if (npl_stack_push(s, sizeof(Code), &c)) {
40+ fprintf(stderr, "push_num() failed.\n");
41+ exit(1);
42+ }
43+}
44+
45+void push_op(npl_stack_t *s, int op)
46+{
47+ Code c;
48+
49+ if (op < 0 || 3 < op) {
50+ fprintf(stderr, "push_op() failed.\n");
51+ exit(1);
52+ }
53+
54+ c.code = 1;
55+ c.op = op;
56+
57+ if (npl_stack_push(s, sizeof(Code), &c)) {
58+ fprintf(stderr, "push_op() failed.\n");
59+ exit(1);
60+ }
61+}
62+
63+void push_lp(npl_stack_t *s)
64+{
65+ Code c;
66+
67+ c.code = 2;
68+ if (npl_stack_push(s, sizeof(Code), &c)) {
69+ fprintf(stderr, "push_op() failed.\n");
70+ exit(1);
71+ }
72+}
73+
74+void push_rp(npl_stack_t *s)
75+{
76+ Code c;
77+
78+ c.code = 3;
79+ if (npl_stack_push(s, sizeof(Code), &c)) {
80+ fprintf(stderr, "push_op() failed.\n");
81+ exit(1);
82+ }
83+}
84+
85+int pop_num(npl_stack_t *s, int *num)
86+{
87+ Code c;
88+
89+ if (npl_stack_pop(s, sizeof(Code), &c))
90+ return 1;
91+ if (c.code != 0)
92+ return 1;
93+
94+ *num = c.num;
95+ return 0;
96+}
97+
98+void push_code(npl_stack_t *s, Code *c)
99+{
100+ if (npl_stack_push(s, sizeof(Code), c)) {
101+ fprintf(stderr, "push_int() failed.\n");
102+ exit(1);
103+ }
104+}
105+
106+int pop_code(npl_stack_t *s, Code *c)
107+{
108+ return npl_stack_pop(s, sizeof(Code), c);
109+}
110+
111+int get_code(npl_stack_t *s, Code *c)
112+{
113+ return npl_stack_get(s, 0, sizeof(Code), c);
114+}
115+
116+void remove_code(npl_stack_t *s)
117+{
118+ npl_stack_remove(s, sizeof(Code));
119+}
120+
121+// a のすべての内容をポップして、
122+// b にプッシュする。
123+void pop_code_all(npl_stack_t *a, npl_stack_t *b)
124+{
125+ Code c;
126+
127+ while (pop_code(a, &c) == 0)
128+ push_code(b, &c);
129+}
130+
131+npl_stack_t* my_stack_new()
132+{
133+ npl_stack_t *s;
134+
135+ if ((s = npl_stack_new()) == NULL) {
136+ fprintf(stderr, "my_stack_new() failed.\n");
137+ exit(1);
138+ }
139+
140+ return s;
141+}
142+
143+void my_stack_unref(npl_stack_t *s)
144+{
145+ npl_object_unref(NPL_OBJECT(s));
146+}
147+
148+void my_stack_enter(npl_stack_t *s)
149+{
150+ if (npl_stack_enter(s)) {
151+ fprintf(stderr, "my_stack_enter() failed.\n");
152+ exit(1);
153+ }
154+}
155+
156+void my_stack_leave(npl_stack_t *s)
157+{
158+ if (npl_stack_leave(s)) {
159+ fprintf(stderr, "my_stack_leave() failed.\n");
160+ exit(1);
161+ }
162+}
163+
164+int is_num(wchar_t wc)
165+{
166+ if (L'0' <= wc && wc <= L'9')
167+ return 1;
168+
169+ return 0;
170+}
171+
172+int to_num(wchar_t wc)
173+{
174+ if (L'0' <= wc && wc <= L'9')
175+ return wc - L'0';
176+
177+ fprintf(stderr, "to_num() failed\n");
178+ exit(1);
179+
180+ return -1;
181+}
182+
183+// 後置記法コード(実行コード)を計算する
184+int calc(npl_stack_t *s)
185+{
186+ int result;
187+ npl_stack_t *t; // 計算用
188+ Code c;
189+
190+ if ((t = npl_stack_new()) == NULL) {
191+ fprintf(stderr, "calc() failed.\n");
192+ exit(1);
193+ }
194+
195+ while (!pop_code(s, &c)) {
196+ if (c.code == 0) {
197+ push_num(t, c.num);
198+ } else if (c.code == 1) {
199+ int a, b, n;
200+
201+ // スタック(計算用)での順番に注意!
202+ switch (c.op) {
203+ case 0:
204+ if (pop_num(t, &b))
205+ goto ERROR;
206+ if (pop_num(t, &a))
207+ goto ERROR;
208+ n = a + b;
209+ break;
210+ case 1:
211+ if (pop_num(t, &b))
212+ goto ERROR;
213+ if (pop_num(t, &a))
214+ goto ERROR;
215+ n = a - b;
216+ break;
217+ case 2:
218+ if (pop_num(t, &b))
219+ goto ERROR;
220+ if (pop_num(t, &a))
221+ goto ERROR;
222+ n = a * b;
223+ break;
224+ case 3:
225+ if (pop_num(t, &b))
226+ goto ERROR;
227+ if (pop_num(t, &a))
228+ goto ERROR;
229+ n = a / b;
230+ break;
231+ case 4:
232+ if (pop_num(t, &b))
233+ goto ERROR;
234+ if (pop_num(t, &a))
235+ goto ERROR;
236+ n = a % b;
237+ break;
238+ case 5:
239+ if (pop_num(t, &a))
240+ goto ERROR;
241+ n = a;
242+ break;
243+ case 6:
244+ if (pop_num(t, &a))
245+ goto ERROR;
246+ n = -a;
247+ break;
248+ default:
249+ fprintf(stderr, "calc() failed.\n");
250+ exit(1);
251+ }
252+
253+ push_num(t, n);
254+ }
255+ }
256+
257+ npl_stack_clean(s);
258+ pop_code_all(t, s);
259+ npl_object_unref(NPL_OBJECT(t));
260+
261+ return 0; // success
262+
263+ERROR:
264+ npl_object_unref(NPL_OBJECT(t));
265+ return 1; // error
266+}
267+
268+// 中置記法コード(トークン)を
269+// 後置記法コード(実行コード)に変換する。
270+int compile(npl_stack_t *s)
271+{
272+ npl_stack_t *t, *u, *v;
273+ Code code, c;
274+ int first; // 単項演算子を判別するため
275+
276+ // セットアップ
277+ t = my_stack_new();
278+ u = my_stack_new();
279+ v = my_stack_new();
280+ pop_code_all(s, t);
281+
282+ // 変換処理
283+ first = 1;
284+ while (pop_code(t, &code) == 0) {
285+ if (code.code == 0) {
286+ push_code(v, &code);
287+ first = 0;
288+ } else if (code.code == 1) {
289+ while (get_code(u, &c) == 0) {
290+ if (code.op == 0 || code.op == 1)
291+ push_code(v, &c);
292+ if (code.op == 2 || code.op == 3)
293+ if (c.op == 0 || c.op == 1)
294+ break;
295+ else
296+ push_code(v, &c);
297+ remove_code(u);
298+ }
299+ if (first) {
300+ if (code.op == 0)
301+ code.op = 5;
302+ if (code.op == 1)
303+ code.op = 6;
304+ first = 0;
305+ }
306+ push_code(u, &code);
307+ } else if (code.code == 2) {
308+ my_stack_enter(u);
309+ first = 1;
310+ } else if (code.code == 3) {
311+ pop_code_all(u, v);
312+ my_stack_leave(u);
313+ first = 0;
314+ }
315+ }
316+
317+ pop_code_all(u, v);
318+ pop_code_all(v, s);
319+
320+ // 終了
321+ npl_object_unref(NPL_OBJECT(v));
322+ npl_object_unref(NPL_OBJECT(u));
323+ npl_object_unref(NPL_OBJECT(t));
324+
325+ return 0;
326+}
327+
328+// 数式を表す文字列を字句解析して、
329+// 中置記法コード(トークン)をスタック s に
330+// 格納する。
331+int parse(wchar_t *sbuf, npl_stack_t *s)
332+{
333+ int num, n;
334+ int flag; // num が続いていることを示す。
335+ size_t i;
336+ Code code;
337+
338+ flag = 0;
339+ for (i=0; sbuf[i] != L'\0'; i++) {
340+ if (sbuf[i] == L'\n')
341+ break;
342+ if (flag) {
343+ if (is_num(sbuf[i])) {
344+ n = to_num(sbuf[i]);
345+ if (num != 0 && 10 > (INT_MAX / num))
346+ return 1;
347+ num *= 10;
348+ if (num + n < num)
349+ return 1;
350+ num += n;
351+ continue;
352+ } else {
353+ code.code = 0;
354+ code.op = num;
355+ push_code(s, &code);
356+ flag = 0;
357+ }
358+ }
359+ if (is_num(sbuf[i])) {
360+ num = to_num(sbuf[i]);
361+ flag = 1;
362+ } else {
363+ switch (sbuf[i]) {
364+ case L' ':
365+ case L'\t':
366+ break;
367+ case L'+':
368+ code.code = 1;
369+ code.op = 0;
370+ push_code(s, &code);
371+ break;
372+ case L'-':
373+ code.code = 1;
374+ code.op = 1;
375+ push_code(s, &code);
376+ break;
377+ case L'*':
378+ code.code = 1;
379+ code.op = 2;
380+ push_code(s, &code);
381+ break;
382+ case L'/':
383+ code.code = 1;
384+ code.op = 3;
385+ push_code(s, &code);
386+ break;
387+ case L'%':
388+ code.code = 1;
389+ code.op = 4;
390+ push_code(s, &code);
391+ break;
392+ case L'(':
393+ code.code = 2;
394+ code.num = 0;
395+ push_code(s, &code);
396+ break;
397+ case L')':
398+ code.code = 3;
399+ code.num = 0;
400+ push_code(s, &code);
401+ break;
402+ default:
403+ return 1;
404+ break;
405+ }
406+ }
407+ }
408+
409+ if (flag) {
410+ code.code = 0;
411+ code.op = num;
412+ push_code(s, &code);
413+ }
414+
415+ return 0;
416+}
417+
418+int main(void)
419+{
420+ npl_stream_t *out, *in;
421+ npl_sbuf_t *sbuf;
422+ npl_stack_t *s;
423+ int num;
424+
425+ if (npl_init()) {
426+ fprintf(stderr, "npl_init() failed.\n");
427+ exit(1);
428+ }
429+
430+ // ストリーム
431+ if ((out = npl_stream_stdout()) == NULL) {
432+ fprintf(stderr, "npl_stream_stdout() failed.\n");
433+ exit(1);
434+ }
435+ if ((in = npl_stream_stdin()) == NULL) {
436+ fprintf(stderr, "npl_stream_stdin() failed.\n");
437+ exit(1);
438+ }
439+
440+ // 文字列バッファ
441+ if ((sbuf = npl_sbuf_new()) == NULL) {
442+ fprintf(stderr, "npl_sbuf_new() failed.\n");
443+ exit(1);
444+ }
445+
446+ // 新しいスタック・オブジェクトを作成する
447+ if ((s = npl_stack_new()) == NULL) {
448+ fprintf(stderr, "npl_stack_new() failed.\n");
449+ exit(1);
450+ }
451+
452+ // 数式インタプリタ
453+ while (!npl_stream_eof(in) && !npl_stream_error(in)) {
454+ npl_stream_write(out, L" >> ");
455+ if (npl_stream_read(in, sbuf))
456+ break;
457+
458+ npl_stack_clean(s);
459+ if (parse(npl_buf_get(NPL_BUF(sbuf)), s)) {
460+ fprintf(stderr, "parse error.\n");
461+ continue;
462+ }
463+ if (compile(s)) {
464+ fprintf(stderr, "compile error.\n");
465+ continue;
466+ }
467+ if (calc(s)) {
468+ fprintf(stderr, "calc error.\n");
469+ continue;
470+ }
471+
472+ if (pop_num(s, &num) == 0)
473+ printf("%d\n", num);
474+ }
475+
476+ // オブジェクトは、もう参照しない
477+ npl_object_unref(NPL_OBJECT(s));
478+ npl_object_unref(NPL_OBJECT(sbuf));
479+ npl_object_unref(NPL_OBJECT(in));
480+ npl_object_unref(NPL_OBJECT(out));
481+
482+ if (npl_final()) {
483+ fprintf(stderr, "npl_final() failed.\n");
484+ exit(1);
485+ }
486+
487+ return 0;
488+}
489+
--- trunk/npl/test/stack/test3.c (revision 0)
+++ trunk/npl/test/stack/test3.c (revision 64)
@@ -0,0 +1,164 @@
1+// test3.c
2+//
3+// 簡易なスタック式電卓。
4+//
5+// スタックを使って、
6+// 簡単な四則演算を行う。
7+// (後置記法で計算する)
8+
9+#include <stdio.h>
10+#include <stdlib.h>
11+#include <string.h>
12+#include "../../npl.h"
13+
14+typedef struct Code Code;
15+
16+// スタックに積まれる内容物
17+struct Code {
18+ int code; // 0: num 1: op
19+
20+ union {
21+ // 数値
22+ int num;
23+
24+ // 演算子。
25+ // 0: + 1: - 2: * 3: /
26+ int op;
27+ };
28+};
29+
30+void push_num(npl_stack_t *s, int num)
31+{
32+ Code c;
33+
34+ c.code = 0;
35+ c.num = num;
36+
37+ if (npl_stack_push(s, sizeof(Code), &c)) {
38+ fprintf(stderr, "push_num() failed.\n");
39+ exit(1);
40+ }
41+}
42+
43+void push_op(npl_stack_t *s, int op)
44+{
45+ Code c;
46+
47+ if (op < 0 || 3 < op) {
48+ fprintf(stderr, "push_op() failed.\n");
49+ exit(1);
50+ }
51+
52+ c.code = 1;
53+ c.op = op;
54+
55+ if (npl_stack_push(s, sizeof(Code), &c)) {
56+ fprintf(stderr, "push_op() failed.\n");
57+ exit(1);
58+ }
59+}
60+
61+void push_int(npl_stack_t *s, int i)
62+{
63+ if (npl_stack_push(s, sizeof(int), &i)) {
64+ fprintf(stderr, "push_int() failed.\n");
65+ exit(1);
66+ }
67+}
68+
69+int pop_int(npl_stack_t *s)
70+{
71+ int i;
72+
73+ if (npl_stack_pop(s, sizeof(int), &i)) {
74+ fprintf(stderr, "pop_int() failed.\n");
75+ exit(1);
76+ }
77+
78+ return i;
79+}
80+
81+int calc(npl_stack_t *s)
82+{
83+ int result;
84+ npl_stack_t *t; // 計算用
85+ Code c;
86+
87+ if ((t = npl_stack_new()) == NULL) {
88+ fprintf(stderr, "calc() failed.\n");
89+ exit(1);
90+ }
91+
92+ while (!npl_stack_pop(s, sizeof(Code), &c)) {
93+ if (c.code == 0) {
94+ push_int(t, c.num);
95+ } else if (c.code == 1) {
96+ int a, b, n;
97+
98+ // スタック(計算用)での順番に注意!
99+ b = pop_int(t);
100+ a = pop_int(t);
101+
102+ switch (c.op) {
103+ case 0:
104+ n = a + b;
105+ break;
106+ case 1:
107+ n = a - b;
108+ break;
109+ case 2:
110+ n = a * b;
111+ break;
112+ case 3:
113+ n = a / b;
114+ break;
115+ default:
116+ fprintf(stderr, "calc() failed.\n");
117+ exit(1);
118+ }
119+
120+ push_int(t, n);
121+ }
122+ }
123+
124+ result = pop_int(t);
125+ npl_object_unref(NPL_OBJECT(t));
126+
127+ return result;
128+}
129+
130+int main(void)
131+{
132+ npl_stack_t *s;
133+
134+ if (npl_init()) {
135+ fprintf(stderr, "npl_init() failed.\n");
136+ exit(1);
137+ }
138+
139+ // 新しいスタック・オブジェクトを作成する
140+ if ((s = npl_stack_new()) == NULL) {
141+ fprintf(stderr, "npl_stack_new() failed.\n");
142+ exit(1);
143+ }
144+
145+ // (100 - 28) / 12
146+ push_op(s, 3);
147+ push_num(s, 12);
148+ push_op(s, 1);
149+ push_num(s, 28);
150+ push_num(s, 100);
151+
152+ printf("%d\n", calc(s));
153+
154+ // オブジェクトは、もう参照しない
155+ npl_object_unref(NPL_OBJECT(s));
156+
157+ if (npl_final()) {
158+ fprintf(stderr, "npl_final() failed.\n");
159+ exit(1);
160+ }
161+
162+ return 0;
163+}
164+
--- trunk/npl/test/stack/Makefile (revision 0)
+++ trunk/npl/test/stack/Makefile (revision 64)
@@ -0,0 +1,20 @@
1+all: test1 test2 test3 calc
2+
3+test1: test1.c
4+ gcc -otest1 test1.c ../../libnpl.a
5+
6+test2: test2.c
7+ gcc -otest2 test2.c ../../libnpl.a
8+
9+test3: test3.c
10+ gcc -otest3 test3.c ../../libnpl.a
11+
12+calc: calc.c
13+ gcc -ocalc calc.c ../../libnpl.a
14+
15+clean:
16+ rm -f test1
17+ rm -f test2
18+ rm -f test3
19+ rm -f calc
20+
--- trunk/npl/test/stack/test1.c (revision 0)
+++ trunk/npl/test/stack/test1.c (revision 64)
@@ -0,0 +1,78 @@
1+// スタックの基本的な操作
2+
3+#include <stdio.h>
4+#include <stdlib.h>
5+#include <string.h>
6+#include "../../npl.h"
7+
8+void my_push(npl_stack_t *s, size_t bytes, void *p)
9+{
10+ if (npl_stack_push(s, bytes, p)) {
11+ fprintf(stderr, "my_push() failed.\n");
12+ exit(1);
13+ }
14+}
15+
16+void my_pop(npl_stack_t *s, size_t bytes, void *p)
17+{
18+ if (npl_stack_pop(s, bytes, p)) {
19+ fprintf(stderr, "my_pop() failed.\n");
20+ exit(1);
21+ }
22+}
23+
24+int main(void)
25+{
26+ npl_stack_t *s;
27+ int i;
28+ double d;
29+ char *str;
30+
31+ if (npl_init()) {
32+ fprintf(stderr, "npl_init() failed.\n");
33+ exit(1);
34+ }
35+
36+ // 新しいスタック・オブジェクトを作成する
37+ if ((s = npl_stack_new()) == NULL) {
38+ fprintf(stderr, "npl_stack_new() failed.\n");
39+ exit(1);
40+ }
41+
42+ // スタックに積む
43+ i = 500;
44+ my_push(s, sizeof(i), &i);
45+
46+ d = 56.789;
47+ my_push(s, sizeof(d), &d);
48+
49+ str = "my message.";
50+ my_push(s, sizeof(str), &str);
51+
52+ // 念の為、値はリセット
53+ i = 0;
54+ d = 0.0;
55+ str = NULL;
56+
57+ // スタックから取り出す。
58+ // (スタックなので積んだ順とは逆。)
59+ my_pop(s, sizeof(str), &str);
60+ my_pop(s, sizeof(d), &d);
61+ my_pop(s, sizeof(i), &i);
62+
63+ // 表示
64+ printf("%d\n", i);
65+ printf("%lf\n", d);
66+ printf("%s\n", str);
67+
68+ // オブジェクトは、もう参照しない
69+ npl_object_unref(NPL_OBJECT(s));
70+
71+ if (npl_final()) {
72+ fprintf(stderr, "npl_final() failed.\n");
73+ exit(1);
74+ }
75+
76+ return 0;
77+}
78+
--- trunk/npl/npl.h (revision 63)
+++ trunk/npl/npl.h (revision 64)
@@ -367,6 +367,7 @@
367367 void npl_sblock_set_prev(npl_sblock_t *sb, npl_sblock_t *prev);
368368 int npl_sblock_push(npl_sblock_t *sb, size_t bytes, void *p);
369369 int npl_sblock_pop(npl_sblock_t *sb, size_t bytes, void *p);
370+int npl_sblock_get(npl_sblock_t *sb, size_t offset, size_t bytes, void *p);
370371 void npl_sblock_clear(npl_sblock_t *sb);
371372
372373 // stack class
@@ -389,6 +390,8 @@
389390 int npl_stack_enter(npl_stack_t *s);
390391 int npl_stack_push(npl_stack_t *s, size_t bytes, void *p);
391392 int npl_stack_pop(npl_stack_t *s, size_t bytes, void *p);
393+int npl_stack_remove(npl_stack_t *s, size_t bytes);
394+int npl_stack_get(npl_stack_t *s, size_t offset, size_t bytes, void *p);
392395
393396 int npl_stack_enter_obj(npl_stack_t *s);
394397 int npl_stack_push_obj(npl_stack_t *s, npl_object_t *obj);
--- trunk/npl/sbuf.c (revision 63)
+++ trunk/npl/sbuf.c (revision 64)
@@ -61,6 +61,8 @@
6161 return 1; // error
6262 if (npl_buf_resize(NPL_BUF(sb), bytes))
6363 return 1; // error
64+
65+ sb->len = size;
6466 }
6567
6668 // バッファへ追加
--- trunk/npl/lang/Makefile (revision 0)
+++ trunk/npl/lang/Makefile (revision 64)
@@ -0,0 +1,12 @@
1+all: calci calcf
2+
3+calci: calci.c
4+ gcc -ocalci calci.c ../libnpl.a
5+
6+calcf: calcf.c
7+ gcc -ocalcf calcf.c ../libnpl.a -lm
8+
9+clean:
10+ rm -f calci
11+ rm -f calcf
12+
--- trunk/npl/lang/calcf.c (revision 0)
+++ trunk/npl/lang/calcf.c (revision 64)
@@ -0,0 +1,864 @@
1+// calcf.c
2+//
3+// 簡易なスタック式電卓。 浮動小数点バージョン。
4+//
5+// 実装状況:
6+// 加減乗除、余り、カッコ、累乗、
7+// 変数、変数への代入。
8+// 構文エラーチェックなど行ってないので、
9+// 誤った入力には注意。
10+//
11+// 入力例:
12+// >> 1.5 + 2.3
13+//
14+// 2の0.5乗 >> 2^0.5
15+// 変数への代入 >> a = 2.5 + 5.2
16+// 変数を使う >> a^b
17+
18+#include <stdio.h>
19+#include <stdlib.h>
20+#include <string.h>
21+#include <limits.h>
22+#include <math.h>
23+#include "../npl.h"
24+
25+typedef enum CodeType CodeType;
26+typedef struct Code Code;
27+
28+enum CodeType {
29+ CT_NONE = 0,
30+ CT_NUM,
31+ CT_U_PLUS,
32+ CT_U_MINUS,
33+ CT_PLUS,
34+ CT_MINUS,
35+ CT_MUL,
36+ CT_DIV,
37+ CT_MOD,
38+ CT_LP,
39+ CT_RP,
40+ CT_COMMA,
41+ CT_VAR,
42+ CT_POW,
43+ CT_EQ,
44+};
45+
46+// スタックに積まれる内容物
47+struct Code {
48+ CodeType ct;
49+ union {
50+ double num;
51+ npl_var_t *var;
52+ };
53+};
54+
55+// 変数スタック
56+npl_stack_t *var_stack;
57+
58+npl_var_t* get_var(wchar_t *name)
59+{
60+ npl_var_t *var = NULL;
61+ size_t i, len, offset;
62+
63+ // スタックを探す
64+ len = npl_stack_count(var_stack) / sizeof(npl_var_t*);
65+ for (i=0; i<len; i++) {
66+ offset = i * sizeof(npl_var_t*);
67+ if (npl_stack_get(var_stack, offset, sizeof(npl_var_t*), &var)) {
68+ fprintf(stderr, "npl_stack_get() failed.\n");
69+ exit(1);
70+ }
71+ if (wcscmp(npl_var_name(var), name) == 0) {
72+ npl_object_ref(NPL_OBJECT(var));
73+ break;
74+ }
75+ var = NULL;
76+ }
77+
78+ if (var == NULL) {
79+ npl_val_t val;
80+
81+ if ((var = npl_var_new(name)) == NULL) {
82+ fprintf(stderr, "npl_var_new() failed.\n");
83+ exit(1);
84+ }
85+
86+ npl_val_begin(&val);
87+ npl_val_set_int(&val, 0);
88+ npl_var_set(var, &val);
89+ npl_val_end(&val);
90+ if (npl_stack_push_obj(var_stack, NPL_OBJECT(var))) {
91+ fprintf(stderr, "npl_stack_push_obj() failed.\n");
92+ exit(1);
93+ }
94+ }
95+
96+ return var;
97+}
98+
99+void _push(npl_stack_t *s, CodeType ct, double num)
100+{
101+ Code c;
102+
103+ c.ct = ct;
104+ c.num = num;
105+ if (npl_stack_push(s, sizeof(Code), &c)) {
106+ fprintf(stderr, "_push() failed.\n");
107+ exit(1);
108+ }
109+}
110+
111+void push_num(npl_stack_t *s, double num)
112+{
113+ _push(s, CT_NUM, num);
114+}
115+
116+void push_u_plus(npl_stack_t *s)
117+{
118+ _push(s, CT_U_PLUS, 0);
119+}
120+
121+void push_u_minus(npl_stack_t *s)
122+{
123+ _push(s, CT_U_MINUS, 0);
124+}
125+
126+void push_plus(npl_stack_t *s)
127+{
128+ _push(s, CT_PLUS, 0);
129+}
130+
131+void push_minus(npl_stack_t *s)
132+{
133+ _push(s, CT_MINUS, 0);
134+}
135+
136+void push_mul(npl_stack_t *s)
137+{
138+ _push(s, CT_MUL, 0);
139+}
140+
141+void push_div(npl_stack_t *s)
142+{
143+ _push(s, CT_DIV, 0);
144+}
145+
146+void push_mod(npl_stack_t *s)
147+{
148+ _push(s, CT_MOD, 0);
149+}
150+
151+void push_lp(npl_stack_t *s)
152+{
153+ _push(s, CT_LP, 0);
154+}
155+
156+void push_rp(npl_stack_t *s)
157+{
158+ _push(s, CT_RP, 0);
159+}
160+
161+void push_comma(npl_stack_t *s)
162+{
163+ _push(s, CT_COMMA, 0);
164+}
165+
166+void push_var(npl_stack_t *s, wchar_t *name)
167+{
168+ Code c;
169+ npl_var_t *var;
170+
171+ var = get_var(name);
172+ c.ct = CT_VAR;
173+ c.var = var;
174+ if (npl_stack_push(s, sizeof(Code), &c)) {
175+ fprintf(stderr, "_push() failed.\n");
176+ exit(1);
177+ }
178+}
179+
180+void push_pow(npl_stack_t *s)
181+{
182+ _push(s, CT_POW, 0);
183+}
184+
185+void push_eq(npl_stack_t *s)
186+{
187+ _push(s, CT_EQ, 0);
188+}
189+
190+void push_code(npl_stack_t *s, Code *c)
191+{
192+ if (npl_stack_push(s, sizeof(Code), c)) {
193+ fprintf(stderr, "push_code() failed.\n");
194+ exit(1);
195+ }
196+}
197+
198+int pop_num(npl_stack_t *s, double *num)
199+{
200+ Code c;
201+
202+ if (npl_stack_pop(s, sizeof(Code), &c))
203+ return 1;
204+ if (c.ct == CT_NUM) {
205+ *num = c.num;
206+ } else if (c.ct == CT_VAR) {
207+ if (c.var->val.type == NPL_VT_FLOAT)
208+ *num = c.var->val.f;
209+ else
210+ *num = 0;
211+ } else {
212+ return 1;
213+ }
214+
215+ return 0;
216+}
217+
218+npl_var_t* pop_var(npl_stack_t *s)
219+{
220+ Code c;
221+
222+ if (npl_stack_pop(s, sizeof(Code), &c))
223+ return NULL;
224+ if (c.ct == CT_VAR)
225+ return c.var;
226+
227+ return NULL;
228+}
229+
230+int pop_code(npl_stack_t *s, Code *c)
231+{
232+ return npl_stack_pop(s, sizeof(Code), c);
233+}
234+
235+int get_code(npl_stack_t *s, Code *c)
236+{
237+ return npl_stack_get(s, 0, sizeof(Code), c);
238+}
239+
240+void remove_code(npl_stack_t *s)
241+{
242+ Code c;
243+
244+ if (get_code(s, &c))
245+ return;
246+ if (c.ct == CT_VAR) {
247+ npl_object_unref(NPL_OBJECT(c.var));
248+ c.var = NULL;
249+ }
250+ npl_stack_remove(s, sizeof(Code));
251+}
252+
253+// a のすべての内容をポップして、
254+// b にプッシュする。
255+void pop_code_all(npl_stack_t *a, npl_stack_t *b)
256+{
257+ Code c;
258+
259+ while (pop_code(a, &c) == 0)
260+ push_code(b, &c);
261+}
262+
263+npl_stack_t* my_stack_new()
264+{
265+ npl_stack_t *s;
266+
267+ if ((s = npl_stack_new()) == NULL) {
268+ fprintf(stderr, "my_stack_new() failed.\n");
269+ exit(1);
270+ }
271+
272+ return s;
273+}
274+
275+void my_stack_unref(npl_stack_t *s)
276+{
277+ npl_object_unref(NPL_OBJECT(s));
278+}
279+
280+void my_stack_enter(npl_stack_t *s)
281+{
282+ if (npl_stack_enter(s)) {
283+ fprintf(stderr, "my_stack_enter() failed.\n");
284+ exit(1);
285+ }
286+}
287+
288+void my_stack_leave(npl_stack_t *s)
289+{
290+ if (npl_stack_leave(s)) {
291+ fprintf(stderr, "my_stack_leave() failed.\n");
292+ exit(1);
293+ }
294+}
295+
296+int is_num(wchar_t wc)
297+{
298+ if (L'0' <= wc && wc <= L'9')
299+ return 1;
300+
301+ return 0;
302+}
303+
304+int to_num(wchar_t wc)
305+{
306+ if (L'0' <= wc && wc <= L'9')
307+ return wc - L'0';
308+
309+ fprintf(stderr, "to_num() failed\n");
310+ exit(1);
311+
312+ return -1;
313+}
314+
315+int is_alpha(wchar_t wc)
316+{
317+ if (L'a' <= wc && wc <= L'z')
318+ return 1;
319+ if (L'A' <= wc && wc <= L'Z')
320+ return 1;
321+ if (wc == L'_')
322+ return 1;
323+
324+ return 0;
325+}
326+
327+int is_alnum(wchar_t wc)
328+{
329+ if (is_num(wc))
330+ return 1;
331+ if (is_alpha(wc))
332+ return 1;
333+
334+ return 0;
335+}
336+
337+// 後置記法コード(実行コード)を計算する
338+int calc(npl_stack_t *s)
339+{
340+ int result;
341+ npl_stack_t *t; // 計算用
342+ Code c;
343+
344+ if ((t = npl_stack_new()) == NULL) {
345+ fprintf(stderr, "calc() failed.\n");
346+ exit(1);
347+ }
348+
349+ // スタックの中身を表示
350+/*
351+ {
352+ size_t i = 0;
353+
354+ while (!npl_stack_get(s, sizeof(Code)*i, sizeof(Code), &c)) {
355+ switch (c.ct) {
356+ case CT_NUM:
357+ printf("<%lf> ", c.num);
358+ break;
359+ case CT_U_PLUS:
360+ printf("<+u> ");
361+ break;
362+ case CT_U_MINUS:
363+ printf("<-u> ");
364+ break;
365+ case CT_PLUS:
366+ printf("<+> ");
367+ break;
368+ case CT_MINUS:
369+ printf("<-> ");
370+ break;
371+ case CT_MUL:
372+ printf("<*> ");
373+ break;
374+ case CT_DIV:
375+ printf("</> ");
376+ break;
377+ case CT_MOD:
378+ printf("<%%> ");
379+ break;
380+ case CT_LP:
381+ printf("<(> ");
382+ break;
383+ case CT_RP:
384+ printf("<)> ");
385+ break;
386+ case CT_COMMA:
387+ break;
388+ case CT_VAR:
389+ printf("<%S> ", npl_var_name(c.var));
390+ break;
391+ case CT_POW:
392+ printf("<^> ");
393+ break;
394+ case CT_EQ:
395+ printf("<=> ");
396+ break;
397+ }
398+ i++;
399+ }
400+ printf("\n");
401+ }
402+*/
403+ while (!pop_code(s, &c)) {
404+ double a, b, n;
405+
406+ switch (c.ct) {
407+ case CT_NUM:
408+ push_num(t, c.num);
409+ break;
410+ case CT_U_PLUS:
411+ if (pop_num(t, &a))
412+ goto ERROR;
413+ n = a;
414+ push_num(t, n);
415+ break;
416+ case CT_U_MINUS:
417+ if (pop_num(t, &a))
418+ goto ERROR;
419+ if (a == INT_MIN)
420+ goto ERROR;
421+ n = -a;
422+ push_num(t, n);
423+ break;
424+ case CT_PLUS:
425+ if (pop_num(t, &b))
426+ goto ERROR;
427+ if (pop_num(t, &a))
428+ goto ERROR;
429+ n = a + b;
430+ push_num(t, n);
431+ break;
432+ case CT_MINUS:
433+ if (pop_num(t, &b))
434+ goto ERROR;
435+ if (pop_num(t, &a))
436+ goto ERROR;
437+ n = a - b;
438+ push_num(t, n);
439+ break;
440+ case CT_MUL:
441+ if (pop_num(t, &b))
442+ goto ERROR;
443+ if (pop_num(t, &a))
444+ goto ERROR;
445+ n = a * b;
446+ push_num(t, n);
447+ break;
448+ case CT_DIV:
449+ if (pop_num(t, &b))
450+ goto ERROR;
451+ if (pop_num(t, &a))
452+ goto ERROR;
453+ n = a / b;
454+ push_num(t, n);
455+ break;
456+ case CT_MOD:
457+ if (pop_num(t, &b))
458+ goto ERROR;
459+ if (pop_num(t, &a))
460+ goto ERROR;
461+ n = fmod(a, b);
462+ push_num(t, n);
463+ break;
464+ case CT_COMMA:
465+ break;
466+ case CT_VAR:
467+ push_code(t, &c);
468+ break;
469+ case CT_POW:
470+ if (pop_num(t, &b))
471+ goto ERROR;
472+ if (pop_num(t, &a))
473+ goto ERROR;
474+ n = pow(a, b);
475+ push_num(t, n);
476+ break;
477+ case CT_EQ:
478+ {
479+ npl_var_t *var;
480+ npl_val_t val;
481+
482+ if (pop_num(t, &a))
483+ goto ERROR;
484+ if ((var = pop_var(t)) == NULL)
485+ goto ERROR;
486+
487+ npl_val_begin(&val);
488+ npl_val_set_float(&val, a);
489+ npl_var_set(var, &val);
490+ npl_val_end(&val);
491+ npl_object_unref(NPL_OBJECT(var));
492+
493+ push_num(t, a);
494+ }
495+ break;
496+ }
497+ }
498+
499+ pop_code_all(t, s);
500+ npl_object_unref(NPL_OBJECT(t));
501+
502+ return 0; // success
503+
504+ERROR:
505+ npl_object_unref(NPL_OBJECT(t));
506+ return 1; // error
507+}
508+
509+// 中置記法で、一時的にスタック (h) に保管していた
510+// 演算記号を後置記法コードのスタック s に書き戻す。
511+void put_back_op(Code *code, npl_stack_t *s, npl_stack_t *h)
512+{
513+ Code c;
514+ int loop = 1;
515+
516+ while (loop) {
517+ if (get_code(h, &c))
518+ break;
519+ if (code == NULL) {
520+ push_code(s, &c);
521+ remove_code(h);
522+ continue;
523+ }
524+ switch (c.ct) {
525+ case CT_U_PLUS:
526+ case CT_U_MINUS:
527+ case CT_PLUS:
528+ case CT_MINUS:
529+ switch (code->ct) {
530+ case CT_MUL:
531+ case CT_DIV:
532+ case CT_MOD:
533+ case CT_POW:
534+ loop = 0;
535+ break;
536+ default:
537+ push_code(s, &c);
538+ remove_code(h);
539+ break;
540+ }
541+ break;
542+ case CT_MUL:
543+ case CT_DIV:
544+ case CT_MOD:
545+ switch (code->ct) {
546+ case CT_POW:
547+ loop = 0;
548+ break;
549+ default:
550+ push_code(s, &c);
551+ remove_code(h);
552+ break;
553+ }
554+ break;
555+ case CT_POW:
556+ switch (code->ct) {
557+ default:
558+ push_code(s, &c);
559+ remove_code(h);
560+ break;
561+ }
562+ break;
563+ case CT_EQ:
564+ switch (code->ct) {
565+ case CT_U_PLUS:
566+ case CT_U_MINUS:
567+ case CT_PLUS:
568+ case CT_MINUS:
569+ case CT_MUL:
570+ case CT_DIV:
571+ case CT_MOD:
572+ case CT_POW:
573+ loop = 0;
574+ break;
575+ default:
576+ push_code(s, &c);
577+ remove_code(h);
578+ break;
579+ }
580+ break;
581+ default:
582+ fprintf(stderr, "unknown operator.\n");
583+ exit(1);
584+ break;
585+ }
586+ }
587+}
588+
589+// 中置記法コード(トークン)を
590+// 後置記法コード(実行コード)に変換する。
591+int compile(npl_stack_t *s)
592+{
593+ npl_stack_t *t, *u, *v;
594+ Code code, c;
595+ int first; // 単項演算子を判別するため
596+
597+ // セットアップ
598+ t = my_stack_new();
599+ u = my_stack_new();
600+ v = my_stack_new();
601+ pop_code_all(s, t);
602+
603+ // 変換処理
604+ first = 1;
605+ while (pop_code(t, &code) == 0) {
606+ switch (code.ct) {
607+ case CT_NUM:
608+ case CT_VAR:
609+ push_code(v, &code);
610+ if (first)
611+ first = 0;
612+ break;
613+ case CT_PLUS:
614+ case CT_MINUS:
615+ case CT_MUL:
616+ case CT_DIV:
617+ case CT_MOD:
618+ case CT_POW:
619+ if (first) {
620+ if (code.ct == CT_PLUS)
621+ code.ct = CT_U_PLUS;
622+ if (code.ct == CT_MINUS)
623+ code.ct = CT_U_MINUS;
624+ first = 0;
625+ }
626+ put_back_op(&code, v, u);
627+ push_code(u, &code);
628+ break;
629+ case CT_EQ:
630+ push_code(u, &code);
631+ first = 1;
632+ break;
633+ case CT_LP:
634+ my_stack_enter(u);
635+ first = 1;
636+ break;
637+ case CT_RP:
638+ pop_code_all(u, v);
639+ my_stack_leave(u);
640+ first = 0;
641+ break;
642+ }
643+ }
644+
645+ pop_code_all(u, v);
646+ pop_code_all(v, s);
647+
648+ // 終了
649+ npl_object_unref(NPL_OBJECT(v));
650+ npl_object_unref(NPL_OBJECT(u));
651+ npl_object_unref(NPL_OBJECT(t));
652+
653+ return 0;
654+}
655+
656+// 数式を表す文字列を字句解析して、
657+// 中置記法コード(トークン)をスタック s に
658+// 格納する。
659+int parse(wchar_t *sbuf, npl_stack_t *s)
660+{
661+ double num, d;
662+ int n;
663+ size_t i;
664+ Code code;
665+ npl_sbuf_t *sb;
666+ wchar_t wcs[4];
667+
668+ // 文字が数字の続きである場合は 1,
669+ // 文字が識別子の続きである場合は 2
670+ int flag;
671+
672+ // 文字が小数点以下である場合
673+ int flag2;
674+
675+ if ((sb = npl_sbuf_new()) == NULL) {
676+ fprintf(stderr, "npl_sbuf_new() failed.\n");
677+ exit(1);
678+ }
679+ wmemset(wcs, L'\0', 4);
680+
681+ flag = 0;
682+ for (i=0; sbuf[i] != L'\0'; i++) {
683+ if (sbuf[i] == L'\n')
684+ break;
685+ if (flag == 1) {
686+ if (flag2 == 0 && sbuf[i] == L'.') {
687+ flag2 = 1;
688+ d = 0.1;
689+ continue;
690+ }
691+ if (is_num(sbuf[i])) {
692+ n = to_num(sbuf[i]);
693+ if (flag2 == 0) {
694+ num *= 10;
695+ num += n;
696+ } else {
697+ num += d * n;
698+ d *= 0.1;
699+ }
700+ continue;
701+ } else {
702+ push_num(s, num);
703+ flag = 0;
704+ }
705+ } else if (flag == 2) {
706+ if (is_alnum(sbuf[i])) {
707+ wcs[0] = sbuf[i];
708+ if (npl_sbuf_add(sb, wcs))
709+ goto ERROR;
710+ continue;
711+ } else {
712+ push_var(s, npl_buf_get(NPL_BUF(sb)));
713+ flag = 0;
714+ }
715+ }
716+ if (is_num(sbuf[i])) {
717+ num = to_num(sbuf[i]);
718+ flag = 1;
719+ flag2 = 0;
720+ } else if (is_alpha(sbuf[i])) {
721+ npl_buf_clear(NPL_BUF(sb));
722+ wcs[0] = sbuf[i];
723+ if (npl_sbuf_add(sb, wcs))
724+ goto ERROR;
725+ flag = 2;
726+ } else {
727+ switch (sbuf[i]) {
728+ case L' ':
729+ case L'\t':
730+ break;
731+ case L'+':
732+ push_plus(s);
733+ break;
734+ case L'-':
735+ push_minus(s);
736+ break;
737+ case L'*':
738+ push_mul(s);
739+ break;
740+ case L'/':
741+ push_div(s);
742+ break;
743+ case L'%':
744+ push_mod(s);
745+ break;
746+ case L'(':
747+ push_lp(s);
748+ break;
749+ case L')':
750+ push_rp(s);
751+ break;
752+ case L'^':
753+ push_pow(s);
754+ break;
755+ case L'=':
756+ push_eq(s);
757+ break;
758+ default:
759+ goto ERROR;
760+ break;
761+ }
762+ }
763+ }
764+
765+ if (flag == 1)
766+ push_num(s, num);
767+ else if (flag == 2)
768+ push_var(s, npl_buf_get(NPL_BUF(sb)));
769+
770+ npl_object_unref(NPL_OBJECT(sb));
771+ return 0;
772+
773+ERROR:
774+ npl_object_unref(NPL_OBJECT(sb));
775+ return 1;
776+}
777+
778+int main(void)
779+{
780+ npl_stream_t *out, *in;
781+ npl_sbuf_t *sbuf;
782+ npl_stack_t *s;
783+ double num;
784+
785+ if (npl_init()) {
786+ fprintf(stderr, "npl_init() failed.\n");
787+ exit(1);
788+ }
789+
790+ // ストリーム
791+ if ((out = npl_stream_stdout()) == NULL) {
792+ fprintf(stderr, "npl_stream_stdout() failed.\n");
793+ exit(1);
794+ }
795+ if ((in = npl_stream_stdin()) == NULL) {
796+ fprintf(stderr, "npl_stream_stdin() failed.\n");
797+ exit(1);
798+ }
799+
800+ // 文字列バッファ
801+ if ((sbuf = npl_sbuf_new()) == NULL) {
802+ fprintf(stderr, "npl_sbuf_new() failed.\n");
803+ exit(1);
804+ }
805+
806+ // 新しいスタック・オブジェクトを作成する
807+ if ((s = npl_stack_new()) == NULL) {
808+ fprintf(stderr, "npl_stack_new() failed.\n");
809+ exit(1);
810+ }
811+
812+ // 変数スタック
813+ if ((var_stack = npl_stack_new()) == NULL) {
814+ fprintf(stderr, "npl_stack_new() failed.\n");
815+ exit(1);
816+ }
817+ if (npl_stack_enter_obj(var_stack)) {
818+ fprintf(stderr, "npl_stack_enter_obj() failed.\n");
819+ exit(1);
820+ }
821+
822+ // 数式インタプリタ
823+ while (1) {
824+ npl_stream_write(out, L" >> ");
825+ if (npl_stream_read(in, sbuf))
826+ break;
827+ if (npl_stream_eof(in) || npl_stream_error(in)) {
828+ printf("\n");
829+ break;
830+ }
831+
832+ npl_stack_clean(s);
833+ if (parse(npl_buf_get(NPL_BUF(sbuf)), s)) {
834+ fprintf(stderr, "parse error.\n");
835+ continue;
836+ }
837+ if (compile(s)) {
838+ fprintf(stderr, "compile error.\n");
839+ continue;
840+ }
841+ if (calc(s)) {
842+ fprintf(stderr, "calc error.\n");
843+ continue;
844+ }
845+
846+ if (pop_num(s, &num) == 0)
847+ printf("%g\n", num);
848+ }
849+
850+ // オブジェクトは、もう参照しない
851+ npl_object_unref(NPL_OBJECT(var_stack));
852+ npl_object_unref(NPL_OBJECT(s));
853+ npl_object_unref(NPL_OBJECT(sbuf));
854+ npl_object_unref(NPL_OBJECT(in));
855+ npl_object_unref(NPL_OBJECT(out));
856+
857+ if (npl_final()) {
858+ fprintf(stderr, "npl_final() failed.\n");
859+ exit(1);
860+ }
861+
862+ return 0;
863+}
864+
--- trunk/npl/lang/calci.c (revision 0)
+++ trunk/npl/lang/calci.c (revision 64)
@@ -0,0 +1,929 @@
1+// calci.c
2+//
3+// 簡易なスタック式電卓。 整数値バージョン。
4+//
5+// 実装状況:
6+// 加減乗除、余り、カッコ、累乗、
7+// 変数、変数への代入
8+// 構文エラーチェックなど行ってないので、
9+// 誤った入力には注意。
10+//
11+// 入力例:
12+// >> 1 + 1
13+// >> 2 * (3 + 4)
14+//
15+// 2の7乗 >> 2^7
16+// 変数への代入 >> a = 3 + 5
17+// 変数を使う >> a^b
18+
19+#include <stdio.h>
20+#include <stdlib.h>
21+#include <string.h>
22+#include <limits.h>
23+#include "../npl.h"
24+
25+typedef enum CodeType CodeType;
26+typedef struct Code Code;
27+
28+enum CodeType {
29+ CT_NONE = 0,
30+ CT_NUM,
31+ CT_U_PLUS,
32+ CT_U_MINUS,
33+ CT_PLUS,
34+ CT_MINUS,
35+ CT_MUL,
36+ CT_DIV,
37+ CT_MOD,
38+ CT_LP,
39+ CT_RP,
40+ CT_COMMA,
41+ CT_VAR,
42+ CT_POW,
43+ CT_EQ,
44+};
45+
46+// スタックに積まれる内容物
47+struct Code {
48+ CodeType ct;
49+ union {
50+ int num;
51+ npl_var_t *var;
52+ };
53+};
54+
55+// 変数スタック
56+npl_stack_t *var_stack;
57+
58+npl_var_t* get_var(wchar_t *name)
59+{
60+ npl_var_t *var = NULL;
61+ size_t i, len, offset;
62+
63+ // スタックを探す
64+ len = npl_stack_count(var_stack) / sizeof(npl_var_t*);
65+ for (i=0; i<len; i++) {
66+ offset = i * sizeof(npl_var_t*);
67+ if (npl_stack_get(var_stack, offset, sizeof(npl_var_t*), &var)) {
68+ fprintf(stderr, "npl_stack_get() failed.\n");
69+ exit(1);
70+ }
71+ if (wcscmp(npl_var_name(var), name) == 0) {
72+ npl_object_ref(NPL_OBJECT(var));
73+ break;
74+ }
75+ var = NULL;
76+ }
77+
78+ if (var == NULL) {
79+ npl_val_t val;
80+
81+ if ((var = npl_var_new(name)) == NULL) {
82+ fprintf(stderr, "npl_var_new() failed.\n");
83+ exit(1);
84+ }
85+
86+ npl_val_begin(&val);
87+ npl_val_set_int(&val, 0);
88+ npl_var_set(var, &val);
89+ npl_val_end(&val);
90+ if (npl_stack_push_obj(var_stack, NPL_OBJECT(var))) {
91+ fprintf(stderr, "npl_stack_push_obj() failed.\n");
92+ exit(1);
93+ }
94+ }
95+
96+ return var;
97+}
98+
99+void _push(npl_stack_t *s, CodeType ct, int num)
100+{
101+ Code c;
102+
103+ c.ct = ct;
104+ c.num = num;
105+ if (npl_stack_push(s, sizeof(Code), &c)) {
106+ fprintf(stderr, "_push() failed.\n");
107+ exit(1);
108+ }
109+}
110+
111+void push_num(npl_stack_t *s, int num)
112+{
113+ _push(s, CT_NUM, num);
114+}
115+
116+void push_u_plus(npl_stack_t *s)
117+{
118+ _push(s, CT_U_PLUS, 0);
119+}
120+
121+void push_u_minus(npl_stack_t *s)
122+{
123+ _push(s, CT_U_MINUS, 0);
124+}
125+
126+void push_plus(npl_stack_t *s)
127+{
128+ _push(s, CT_PLUS, 0);
129+}
130+
131+void push_minus(npl_stack_t *s)
132+{
133+ _push(s, CT_MINUS, 0);
134+}
135+
136+void push_mul(npl_stack_t *s)
137+{
138+ _push(s, CT_MUL, 0);
139+}
140+
141+void push_div(npl_stack_t *s)
142+{
143+ _push(s, CT_DIV, 0);
144+}
145+
146+void push_mod(npl_stack_t *s)
147+{
148+ _push(s, CT_MOD, 0);
149+}
150+
151+void push_lp(npl_stack_t *s)
152+{
153+ _push(s, CT_LP, 0);
154+}
155+
156+void push_rp(npl_stack_t *s)
157+{
158+ _push(s, CT_RP, 0);
159+}
160+
161+void push_comma(npl_stack_t *s)
162+{
163+ _push(s, CT_COMMA, 0);
164+}
165+
166+void push_var(npl_stack_t *s, wchar_t *name)
167+{
168+ Code c;
169+ npl_var_t *var;
170+
171+ var = get_var(name);
172+ c.ct = CT_VAR;
173+ c.var = var;
174+ if (npl_stack_push(s, sizeof(Code), &c)) {
175+ fprintf(stderr, "_push() failed.\n");
176+ exit(1);
177+ }
178+}
179+
180+void push_pow(npl_stack_t *s)
181+{
182+ _push(s, CT_POW, 0);
183+}
184+
185+void push_eq(npl_stack_t *s)
186+{
187+ _push(s, CT_EQ, 0);
188+}
189+
190+void push_code(npl_stack_t *s, Code *c)
191+{
192+ if (npl_stack_push(s, sizeof(Code), c)) {
193+ fprintf(stderr, "push_code() failed.\n");
194+ exit(1);
195+ }
196+}
197+
198+int pop_num(npl_stack_t *s, int *num)
199+{
200+ Code c;
201+
202+ if (npl_stack_pop(s, sizeof(Code), &c))
203+ return 1;
204+ if (c.ct == CT_NUM) {
205+ *num = c.num;
206+ } else if (c.ct == CT_VAR) {
207+ if (c.var->val.type == NPL_VT_INT)
208+ *num = c.var->val.i;
209+ else
210+ *num = 0;
211+ } else {
212+ return 1;
213+ }
214+
215+ return 0;
216+}
217+
218+npl_var_t* pop_var(npl_stack_t *s)
219+{
220+ Code c;
221+
222+ if (npl_stack_pop(s, sizeof(Code), &c))
223+ return NULL;
224+ if (c.ct == CT_VAR)
225+ return c.var;
226+
227+ return NULL;
228+}
229+
230+int pop_code(npl_stack_t *s, Code *c)
231+{
232+ return npl_stack_pop(s, sizeof(Code), c);
233+}
234+
235+int get_code(npl_stack_t *s, Code *c)
236+{
237+ return npl_stack_get(s, 0, sizeof(Code), c);
238+}
239+
240+void remove_code(npl_stack_t *s)
241+{
242+ Code c;
243+
244+ if (get_code(s, &c))
245+ return;
246+ if (c.ct == CT_VAR) {
247+ npl_object_unref(NPL_OBJECT(c.var));
248+ c.var = NULL;
249+ }
250+ npl_stack_remove(s, sizeof(Code));
251+}
252+
253+// a のすべての内容をポップして、
254+// b にプッシュする。
255+void pop_code_all(npl_stack_t *a, npl_stack_t *b)
256+{
257+ Code c;
258+
259+ while (pop_code(a, &c) == 0)
260+ push_code(b, &c);
261+}
262+
263+npl_stack_t* my_stack_new()
264+{
265+ npl_stack_t *s;
266+
267+ if ((s = npl_stack_new()) == NULL) {
268+ fprintf(stderr, "my_stack_new() failed.\n");
269+ exit(1);
270+ }
271+
272+ return s;
273+}
274+
275+void my_stack_unref(npl_stack_t *s)
276+{
277+ npl_object_unref(NPL_OBJECT(s));
278+}
279+
280+void my_stack_enter(npl_stack_t *s)
281+{
282+ if (npl_stack_enter(s)) {
283+ fprintf(stderr, "my_stack_enter() failed.\n");
284+ exit(1);
285+ }
286+}
287+
288+void my_stack_leave(npl_stack_t *s)
289+{
290+ if (npl_stack_leave(s)) {
291+ fprintf(stderr, "my_stack_leave() failed.\n");
292+ exit(1);
293+ }
294+}
295+
296+int is_num(wchar_t wc)
297+{
298+ if (L'0' <= wc && wc <= L'9')
299+ return 1;
300+
301+ return 0;
302+}
303+
304+int to_num(wchar_t wc)
305+{
306+ if (L'0' <= wc && wc <= L'9')
307+ return wc - L'0';
308+
309+ fprintf(stderr, "to_num() failed\n");
310+ exit(1);
311+
312+ return -1;
313+}
314+
315+int is_alpha(wchar_t wc)
316+{
317+ if (L'a' <= wc && wc <= L'z')
318+ return 1;
319+ if (L'A' <= wc && wc <= L'Z')
320+ return 1;
321+ if (wc == L'_')
322+ return 1;
323+
324+ return 0;
325+}
326+
327+int is_alnum(wchar_t wc)
328+{
329+ if (is_num(wc))
330+ return 1;
331+ if (is_alpha(wc))
332+ return 1;
333+
334+ return 0;
335+}
336+
337+int add(int a, int b, int *r)
338+{
339+ int n = a + b;
340+
341+ if (b >= 0) {
342+ if (n < a)
343+ return 1; // overflow
344+ } else {
345+ if (n > a)
346+ return 1; // overflow
347+ }
348+
349+ *r = n;
350+
351+ return 0;
352+}
353+
354+int sub(int a, int b, int *r)
355+{
356+ int n = a - b;
357+
358+ if (b >= 0) {
359+ if (n > a)
360+ return 1; // overflow
361+ } else {
362+ if (n < a)
363+ return 1; // overflow
364+ }
365+
366+ *r = n;
367+
368+ return 0;
369+}
370+
371+int mul(int a, int b, int *r)
372+{
373+ int n = a * b;
374+
375+ if (a == 0 || b == 0) {
376+ *r = 0;
377+ return 0;
378+ }
379+
380+ if (a > 0 && b > 0) {
381+ if (a > (INT_MAX / b))
382+ return 1; // overflow
383+ } else if (a > 0 && b < 0) {
384+ if (a > (INT_MIN / b))
385+ return 1; // overflow
386+ } else if (a < 0 && b > 0) {
387+ if (b > (INT_MIN / a))
388+ return 1; // overflow
389+ } else {
390+ if (-a > (INT_MIN / b))
391+ return 1; // overflow
392+ }
393+
394+ *r = n;
395+
396+ return 0;
397+}
398+
399+// 後置記法コード(実行コード)を計算する
400+int calc(npl_stack_t *s)
401+{
402+ int result;
403+ npl_stack_t *t; // 計算用
404+ Code c;
405+
406+ if ((t = npl_stack_new()) == NULL) {
407+ fprintf(stderr, "calc() failed.\n");
408+ exit(1);
409+ }
410+
411+ // スタックの中身を表示
412+/*
413+ {
414+ size_t i = 0;
415+
416+ while (!npl_stack_get(s, sizeof(Code)*i, sizeof(Code), &c)) {
417+ switch (c.ct) {
418+ case CT_NUM:
419+ printf("<%d> ", c.num);
420+ break;
421+ case CT_U_PLUS:
422+ printf("<+u> ");
423+ break;
424+ case CT_U_MINUS:
425+ printf("<-u> ");
426+ break;
427+ case CT_PLUS:
428+ printf("<+> ");
429+ break;
430+ case CT_MINUS:
431+ printf("<-> ");
432+ break;
433+ case CT_MUL:
434+ printf("<*> ");
435+ break;
436+ case CT_DIV:
437+ printf("</> ");
438+ break;
439+ case CT_MOD:
440+ printf("<%%> ");
441+ break;
442+ case CT_LP:
443+ printf("<(> ");
444+ break;
445+ case CT_RP:
446+ printf("<)> ");
447+ break;
448+ case CT_COMMA:
449+ break;
450+ case CT_VAR:
451+ printf("<%S> ", npl_var_name(c.var));
452+ break;
453+ case CT_POW:
454+ printf("<^> ");
455+ break;
456+ case CT_EQ:
457+ printf("<=> ");
458+ break;
459+ }
460+ i++;
461+ }
462+ printf("\n");
463+ }
464+*/
465+ while (!pop_code(s, &c)) {
466+ int a, b, n;
467+
468+ switch (c.ct) {
469+ case CT_NUM:
470+ push_num(t, c.num);
471+ break;
472+ case CT_U_PLUS:
473+ if (pop_num(t, &a))
474+ goto ERROR;
475+ n = a;
476+ push_num(t, n);
477+ break;
478+ case CT_U_MINUS:
479+ if (pop_num(t, &a))
480+ goto ERROR;
481+ if (a == INT_MIN)
482+ goto ERROR;
483+ n = -a;
484+ push_num(t, n);
485+ break;
486+ case CT_PLUS:
487+ if (pop_num(t, &b))
488+ goto ERROR;
489+ if (pop_num(t, &a))
490+ goto ERROR;
491+ if (add(a, b, &n))
492+ goto ERROR;
493+ push_num(t, n);
494+ break;
495+ case CT_MINUS:
496+ if (pop_num(t, &b))
497+ goto ERROR;
498+ if (pop_num(t, &a))
499+ goto ERROR;
500+ if (sub(a, b, &n))
501+ goto ERROR;
502+ push_num(t, n);
503+ break;
504+ case CT_MUL:
505+ if (pop_num(t, &b))
506+ goto ERROR;
507+ if (pop_num(t, &a))
508+ goto ERROR;
509+ if (mul(a, b, &n))
510+ goto ERROR;
511+ push_num(t, n);
512+ break;
513+ case CT_DIV:
514+ if (pop_num(t, &b))
515+ goto ERROR;
516+ if (pop_num(t, &a))
517+ goto ERROR;
518+ n = a / b;
519+ push_num(t, n);
520+ break;
521+ case CT_MOD:
522+ if (pop_num(t, &b))
523+ goto ERROR;
524+ if (pop_num(t, &a))
525+ goto ERROR;
526+ n = a % b;
527+ push_num(t, n);
528+ break;
529+ case CT_COMMA:
530+ break;
531+ case CT_VAR:
532+ push_code(t, &c);
533+ break;
534+ case CT_POW:
535+ if (pop_num(t, &b))
536+ goto ERROR;
537+ if (pop_num(t, &a))
538+ goto ERROR;
539+ if (b == 0) {
540+ n = 1;
541+ } else if (b > 0) {
542+ int i;
543+
544+ n = 1;
545+ for (i=0; i<b; i++)
546+ if (mul(n, a, &n))
547+ goto ERROR;
548+ } else if (b < 0) {
549+ goto ERROR; // not support
550+ }
551+ push_num(t, n);
552+ break;
553+ case CT_EQ:
554+ {
555+ npl_var_t *var;
556+ npl_val_t val;
557+
558+ if (pop_num(t, &a))
559+ goto ERROR;
560+ if ((var = pop_var(t)) == NULL)
561+ goto ERROR;
562+
563+ npl_val_begin(&val);
564+ npl_val_set_int(&val, a);
565+ npl_var_set(var, &val);
566+ npl_val_end(&val);
567+ npl_object_unref(NPL_OBJECT(var));
568+
569+ push_num(t, a);
570+ }
571+ break;
572+ }
573+ }
574+
575+ pop_code_all(t, s);
576+ npl_object_unref(NPL_OBJECT(t));
577+
578+ return 0; // success
579+
580+ERROR:
581+ npl_object_unref(NPL_OBJECT(t));
582+ return 1; // error
583+}
584+
585+// 中置記法で、一時的にスタック (h) に保管していた
586+// 演算記号を後置記法コードのスタック s に書き戻す。
587+void put_back_op(Code *code, npl_stack_t *s, npl_stack_t *h)
588+{
589+ Code c;
590+ int loop = 1;
591+
592+ while (loop) {
593+ if (get_code(h, &c))
594+ break;
595+ if (code == NULL) {
596+ push_code(s, &c);
597+ remove_code(h);
598+ continue;
599+ }
600+ switch (c.ct) {
601+ case CT_U_PLUS:
602+ case CT_U_MINUS:
603+ case CT_PLUS:
604+ case CT_MINUS:
605+ switch (code->ct) {
606+ case CT_MUL:
607+ case CT_DIV:
608+ case CT_MOD:
609+ case CT_POW:
610+ loop = 0;
611+ break;
612+ default:
613+ push_code(s, &c);
614+ remove_code(h);
615+ break;
616+ }
617+ break;
618+ case CT_MUL:
619+ case CT_DIV:
620+ case CT_MOD:
621+ switch (code->ct) {
622+ case CT_POW:
623+ loop = 0;
624+ break;
625+ default:
626+ push_code(s, &c);
627+ remove_code(h);
628+ break;
629+ }
630+ break;
631+ case CT_POW:
632+ switch (code->ct) {
633+ default:
634+ push_code(s, &c);
635+ remove_code(h);
636+ break;
637+ }
638+ break;
639+ case CT_EQ:
640+ switch (code->ct) {
641+ case CT_U_PLUS:
642+ case CT_U_MINUS:
643+ case CT_PLUS:
644+ case CT_MINUS:
645+ case CT_MUL:
646+ case CT_DIV:
647+ case CT_MOD:
648+ case CT_POW:
649+ loop = 0;
650+ break;
651+ default:
652+ push_code(s, &c);
653+ remove_code(h);
654+ break;
655+ }
656+ break;
657+ default:
658+ fprintf(stderr, "unknown operator.\n");
659+ exit(1);
660+ break;
661+ }
662+ }
663+}
664+
665+// 中置記法コード(トークン)を
666+// 後置記法コード(実行コード)に変換する。
667+int compile(npl_stack_t *s)
668+{
669+ npl_stack_t *t, *u, *v;
670+ Code code, c;
671+ int first; // 単項演算子を判別するため
672+
673+ // セットアップ
674+ t = my_stack_new();
675+ u = my_stack_new();
676+ v = my_stack_new();
677+ pop_code_all(s, t);
678+
679+ // 変換処理
680+ first = 1;
681+ while (pop_code(t, &code) == 0) {
682+ switch (code.ct) {
683+ case CT_NUM:
684+ case CT_VAR:
685+ push_code(v, &code);
686+ if (first)
687+ first = 0;
688+ break;
689+ case CT_PLUS:
690+ case CT_MINUS:
691+ case CT_MUL:
692+ case CT_DIV:
693+ case CT_MOD:
694+ case CT_POW:
695+ if (first) {
696+ if (code.ct == CT_PLUS)
697+ code.ct = CT_U_PLUS;
698+ if (code.ct == CT_MINUS)
699+ code.ct = CT_U_MINUS;
700+ first = 0;
701+ }
702+ put_back_op(&code, v, u);
703+ push_code(u, &code);
704+ break;
705+ case CT_EQ:
706+ push_code(u, &code);
707+ first = 1;
708+ break;
709+ case CT_LP:
710+ my_stack_enter(u);
711+ first = 1;
712+ break;
713+ case CT_RP:
714+ pop_code_all(u, v);
715+ my_stack_leave(u);
716+ first = 0;
717+ break;
718+ }
719+ }
720+
721+ pop_code_all(u, v);
722+ pop_code_all(v, s);
723+
724+ // 終了
725+ npl_object_unref(NPL_OBJECT(v));
726+ npl_object_unref(NPL_OBJECT(u));
727+ npl_object_unref(NPL_OBJECT(t));
728+
729+ return 0;
730+}
731+
732+// 数式を表す文字列を字句解析して、
733+// 中置記法コード(トークン)をスタック s に
734+// 格納する。
735+int parse(wchar_t *sbuf, npl_stack_t *s)
736+{
737+ int num, n;
738+ size_t i;
739+ Code code;
740+ npl_sbuf_t *sb;
741+ wchar_t wcs[4];
742+
743+ // 文字が数字の続きである場合は 1,
744+ // 文字が識別子の続きである場合は 2
745+ int flag;
746+
747+ if ((sb = npl_sbuf_new()) == NULL) {
748+ fprintf(stderr, "npl_sbuf_new() failed.\n");
749+ exit(1);
750+ }
751+ wmemset(wcs, L'\0', 4);
752+
753+ flag = 0;
754+ for (i=0; sbuf[i] != L'\0'; i++) {
755+ if (sbuf[i] == L'\n')
756+ break;
757+ if (flag == 1) {
758+ if (is_num(sbuf[i])) {
759+ n = to_num(sbuf[i]);
760+ if (num != 0 && 10 > (INT_MAX / num))
761+ goto ERROR;
762+ num *= 10;
763+ if (num + n < num)
764+ goto ERROR;
765+ num += n;
766+ continue;
767+ } else {
768+ push_num(s, num);
769+ flag = 0;
770+ }
771+ } else if (flag == 2) {
772+ if (is_alnum(sbuf[i])) {
773+ wcs[0] = sbuf[i];
774+ if (npl_sbuf_add(sb, wcs))
775+ goto ERROR;
776+ continue;
777+ } else {
778+ push_var(s, npl_buf_get(NPL_BUF(sb)));
779+ flag = 0;
780+ }
781+ }
782+ if (is_num(sbuf[i])) {
783+ num = to_num(sbuf[i]);
784+ flag = 1;
785+ } else if (is_alpha(sbuf[i])) {
786+ npl_buf_clear(NPL_BUF(sb));
787+ wcs[0] = sbuf[i];
788+ if (npl_sbuf_add(sb, wcs))
789+ goto ERROR;
790+ flag = 2;
791+ } else {
792+ switch (sbuf[i]) {
793+ case L' ':
794+ case L'\t':
795+ break;
796+ case L'+':
797+ push_plus(s);
798+ break;
799+ case L'-':
800+ push_minus(s);
801+ break;
802+ case L'*':
803+ push_mul(s);
804+ break;
805+ case L'/':
806+ push_div(s);
807+ break;
808+ case L'%':
809+ push_mod(s);
810+ break;
811+ case L'(':
812+ push_lp(s);
813+ break;
814+ case L')':
815+ push_rp(s);
816+ break;
817+ case L'^':
818+ push_pow(s);
819+ break;
820+ case L'=':
821+ push_eq(s);
822+ break;
823+ default:
824+ goto ERROR;
825+ break;
826+ }
827+ }
828+ }
829+
830+ if (flag == 1)
831+ push_num(s, num);
832+ else if (flag == 2)
833+ push_var(s, npl_buf_get(NPL_BUF(sb)));
834+
835+ npl_object_unref(NPL_OBJECT(sb));
836+ return 0;
837+
838+ERROR:
839+ npl_object_unref(NPL_OBJECT(sb));
840+ return 1;
841+}
842+
843+int main(void)
844+{
845+ npl_stream_t *out, *in;
846+ npl_sbuf_t *sbuf;
847+ npl_stack_t *s;
848+ int num;
849+
850+ if (npl_init()) {
851+ fprintf(stderr, "npl_init() failed.\n");
852+ exit(1);
853+ }
854+
855+ // ストリーム
856+ if ((out = npl_stream_stdout()) == NULL) {
857+ fprintf(stderr, "npl_stream_stdout() failed.\n");
858+ exit(1);
859+ }
860+ if ((in = npl_stream_stdin()) == NULL) {
861+ fprintf(stderr, "npl_stream_stdin() failed.\n");
862+ exit(1);
863+ }
864+
865+ // 文字列バッファ
866+ if ((sbuf = npl_sbuf_new()) == NULL) {
867+ fprintf(stderr, "npl_sbuf_new() failed.\n");
868+ exit(1);
869+ }
870+
871+ // 新しいスタック・オブジェクトを作成する
872+ if ((s = npl_stack_new()) == NULL) {
873+ fprintf(stderr, "npl_stack_new() failed.\n");
874+ exit(1);
875+ }
876+
877+ // 変数スタック
878+ if ((var_stack = npl_stack_new()) == NULL) {
879+ fprintf(stderr, "npl_stack_new() failed.\n");
880+ exit(1);
881+ }
882+ if (npl_stack_enter_obj(var_stack)) {
883+ fprintf(stderr, "npl_stack_enter_obj() failed.\n");
884+ exit(1);
885+ }
886+
887+ // 数式インタプリタ
888+ while (1) {
889+ npl_stream_write(out, L" >> ");
890+ if (npl_stream_read(in, sbuf))
891+ break;
892+ if (npl_stream_eof(in) || npl_stream_error(in)) {
893+ printf("\n");
894+ break;
895+ }
896+
897+ npl_stack_clean(s);
898+ if (parse(npl_buf_get(NPL_BUF(sbuf)), s)) {
899+ fprintf(stderr, "parse error.\n");
900+ continue;
901+ }
902+ if (compile(s)) {
903+ fprintf(stderr, "compile error.\n");
904+ continue;
905+ }
906+ if (calc(s)) {
907+ fprintf(stderr, "calc error.\n");
908+ continue;
909+ }
910+
911+ if (pop_num(s, &num) == 0)
912+ printf("%d\n", num);
913+ }
914+
915+ // オブジェクトは、もう参照しない
916+ npl_object_unref(NPL_OBJECT(var_stack));
917+ npl_object_unref(NPL_OBJECT(s));
918+ npl_object_unref(NPL_OBJECT(sbuf));
919+ npl_object_unref(NPL_OBJECT(in));
920+ npl_object_unref(NPL_OBJECT(out));
921+
922+ if (npl_final()) {
923+ fprintf(stderr, "npl_final() failed.\n");
924+ exit(1);
925+ }
926+
927+ return 0;
928+}
929+
--- trunk/npl/stack.c (revision 63)
+++ trunk/npl/stack.c (revision 64)
@@ -23,13 +23,14 @@
2323 npl_sblock_t *sb = s->stack;
2424
2525 s->stack = _get_prev(s->stack);
26+ if (s->stack != NULL)
27+ npl_object_ref(NPL_OBJECT(s->stack));
28+ npl_sblock_clear(sb);
2629
27- if (s->unused == NULL) {
28- npl_sblock_clear(sb);
30+ if (s->unused == NULL)
2931 s->unused = sb;
30- } else {
32+ else
3133 npl_object_unref(NPL_OBJECT(sb));
32- }
3334 }
3435 }
3536
@@ -242,7 +243,6 @@
242243
243244 assert(s);
244245 assert(bytes > 0);
245- assert(p);
246246
247247 if (npl_sub(s->count, bytes, &new_count))
248248 return 1; // 要素なし
@@ -253,6 +253,34 @@
253253 return 0;
254254 }
255255
256+int npl_stack_remove(npl_stack_t *s, size_t bytes)
257+{
258+ return npl_stack_pop(s, bytes, NULL);
259+}
260+
261+int npl_stack_get(npl_stack_t *s, size_t offset, size_t bytes, void *p)
262+{
263+ npl_sblock_t *sb;
264+ size_t count;
265+
266+ assert(s);
267+
268+ sb = s->stack;
269+ if (npl_add(offset, bytes, &count))
270+ return 1; // 要素なし
271+ if (count > s->count)
272+ return 1; // 要素なし
273+
274+ while (offset >= sb->sp) {
275+ offset -= sb->sp;
276+ if (NPL_BLOCK(sb)->link == NULL)
277+ return 1; // 要素なし
278+ sb = NPL_SBLOCK(NPL_BLOCK(sb)->link);
279+ }
280+
281+ return npl_sblock_get(sb, offset, bytes, p);
282+}
283+
256284 int npl_stack_enter_obj(npl_stack_t *s)
257285 {
258286 return _enter(s, _cleaner_obj);
--- trunk/npl/sblock.c (revision 63)
+++ trunk/npl/sblock.c (revision 64)
@@ -64,19 +64,43 @@
6464
6565 assert(sb);
6666 assert(bytes > 0);
67- assert(p);
6867
6968 if (npl_sub(sb->sp, bytes, &new_sp))
7069 return 1; // ポップできない
7170
7271 sb->sp = new_sp;
73- s = NPL_CHUNK(sb)->chunk;
74- s = s + sb->sp;
75- memcpy(p, s, bytes);
72+ if (p != NULL) {
73+ s = NPL_CHUNK(sb)->chunk;
74+ s = s + sb->sp;
75+ memcpy(p, s, bytes);
76+ }
7677
7778 return 0;
7879 }
7980
81+int npl_sblock_get(npl_sblock_t *sb, size_t offset, size_t bytes, void *p)
82+{
83+ size_t sp;
84+ unsigned char *s;
85+
86+ assert(sb);
87+ assert(bytes > 0);
88+
89+ sp = sb->sp;
90+ if (npl_sub(sp, offset, &sp))
91+ return 1; // 要素なし
92+ if (npl_sub(sp, bytes, &sp))
93+ return 1; // 要素なし
94+
95+ if (p != NULL) {
96+ s = NPL_CHUNK(sb)->chunk;
97+ s = s + sp;
98+ memcpy(p, s, bytes);
99+ }
100+
101+ return 0;
102+}
103+
80104 void npl_sblock_clear(npl_sblock_t *sb)
81105 {
82106 assert(sb);
旧リポジトリブラウザで表示