the sfip language
1. a practical presentation
To try the sfip programming language, you simply need to download the source, extract it, and then run at the command shell:
To execute a file, simply enter load2("file") at the prompt.
You can also turn exec.lisp into an executable and then run exec.lisp file at the command shell
To quit, simply type QUIT() at the prompt
sfip can manage arithmetic calcul in infix form.
So, you can write 4+2*(5-2) as you would do in any language different from lisp. Conversely to lisp, you do not have to put spaces.
To set a value to a variable, you can simply type a=4+6
and then you can type a+1 and obtain 11.
To test wether two variables are equal, you simply type a==b
a++ will increment a, as in C, whereas a-- will decrement it
For this part, you will need to execute another file
To print something, simply use for example:
print 4+3 You do not need any parenthese.
In sfip, indentation matters, as in python. Be careful to use indentation and not spaces.
Note that Commentaries are as in C.
You can simply write:
You can also write everything on the same line, but then, you simply need a comma after what was tested in the if.
if a==6, print 4
else print 3
For the loop construct, you can simply write:
To enter a function which will return the sum of its arguments:
You can also write:
defun g(a,b) a+b
to execute functions, it is the same as in C:
to enter the factorial function:
if n==0, 1
compatibility with lisp
You can call any lisp function if you put their name in upper-case.
But you will have to call them as in C. So, typing F(4,6) will be like typing (f 4 6) in lisp.
If the name of the function contains - you will have to use for example |A-FUNCTION|(4,5):
The two | means that what is inside will correspond to a single symbol.
In the following, we will use the lisp functions CONS, FIRST, REST, NULL.
However, lisp macros can't be used as simply as functions.
If you know a language using match, as Caml, you know that match is very useful to write small and easily understandable code.
match also exist in sfip.
If you wanted to enter a function returning the sum of the elements of a list, you could write:
if NULL(l), 0
but you can also do it with match:
NIL->0 //this is executed is l is equal to NIL
a:m->a+sum_match(m) //a will be FIRST(l) and m REST(l)
we can test it with sum_match('(2 6 3))
You enter can enter lists with ' as in lisp.
In the previous example, match do not seem so useful.
But, if you wanted to check wether the three first elements of a list are equal, you could use:
This will work whatever the size of l is. It will simply return NIL if l has less than three elements.
But match can also work with several variables at the same time.
You could write a function append2 to concatenate two lists like this:
2. a theorical presentation
sfip is based on the eval2 function.
It is a little different than the one of the interpreter described here. It also relies on triggers, and it is still used to process lists. However, the result is a lisp which will be processed with the eval function.
But this does not mean that we use a syntax to convert directly code to lisp code to evaluate it with eval: in fact, the syntax is minimal. For example, the if and loop constructs described in the previous part do not belong to the syntax: they are simply triggers. The code is processed by eval2 and the result is sent to eval.
In fact, the ultimate goal of sfip would be to be independant from any lisp implementation, and to be able to compile code by itself, without passing by eval.
However, for now, it is really easier to use the power and speed of lisp implementations.
You can see the lisp code returned by eval2 when you evaluate a file by passing more arguments to load2.
In fact, load2 is written in lisp and its code begins like this:
(defun |load2|(name &optional info-lex info)
info-lex if for wether you want to print the code remaining from the syntax, and info is for wether you want to print the lisp-code produced by eval2 before to evaluate it with eval.
the minimal syntax of sfip
The syntax of sfip, as the one of lisp, is really minimal. It is quite similar to the one of lisp, but with a few differences.
Firstly, sfip is case-sensitive by default.
Another difference is that indentation is equivalent to parentheses.
; can be used to separate instructions, as in C. However, there is a ; at the end of each line. But we can remove it using an \ at the end of a line.
Another difference is that the syntax differenciates between alpha-numeric characters and others.
If some alpha-numeric characters are followed by characters which are not alpha-numeric, then it will be seen as two different symbols.
so, a-b will be seen as three different symbols: a - b whereas in lisp, it will be seen as a single symbol.
However, we can still use | | to indicate that what is between the | corresponds to a single symbol.
So, |a-b| will be seen as a single symbol.
variables and functions
When the eval2 function sees a symbol which is not a trigger, it will check wether it is followed by a sublist or not.
If it is, it will be seen as a function, and the arguments will pass through eval2. Either, it will be seen as a variable.
so, f(4,3,5) will produce (f 4 3 5) whereas f not followed by a sublist will produce f
This is why you can use lisp functions and lisp variables.
But you will have to use upper-case, since sfip is case-sensitive. However, in common-lisp, you can also use for example |func| for the name of a function, and in that case, it will not be in upper-case, and you can use directly func in sfip.
In a sfip file, you can use the load function of lisp by simply typing LOAD("file.lisp")
So, you can enter in a lisp file:
(defun f (a b)
and call it with
F(4,5) in sfip.
You can also enter:
(defun |f| (a b)
and call it with
f(4,5) in sfip
You can also enter:
(defun |a-function| (a b)
and call it with
|a-function|(4,5) in sfip