Mini-LISP is the subset of LISP. You can find the grammar rules in the README.md file. This is the final project of Compiler in NCU, Taiwan.
LISP is an ancient programming language based on S-expressions and lambda calculus. All operations in Mini-LISP are written in parenthesized prefix notation. For example, a simple mathematical formula (1 + 2) * 3 written in Mini-LISP is:
(* (+ 1 2) 3)As a simplified language, Mini-LISP has only three types (Boolean, number and function) and a few operations.
- Syntax Validation
- Numerical Operations
- Logical Operations
- if Expression
- Variable Definition
- Function
- Named Function
- Recursion
- Type Checking
- Nested Function
- First-class Function
Clone the project.
git clone https://github.com/seanwu1105/mini-lisp-interpreterChange directory to project folder.
cd mini-lisp-interpreter/Install the dependencies with Poetry.
poetry install --no-rootFeed the Mini-LISP source codes into the interpreter as standard input file.
python main.py < filename.lspOr import the Interpreter class in mini_lisp_interpreter folder and call the Interpreter().interpret(your_mini_lisp_code).
For example:
mini_lisp_interpreter.Interpreter().interpret(r'(print-num (mod 10 4))')- Boolean: Boolean type includes two values, #tfor true and#ffor false.
- Number: Signed integer from -(231)to231 - 1, behavior out of this range is not defined.
- Function: See Function.
Casting: Not allowed, but type checking is a bonus feature.
| Name | Symbol | Example | Example Output | 
|---|---|---|---|
| Plus | + | (+ 1 2) | 3 | 
| Minus | - | (- 1 2) | -1 | 
| Multiply | * | (* 2 3) | 6 | 
| Divide | / | (/ 10 3) | 3 | 
| Modulus | mod | (mod 8 3) | 2 | 
| Greater | > | (> 1 2) | #f | 
| Smaller | < | (< 1 2) | #t | 
| Equal | = | (= 1 2) | #f | 
| Name | Symbol | Example | Example Output | 
|---|---|---|---|
| And | and | (and #t #f) | #f | 
| Or | or | (or #t #f) | #t | 
| Not | not | (not #t) | #f | 
- define
- fun
- if
All operators are reserved words, you cannot use any of these words as ID.
separator ::= ‘\t’ | ‘\n’ | ‘\r’ | ‘ ’
letter ::= [a-z]
digit ::= [0-9]number ::= 0 | [1-9]digit* | -[1-9]digit*Examples: 0, 1, -23, 123456
ID ::= letter (letter | digit | ‘-’)*Examples: x, y, john, cat-food
bool-val ::= #t | #fPROGRAM ::= STMT+
STMT ::= EXP | DEF-STMT | PRINT-STMT
PRINT-STMT ::= (print-num EXP) | (print-bool EXP)
EXP ::= bool-val | number | VARIABLE | NUM-OP | LOGICAL-OP
| FUN-EXP | FUN-CALL | IF-EXP
NUM-OP ::= PLUS | MINUS | MULTIPLY | DIVIDE | MODULUS | GREATER
| SMALLER | EQUAL
PLUS ::= (+ EXP EXP+)
MINUS ::= (- EXP EXP)
MULTIPLY ::= (* EXP EXP+)
DIVIDE ::= (/ EXP EXP)
MODULUS ::= (mod EXP EXP)
GREATER ::= (> EXP EXP)
SMALLER ::= (< EXP EXP)
EQUAL ::= (= EXP EXP+)
LOGICAL-OP ::= AND-OP | OR-OP | NOT-OP
AND-OP ::= (and EXP EXP+)
OR-OP ::= (or EXP EXP+)
NOT-OP ::= (not EXP)
DEF-STMT ::= (define VARIABLE EXP)
VARIABLE ::= id
FUN-EXP ::= (fun FUN_IDs FUN-BODY)
FUN-IDs ::= (id*)
FUN-BODY ::= EXP
FUN-CALL ::= (FUN-EXP PARAM*) | (FUN-NAME PARAM*)
PARAM ::= EXP
FUN-NAME ::= id
IF-EXP ::= (if TEST-EXP THAN-EXP ELSE-EXP)
TEST-EXP ::= EXP
THEN-EXP ::= EXP
ELSE-EXP ::= EXPPROGRAM :: = STMT+
STMT ::= EXP | DEF-STMT | PRINT-STMTPRINT-STMT ::= (print-num EXP)Behavior: Print exp in decimal.
    | (print-bool EXP)Behavior: Print #t if EXP is true. Print #f, otherwise.
EXP ::= bool-val | number | VARIABLE
    | NUM-OP | LOGICAL-OP | FUN-EXP | FUN-CALL | IF-EXPNUM-OP ::= PLUS | MINUS | MULTIPLY | DIVIDE | MODULUS |
    | GREATER | SMALLER | EQUALBehavior: return sum of all EXP inside.
Example:
(+ 1 2 3 4)   ; → 10Behavior: return the result that the 1st EXP minus the 2nd EXP.
Example:
(- 2 1)   ; → 1Behavior: return the product of all EXP inside.
Example:
(* 1 2 3 4)   ; → 24Behavior: return the result that 1st EXP divided by 2nd EXP.
Example:
(/ 10 5)  ; → 2
(/ 3 2)   ; → 1 (just like C++)Behavior: return the modulus that 1st EXP divided by 2nd EXP.
Example:
(mod 8 5) ; → 3Behavior: return #t if 1st EXP greater than 2nd EXP. #f otherwise.
Example:
(> 1 2)   ; → #fBehavior: return #t if 1st EXP smaller than 2nd EXP. #f otherwise.
Example:
(< 1 2)   ; → #tBehavior: return #t if all EXPs are equal. #f otherwise.
Example:
(= (+ 1 1) 2 (/6 3))  ; → #tLOGICAL-OP ::= AND-OP | OR-OP | NOT-OPBehavior: return #t if all EXPs are true. #f otherwise.
Example:
(and #t (> 2 1))  ; → #tBehavior: return #t if at least one EXP is true. #f otherwise.
Example:
(or (> 1 2) #f)   ; → #fBehavior: return #t if EXP is false. #f otherwise.
Example:
(not (> 1 2)) ; → #tDEF-STMT ::= (define id EXP)VARIABLE ::= idBehavior: Define a variable named id whose value is EXP.
Example:
(define x 5)
(+ x 1)  ; → 6Note: Redefining is not allowed.
FUN-EXP ::= (fun FUN-IDs FUN-BODY)
FUN-IDs ::= (id*)
FUN-BODY ::= EXP
FUN-CALL ::= (FUN-EXP PARAM*)
    | (FUN-NAME PARAM*)
PARAM ::= EXP
FUN-NAME ::= idBehavior:
FUN-EXP defines a function. When a function is called, bind FUN-IDs to PARAMs, just like the define statement. If an id has been defined outside this function, prefer the definition inside the FUN-EXP. The variable definitions inside a function should not affect the outer scope. A FUN-CALL returns the evaluated result of FUN-BODY. Note that variables used in FUN-BODY should be bound to
PARAMs.
Examples:
((fun (x) (+ x 1)) 2) ; → 3
(define foo (fun () 0))
(foo) ; → 0
(define x 1)
(define bar (fun (x y) (+ x y)))
(bar 2 3) ; → 5
x ; → 1IF-EXP ::= (if TEST-EXP THEN-EXP ELSE-EXP)
TEST-EXP ::= EXP
THEN-EXP ::= EXP
ELSE-EXP ::= EXPBehavior: When TEST-EXP is true, returns THEN-EXP. Otherwise, returns ELSE-EXP.
Example:
(if (= 1 0) 1 2)  ; → 2
(if #t 1 2)   ; → 1The interpreter is able to handle recursive function call.
(define f
    (fun (x) (if (= x 1)
                1
                (* x (f (- x 1))))))
(f 4)   ; → 24For type specifications of operations, please check out the table below:
| Op | Parameter Type | Output Type | 
|---|---|---|
| +,-,*,/,mod | Number(s) | Number | 
| <,>,= | Number(s) | Boolean | 
| and,or,not | Boolean(s) | Boolean | 
| if | Boolean(s) for test-exp | Depend on then-expandelse-exp | 
| fun | Any | Function | 
| Function call | Any | Depend on fun-bodyand parameters | 
(> 1 #t)    ; Type Error: Expect 'number' but got 'boolean'.There could be a function inside another function. The inner one is able to access the local variables of the outer function.
The syntax rule of
fun-bodyshould be redefined tofun-body ::= def-stmt* exp
(define dist-square
    (fun (x y)
        (define square
            (fun (x) (* x x)))
        (+ (square x) (square y))))Functions can be passed like other variables. Furthermore, it can keep its environment.
(define chose
    (fun (chose-fun x y)
        (if (chose-fun x y) x y)))
(chose (fun (x y) (> x y)) 2 1) ; → 2
(define add-x
    (fun (x)
        (fun (y) (+ x y))))
(define f (add-x 5))
(f 3)   ; → 8