diff --git a/examples/mini_calculator.v b/examples/mini_calculator.v new file mode 100644 index 0000000000..bb97763d71 --- /dev/null +++ b/examples/mini_calculator.v @@ -0,0 +1,134 @@ +// 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 pospos { + stack << expr[pos..end_pos] + pos = end_pos + } + else if end_pos==pos { + op := expr[pos].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++ + print('[$expr_count] ') + expr := os.get_line().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) + } +} \ No newline at end of file