mirror of
https://github.com/vlang/v.git
synced 2025-08-03 17:57:59 -04:00
103 lines
2.1 KiB
V
103 lines
2.1 KiB
V
// Q: What's this?
|
|
// A: A simple arithmetic calculator, similar to examples/mini_calculator.v,
|
|
// but *without* an explicit stack. Instead, it re-uses the one from the host language.
|
|
// It also demonstrates how to use textscanner.TextScanner from the V standart library.
|
|
// See https://modules.vlang.io/strings.textscanner.html ,
|
|
// and also https://en.wikipedia.org/wiki/Recursive_descent_parser .
|
|
module main
|
|
|
|
import os
|
|
import strconv
|
|
import strings.textscanner
|
|
|
|
struct Parser {
|
|
textscanner.TextScanner
|
|
}
|
|
|
|
fn (mut p Parser) parse_expression() !f64 {
|
|
mut result := p.parse_term()!
|
|
for {
|
|
p.skip_whitespace()
|
|
c := p.peek_u8()
|
|
if c == `+` {
|
|
p.next()
|
|
result += p.parse_term()!
|
|
} else if c == `-` {
|
|
p.next()
|
|
result -= p.parse_term()!
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
fn (mut p Parser) parse_term() !f64 {
|
|
mut result := p.parse_factor()!
|
|
for {
|
|
p.skip_whitespace()
|
|
c := p.peek_u8()
|
|
if c == `*` {
|
|
p.next()
|
|
result *= p.parse_factor()!
|
|
} else if c == `/` {
|
|
p.next()
|
|
result /= p.parse_factor()!
|
|
} else {
|
|
break
|
|
}
|
|
}
|
|
return result
|
|
}
|
|
|
|
fn (mut p Parser) parse_factor() !f64 {
|
|
p.skip_whitespace()
|
|
c := p.peek_u8()
|
|
if c.is_digit() {
|
|
return p.parse_number()
|
|
} else if c == `(` {
|
|
p.next()
|
|
result := p.parse_expression()!
|
|
p.skip_whitespace()
|
|
if p.next() != `)` {
|
|
return error('Expected closing parenthesis')
|
|
}
|
|
return result
|
|
}
|
|
return error('Expected number or opening parenthesis')
|
|
}
|
|
|
|
fn (mut p Parser) parse_number() !f64 {
|
|
start := p.pos
|
|
for {
|
|
c := p.peek_u8()
|
|
if c.is_digit() || c == `.` || c == `e` || c == `E` {
|
|
p.next()
|
|
continue
|
|
}
|
|
break
|
|
}
|
|
num_str := p.input[start..p.pos]
|
|
return strconv.atof64(num_str) or { return error('Invalid number') }
|
|
}
|
|
|
|
println('Please enter the expression you want to calculate, e.g. `2 * (5-1)` .')
|
|
println("Enter 'exit' or 'EXIT' to quit.")
|
|
mut expr_count := 0
|
|
for {
|
|
expr_count++
|
|
input := os.input_opt('[${expr_count}] ') or {
|
|
println('')
|
|
break
|
|
}.trim_space()
|
|
if input in ['exit', 'EXIT'] {
|
|
break
|
|
}
|
|
mut parser := Parser{textscanner.new(input)}
|
|
result := parser.parse_expression() or {
|
|
println('Error: ${err}')
|
|
continue
|
|
}
|
|
println(result)
|
|
}
|