v

Зеркало из https://github.com/vlang/v
Форк
0
/
mini_calculator.v 
135 строк · 2.7 Кб
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".
3
import os
4

5
const numeric_char = [`0`, `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`, `9`, `.`, `e`, `E`]
6

7
// Convert expression to Reverse Polish Notation.
8
fn 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.
66
fn 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

103
fn 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

112
fn 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
}
136

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.