diff options
Diffstat (limited to 'v_windows/v/examples/mini_calculator.v')
-rw-r--r-- | v_windows/v/examples/mini_calculator.v | 135 |
1 files changed, 135 insertions, 0 deletions
diff --git a/v_windows/v/examples/mini_calculator.v b/v_windows/v/examples/mini_calculator.v new file mode 100644 index 0000000..0c22aa3 --- /dev/null +++ b/v_windows/v/examples/mini_calculator.v @@ -0,0 +1,135 @@ +// Q: What's this? +// A: This is a mini "home-made" calculator. You may also regard it as a very elementary version of "interpreter". +import os + +const numeric_char = [`0`, `1`, `2`, `3`, `4`, `5`, `6`, `7`, `8`, `9`, `.`, `e`, `E`] + +// Convert expression to Reverse Polish Notation. +fn expr_to_rev_pol(expr string) ?[]string { + if expr == '' { + return error('err: empty expression') + } + mut stack := []string{} + mut rev_pol := []string{} + mut pos := 0 + for pos < expr.len { + mut end_pos := pos + for end_pos < expr.len && expr[end_pos] in numeric_char { + end_pos++ + } + if end_pos > pos { + stack << expr[pos..end_pos] + pos = end_pos + } else if end_pos == pos { + op := expr[pos].ascii_str() + match op { + '(' { + stack << op + } + '*', '/' { + for stack.len > 0 && stack.last() !in ['(', '+', '-'] { + rev_pol << stack.last() + stack.delete(stack.len - 1) + } + stack << op + } + '+', '-' { + for stack.len > 0 && stack.last() != '(' { + rev_pol << stack.last() + stack.delete(stack.len - 1) + } + stack << op + } + ')' { + for stack.len > 0 && stack.last() != '(' { + rev_pol << stack.last() + stack.delete(stack.len - 1) + } + stack.delete(stack.len - 1) + } + else { + return error('err: invalid character `$op`') + } + } + pos++ + } + } + for stack.len > 0 { + top := stack.last() + rev_pol << top + stack.delete(stack.len - 1) + } + return rev_pol +} + +// Evaluate the result of Reverse Polish Notation. +fn eval_rev_pol(rev_pol []string) ?f64 { + mut stack := []f64{} + for item in rev_pol { + if is_num_string(item) { + stack << item.f64() + } else { + if stack.len >= 2 { + oprand_r := stack.last() + stack.delete(stack.len - 1) + oprand_l := stack.last() + stack.delete(stack.len - 1) + match item { + '+' { + stack << oprand_l + oprand_r + } + '-' { + stack << oprand_l - oprand_r + } + '*' { + stack << oprand_l * oprand_r + } + '/' { + if oprand_r == 0 { + return error('err: divide by zero') + } + stack << oprand_l / oprand_r + } + else {} + } + } else { + return error('err: invalid expression') + } + } + } + return stack[0] +} + +fn is_num_string(str string) bool { + for c in str { + if c !in numeric_char { + return false + } + } + return true +} + +fn main() { + println('Please enter the expression you want to calculate, e.g. 1e2+(3-2.5)*6/1.5 .') + println("Enter 'exit' or 'EXIT' to quit.") + mut expr_count := 0 + for { + expr_count++ + expr := os.input_opt('[$expr_count] ') or { + println('') + break + }.trim_space() + if expr in ['exit', 'EXIT'] { + break + } + rev_pol := expr_to_rev_pol(expr) or { + eprintln(err) + continue + } + res := eval_rev_pol(rev_pol) or { + eprintln(err) + continue + } + println(res) + } +} |