Blame view

code/drafts/arithlang.jl 1.08 KB
3e0f9b8a   Francisco Coelho   back to work?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
using ParserCombinator


# the AST nodes we will construct, with evaluation via calc()

abstract type Node end
Base.:(==)(n1::Node, n2::Node) = n1.val == n2.val
calc(n::Float64) = n

struct Const <: Node val end
calc(c::Const) = c.val

struct Inv<:Node val end
calc(i::Inv) = 1.0/calc(i.val)

struct Prd<:Node val end
calc(p::Prd) = Base.prod(map(calc, p.val))

struct Neg<:Node val end
calc(n::Neg) = -calc(n.val)

struct Sum<:Node val end
calc(s::Sum) = Base.sum(map(calc, s.val))


# the grammar (the combinators!)

spc = Drop(Star(Space()))
@with_pre spc begin
    sum = Delayed()
    val = E"(" + sum + E")" | (PFloat64() > Const)

    neg = Delayed()       # allow multiple (or no) negations (eg ---3)
    neg.matcher = val | (E"-" + neg > Neg)

    mul = E"*" + neg
    div = E"/" + neg > Inv
    prd = neg + (mul | div)[0:end] |> Prd

    add = E"+" + prd
    sub = E"-" + prd > Neg
    sum.matcher = prd + (add | sub)[0:end] |> Sum

    all = sum + Eos()
end


# and test

prog = "1+2*3/4"
expr = parse_one(prog, all)[1]

# this prints 2.5
value = calc(expr)

println("$prog → $expr = $value")