v
Зеркало из https://github.com/vlang/v
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 {
9if expr == '' {
10return error('err: empty expression')
11}
12mut stack := []string{}
13mut rev_pol := []string{}
14mut pos := 0
15for pos < expr.len {
16mut end_pos := pos
17for end_pos < expr.len && expr[end_pos] in numeric_char {
18end_pos++
19}
20if end_pos > pos {
21stack << expr[pos..end_pos]
22pos = end_pos
23} else if end_pos == pos {
24op := expr[pos].ascii_str()
25match op {
26'(' {
27stack << op
28}
29'*', '/' {
30for stack.len > 0 && stack.last() !in ['(', '+', '-'] {
31rev_pol << stack.last()
32stack.delete(stack.len - 1)
33}
34stack << op
35}
36'+', '-' {
37for stack.len > 0 && stack.last() != '(' {
38rev_pol << stack.last()
39stack.delete(stack.len - 1)
40}
41stack << op
42}
43')' {
44for stack.len > 0 && stack.last() != '(' {
45rev_pol << stack.last()
46stack.delete(stack.len - 1)
47}
48stack.delete(stack.len - 1)
49}
50else {
51return error('err: invalid character `${op}`')
52}
53}
54pos++
55}
56}
57for stack.len > 0 {
58top := stack.last()
59rev_pol << top
60stack.delete(stack.len - 1)
61}
62return rev_pol
63}
64
65// Evaluate the result of Reverse Polish Notation.
66fn eval_rev_pol(rev_pol []string) !f64 {
67mut stack := []f64{}
68for item in rev_pol {
69if is_num_string(item) {
70stack << item.f64()
71} else {
72if stack.len >= 2 {
73oprand_r := stack.last()
74stack.delete(stack.len - 1)
75oprand_l := stack.last()
76stack.delete(stack.len - 1)
77match item {
78'+' {
79stack << oprand_l + oprand_r
80}
81'-' {
82stack << oprand_l - oprand_r
83}
84'*' {
85stack << oprand_l * oprand_r
86}
87'/' {
88if oprand_r == 0 {
89return error('err: divide by zero')
90}
91stack << oprand_l / oprand_r
92}
93else {}
94}
95} else {
96return error('err: invalid expression')
97}
98}
99}
100return stack[0]
101}
102
103fn is_num_string(str string) bool {
104for c in str {
105if c !in numeric_char {
106return false
107}
108}
109return true
110}
111
112fn main() {
113println('Please enter the expression you want to calculate, e.g. 1e2+(3-2.5)*6/1.5 .')
114println("Enter 'exit' or 'EXIT' to quit.")
115mut expr_count := 0
116for {
117expr_count++
118expr := os.input_opt('[${expr_count}] ') or {
119println('')
120break
121}.trim_space()
122if expr in ['exit', 'EXIT'] {
123break
124}
125rev_pol := expr_to_rev_pol(expr) or {
126eprintln(err)
127continue
128}
129res := eval_rev_pol(rev_pol) or {
130eprintln(err)
131continue
132}
133println(res)
134}
135}
136