Filska

From Esolang
Jump to navigation Jump to search

Filska (pronounced "full-ska", Shetland for "high spirited fun") is an esoteric programming language designed to answer the question: what is it like to program in a language where each subprogram can manipulate only a single memory location?

Rationale

Filska is a simple language similar to assembly. It's used to explore programming in a constrained environment. A Filska program may have multiple subprograms, but each subprogram gets only a single floating-point memory location for data. Additionally, there are three floating-point registers, X, Y, and Z, for moving data between subprograms.

Filska is unstructured. To move around within a subprogram, use GTO ("goto") with an offset from the current instruction. There are two options for moving between subprograms: JMP ("jump") and JPR ("jump with reset"). Each subprogram maintains its own program counter. Moving to another subprogram with JMP does not reset this counter, so moving back to the subprogram continues execution with the next instruction. Moving with JPR does reset the counter so returning to the subprogram begins again at the first instruction. When the final instruction of a subprogram is executed, the program counter automatically resets to zero and execution continues (implied looping). There is no execution stack, subprograms are not subroutines.

Filska supports the full range of mathematical operators making mathematical examples the natural target for the language.

Filska is featured in Chapters 12 and 13 of the book Strange Code: Esoteric Languages That Make Programming Fun Again (No Starch Press, 2022).

Examples

Pi

Estimate π using random numbers:

{ main
    set,0
    tmy             " Y=0
    jmp,incS        " S++
    rnd
    tmz
    mul,m=mz
    tmx
    rnd
    tmz
    mul,m=mz
    add,m=mx        " x^2+y^2
    cmp,1
    tst,l,2
    gto,2
    jmp,incC
    set,1
    tmy
    jmp,incC
    tzm
    jmp,incS
    div,m=mz
    tmz
    jmp,print
}
{ print
    set,4
    mul,m=mz
    prt
    set,10
    chr
    jpr,main
}
{ incS
    swp,my
    cmp,1
    tst,e,4
    swp,my
    inc
    jpr,main
    swp,my
    tmz
    jpr,main
}
{ incC
    swp,my
    cmp,1
    tst,e,4
    swp,my
    inc
    jpr,main
    swp,my
    tmz
    jpr,main
}

Roots

Calculate the roots of a quadratic equation:

{ main
    "  Get a, b, and c
    jmp,getA
    jmp,getB
    jmp,getC
    
    "  Calculate D
    jmp,getA        " X=a
    set,4           " M=4
    mul,m=mx        " M = M*X  (4a)
    jmp,getC        " X=c
    mul,m=mx        " M = M*X  (4ac)
    neg             " M = -M   (-4ac)
    tmz             " Z = M    (-4ac)
    jmp,getB        " X=b
    txm             " M=b
    mul,m=mx        " M = M*X  (b*b)
    add,m=mz        " M = M+Z  (b*b - 4ac)
    tmy             " Y = D    (disc)
    jmp,getA        " X = a
    txm             " M = X
    tmz             " Z = M    (a)
    jmp,getB        " X = b    (b)
    tym             " M = Y    (disc)
    cmp,0           " compare(M,0)
    tst,g,3         " D > 0  --> positive
    tst,e,3         " D == 0 --> equal
    tst,l,3         " D < 0  --> negative
    jmp,positive
    jmp,equal
    jmp,negative
}

" Calculate roots w/Z == a, Y == D, X == b
{ positive
    set,2           " M = 2
    mul,m=mz        " M = 2a
    div,m=xm        " M = b/(2a)
    neg             " M = -b/(2a)
    jmp,rest        " X = sqr(Y)/(2a)
    jmp,?double
    add,y=mx        " Y = M + X    (-b/(2a)+sqr(D)/(2a))
    jmp,?double
    sub,y=mx        " Y = M - X    (-b/(2a)-sqrt(D)/(2a))
    jmp,?double
}
{ rest
    set,2
    mul,x=mz
    tym
    sqr
    div,x=mx
    jmp,positive
}
{ ?double
    set,10 chr
    set,49 chr
    set,115 chr
    set,116 chr
    set,32 chr
    set,114 chr
    set,111 chr chr
    set,116 chr
    set,58 chr
    set,32 chr
    jmp,positive
    tym
    prt
    set,10 chr
    set,50 chr
    set,110 chr
    set,100 chr
    set,32 chr
    set,114 chr
    set,111 chr chr
    set,116 chr
    set,58 chr
    set,32 chr
    jmp,positive
    tym
    prt
    set,10 chr
    hlt
}
{ equal
    set,2           " M = 2
    mul,m=mz        " M = 2a
    div,m=xm        " M = b/(2a)
    neg             " M = -b/(2a)
    jmp,?single
    prt             " print single root
    set,10
    chr
    hlt
}
{ ?single
    set,10 chr
    set,79 chr
    set,110 chr
    set,101 chr
    set,32 chr
    set,114 chr
    set,111 chr chr
    set,116 chr
    set,58 chr
    set,32 chr
    jmp,equal
}
{ negative
    set,2           " M = 2
    mul,m=mz        " M = 2a
    div,m=xm        " M = b/(2a)
    neg             " M = -b/(2a)
    swp,mz          " M <--> Z
    jmp,stash
    swp,mz          " M <--> Z
    jmp,resti       " X = sqr(-Y)/(2a)
    jmp,?imag       " '1st root: '
    prt
    set,43 chr
    txm
    prt
    set,105 chr
    set,10 chr
    jmp,?imag       " '2nd root: '
    jmp,stash
    tzm
    prt
    set,45 chr
    txm
    prt
    set,105 chr
    set,10 chr
    hlt
}
{ stash
    tzm
    jmp,negative
    tmz
    jmp,negative
}
{ ?imag
    " 'Complex roots: '
    set,10 chr
    set,67 chr
    set,111 chr
    set,109 chr
    set,112 chr
    set,108 chr
    set,101 chr
    set,120 chr
    set,32 chr
    set,114 chr
    set,111 chr chr
    set,116 chr
    set,115 chr
    set,58 chr
    set,32 chr
    jmp,negative
    " '               '
    set,32
    chr chr chr chr chr
    chr chr chr chr chr
    chr chr chr chr chr
    jmp,negative
}
{ resti
    set,2
    mul,x=mz
    tym
    neg
    sqr
    div,x=mx
    jmp,negative
}

"  Ask for and return a,b, and c
{ getA
    set,65 chr
    set,63 chr
    set,32 chr
    ipt
    jmp,main
    tmx
    jmp,main
    gto,-2
}
{ getB
    set,66 chr
    set,63 chr
    set,32 chr
    ipt
    tmx
    jmp,main
    gto,-2
}
{ getC
    set,67 chr
    set,63 chr
    set,32 chr
    ipt
    tmx
    jmp,main
    gto,-2
}

Computational class

Filska supports an arbitrary number of subprograms that can be configured to act like memory locations. Filska might be Turing complete.

Implementations