forked from garrigue/lablgtk
-
Notifications
You must be signed in to change notification settings - Fork 0
/
rpn.ml
133 lines (118 loc) · 4.16 KB
/
rpn.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
(**************************************************************************)
(* Lablgtk - Examples *)
(* *)
(* This code is in the public domain. *)
(* You may freely copy parts of it in your application. *)
(* *)
(**************************************************************************)
(* $Id$ *)
(* reverse polish calculator *)
open StdLabels
open GMain
let wow _ = prerr_endline "Wow!"; ()
let main () =
let stack = Stack.create () in
(* toplevel window *)
let window =
GWindow.window ~border_width: 10 ~title:"Reverse Polish Calculator" () in
window#connect#destroy ~callback:Main.quit;
(* vbox *)
let vbx = GPack.vbox ~packing:window#add () in
(* entry *)
let entry =
GEdit.entry ~text:"0" ~editable:false ~max_length: 20 ~packing: vbx#add () in
(* BackSpace, Clear, All Clear, Quit *)
let table0 = GPack.table ~rows:1 ~columns:4 ~packing:vbx#add () in
let bs_clicked _ = begin
let txt = entry#text in
let len = String.length txt in
if len <= 1 then
entry#set_text "0"
else entry#set_text (String.sub txt ~pos:0 ~len:(len-1))
end in
let c_clicked _ = entry#set_text("0") in
let ac_clicked _ = Stack.clear stack; entry#set_text("0") in
let labels0 = [("BS", bs_clicked) ; ("C", c_clicked);
("AC", ac_clicked); ("Quit", window#destroy)] in
let rec loop0 labels n =
match labels
with [] -> ()
| (lbl, cb) :: t ->
let button =
GButton.button ~label:lbl
~packing:(table0#attach ~left:n ~top:1 ~expand:`BOTH) () in
button#connect#clicked ~callback:cb;
loop0 t (n+1) in
loop0 labels0 1;
(* Numerals *)
let table1 = GPack.table ~rows:4 ~columns:5 ~packing:vbx#add () in
let labels1 = ["7"; "8"; "9"; "4"; "5"; "6"; "1"; "2"; "3"; "0"] in
let numClicked n _ =
let txt = entry#text in
if (txt = "0") then
entry#set_text n
else begin
entry#append_text n
end in
let rec loop1 labels n =
match labels with [] -> ()
| lbl :: lbls ->
let button = GButton.button ~label:(" "^lbl^" ")
~packing:(table1#attach ~left:(n mod 3) ~top:(n/3) ~expand:`BOTH)
() in
button#connect#clicked ~callback:(numClicked lbl);
loop1 lbls (n+1) in
loop1 labels1 0;
(* Period *)
let periodClicked _ =
let txt = entry#text in
if not (String.contains txt '.') then entry#append_text "." in
(GButton.button ~label:" . "
~packing:(table1#attach ~left:1 ~top:3 ~expand:`BOTH) ())
#connect#clicked ~callback:periodClicked;
(* Enter (Push) *)
let enterClicked _ =
let txt = entry#text in
let n = float_of_string txt in begin
Stack.push n stack;
entry#set_text "0"
end in
(GButton.button ~label:"Ent"
~packing:(table1#attach ~left:2 ~top:3 ~expand:`BOTH) ())
#connect#clicked ~callback:enterClicked;
(* Operators *)
let op2Clicked op _ =
let n1 = float_of_string (entry#text) in
let n2 = Stack.pop stack in
entry#set_text (string_of_float (op n2 n1))
in
let op1Clicked op _ =
let n1 = float_of_string (entry#text) in
entry#set_text (string_of_float (op n1))
in
let modClicked _ =
let n1 = int_of_string (entry#text) in
let n2 = truncate (Stack.pop stack) in
entry#set_text (string_of_int (n2 mod n1))
in
let labels2 = [(" / ", op2Clicked (/.)); (" * ", op2Clicked ( *. ));
(" - ", op2Clicked (-.)); (" + ", op2Clicked (+.));
("mod", modClicked); (" ^ ", op2Clicked ( ** ));
("+/-", op1Clicked (~-.));
("1/x", op1Clicked (fun x -> 1.0/.x))] in
let rec loop2 labels n =
match labels
with [] -> ()
| (lbl, cb) :: t ->
let button = GButton.button ~label:lbl
~packing:(table1#attach ~left:(3 + n/4) ~top: (n mod 4)
~expand:`BOTH)
() in
button#connect#clicked ~callback:cb;
loop2 t (n+1)
in
loop2 labels2 0;
(* show all and enter event loop *)
window#show ();
Main.main ()
let _ = Printexc.print main()