v / examples
Raw file | 135 loc (130 sloc) | 2.74 KB | Latest commit hash 017ace6ea
1// Q: What's this?
2// A: This is a mini "home-made" calculator. You may also regard it as a very elementary version of "interpreter".
3import os
4
5const numeric_char = [`0`, `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`, `9`, `.`, `e`, `E`]
6
7// Convert expression to Reverse Polish Notation.
8fn expr_to_rev_pol(expr string) ![]string {
9 if expr == '' {
10 return error('err: empty expression')
11 }
12 mut stack := []string{}
13 mut rev_pol := []string{}
14 mut pos := 0
15 for pos < expr.len {
16 mut end_pos := pos
17 for end_pos < expr.len && expr[end_pos] in numeric_char {
18 end_pos++
19 }
20 if end_pos > pos {
21 stack << expr[pos..end_pos]
22 pos = end_pos
23 } else if end_pos == pos {
24 op := expr[pos].ascii_str()
25 match op {
26 '(' {
27 stack << op
28 }
29 '*', '/' {
30 for stack.len > 0 && stack.last() !in ['(', '+', '-'] {
31 rev_pol << stack.last()
32 stack.delete(stack.len - 1)
33 }
34 stack << op
35 }
36 '+', '-' {
37 for stack.len > 0 && stack.last() != '(' {
38 rev_pol << stack.last()
39 stack.delete(stack.len - 1)
40 }
41 stack << op
42 }
43 ')' {
44 for stack.len > 0 && stack.last() != '(' {
45 rev_pol << stack.last()
46 stack.delete(stack.len - 1)
47 }
48 stack.delete(stack.len - 1)
49 }
50 else {
51 return error('err: invalid character `${op}`')
52 }
53 }
54 pos++
55 }
56 }
57 for stack.len > 0 {
58 top := stack.last()
59 rev_pol << top
60 stack.delete(stack.len - 1)
61 }
62 return rev_pol
63}
64
65// Evaluate the result of Reverse Polish Notation.
66fn eval_rev_pol(rev_pol []string) !f64 {
67 mut stack := []f64{}
68 for item in rev_pol {
69 if is_num_string(item) {
70 stack << item.f64()
71 } else {
72 if stack.len >= 2 {
73 oprand_r := stack.last()
74 stack.delete(stack.len - 1)
75 oprand_l := stack.last()
76 stack.delete(stack.len - 1)
77 match item {
78 '+' {
79 stack << oprand_l + oprand_r
80 }
81 '-' {
82 stack << oprand_l - oprand_r
83 }
84 '*' {
85 stack << oprand_l * oprand_r
86 }
87 '/' {
88 if oprand_r == 0 {
89 return error('err: divide by zero')
90 }
91 stack << oprand_l / oprand_r
92 }
93 else {}
94 }
95 } else {
96 return error('err: invalid expression')
97 }
98 }
99 }
100 return stack[0]
101}
102
103fn is_num_string(str string) bool {
104 for c in str {
105 if c !in numeric_char {
106 return false
107 }
108 }
109 return true
110}
111
112fn main() {
113 println('Please enter the expression you want to calculate, e.g. 1e2+(3-2.5)*6/1.5 .')
114 println("Enter 'exit' or 'EXIT' to quit.")
115 mut expr_count := 0
116 for {
117 expr_count++
118 expr := os.input_opt('[${expr_count}] ') or {
119 println('')
120 break
121 }.trim_space()
122 if expr in ['exit', 'EXIT'] {
123 break
124 }
125 rev_pol := expr_to_rev_pol(expr) or {
126 eprintln(err)
127 continue
128 }
129 res := eval_rev_pol(rev_pol) or {
130 eprintln(err)
131 continue
132 }
133 println(res)
134 }
135}