! Example of Lindenmayer system.
! Author: Francois Tonneau

size 18 15

set color #afbb63 cap round

dist = 0.1

angle = torad(50)

turn = torad(25)

mark = 0

sub expansion letter$
    if letter$ = "F" then
        return "FF"
    else &
    if letter$ = "X" then
        return "F[+X][X]F[+X]-FX"
    else
        return letter$
    end if
end sub

sub goforward
    rline dist*cos(angle) dist*sin(angle)
end sub

sub turnleft
    angle = angle + turn
end sub

sub turnright
    angle = angle - turn
end sub

! We abuse named points to simulate push() and pop() functions on a stack; the
! 'mark' variable is increased or decreased as the depth of the stack varies.

sub takenote
    mark = mark + 1
    local placetag$ = eval("place_" + mark)
    save placetag$
    gsave
    local angletag$ = eval("angle_" + mark)
    amove angle 0
    save angletag$
    grestore
end sub

sub comeback
    local placetag$ = eval("place_" + mark)
    amove ptx(placetag$.cc) pty(placetag$.cc)
    local angletag$ = eval("angle_" + mark)
    angle = ptx(angletag$.cc)
    mark = mark - 1
end sub

sub takeaction letter$
    if letter$ = "F" then
        goforward
    else &
    if letter$ = "+" then
        turnleft
    else &
    if letter$ = "-" then
        turnright
    else &
    if letter$ = "[" then
        takenote
    else &
    if letter$ = "]" then
        comeback
    end if
end sub

sub growplant times
    local stage
    for stage = 1 to times
        local adult$ = ""
        local pos, code$
        for pos = 1 to len(plant$)
            code$ = seg$(plant$, pos, pos)
            adult$ = adult$ + expansion(code$)
        next pos
        plant$ = adult$
    next stage
end sub

sub drawplant
    local pos, code$
    for pos = 1 to len(plant$)
        code$ = seg$(plant$, pos, pos)
        takeaction(code$)
    next pos
end sub

plant$ = "X"
growplant times 6

amove 1 1
drawplant

