Skip to content

Commit a6b68b9

Browse files
committed
Initial code commit
1 parent daf6e42 commit a6b68b9

File tree

9 files changed

+1243
-1
lines changed

9 files changed

+1243
-1
lines changed

README.md

+132-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,135 @@
1-
sedlisp
1+
SedLisp
22
=======
33

44
Lisp implementation in sed
5+
6+
7+
How to Use
8+
----------
9+
10+
$ sed -f sedlisp.sed # '>' won't be shown.
11+
> (car (quote (a b c)))
12+
a
13+
> (cdr (quote (a b c)))
14+
(b c)
15+
> (cons 1 (cons 2 (cons 3 ())))
16+
(1 2 3)
17+
> (defun fact (n) (if (eq n 0) 1 (* n (fact (- n 1)))))
18+
(lambda (n) (if (eq n 0) 1 (* n (fact (- n 1)))))
19+
> (fact 10)
20+
3628800
21+
> (defun fib (n) (if (eq n 1) 1 (if (eq n 0) 1 (+ (fib (- n 1)) (fib (- n 2))))))
22+
(lambda (n) (if (eq n 1) 1 (if (eq n 0) 1 (+ (fib (- n 1)) (fib (- n 2))))))
23+
> (fib 12)
24+
233
25+
> (defun gen (n) ((lambda (x y) y) (define G n) (lambda (m) (define G (+ G m)))))
26+
(lambda (n) ((lambda (x y) y) (define G n) (lambda (m) (define G (+ G m)))))
27+
> (define x (gen 100))
28+
(lambda (m) (define G (+ G m)))
29+
> (x 10)
30+
110
31+
> (x 90)
32+
200
33+
> (x 300)
34+
500
35+
36+
37+
Builtin Functions
38+
-----------------
39+
40+
- car
41+
- cdr
42+
- cons
43+
- eq
44+
- atom
45+
- +, -, *, /, mod
46+
- neg?
47+
- print
48+
49+
50+
Special Forms
51+
-------------
52+
53+
- quote
54+
- if
55+
- lambda
56+
- defun
57+
- define
58+
59+
60+
Special Forms
61+
-------------
62+
63+
- quote
64+
- if
65+
- lambda
66+
- defun
67+
- define
68+
69+
70+
More Complicated Examples
71+
-------------------------
72+
73+
You can test a few more examples.
74+
75+
FizzBuzz:
76+
77+
$ cat fizzbuzz.l | sed -f sedlisp.sed
78+
(lambda (n) (if (eq n 101) nil (if (print (if (eq (mod n 15) 0) FizzBuzz (if (eq (mod n 5) 0) Buzz (if (eq (mod n 3) 0) Fizz n)))) (fizzbuzz (+ n 1)) nil)))
79+
PRINT: 1
80+
PRINT: 2
81+
PRINT: Fizz
82+
...
83+
PRINT: 98
84+
PRINT: Fizz
85+
PRINT: Buzz
86+
nil
87+
88+
Sort:
89+
90+
$ cat sort.l /dev/stdin | sed -f sedlisp.sed
91+
...
92+
(sort (quote (4 2)))
93+
(2 4)
94+
(sort (quote (4 2 99 12 -4 -7)))
95+
(-7 -4 2 4 12 99)
96+
97+
Though this Lisp implementation does not support eval function, we can
98+
implement eval on top of this interpreter - eval.l is the
99+
implementation:
100+
101+
$ cat eval.l /dev/stdin | sed -f sedlisp.sed
102+
(eval (quote (+ 4 38)))
103+
42
104+
(eval (quote (defun fact (n) (if (eq n 0) 1 (* n (fact (- n 1)))))))
105+
(fact (lambda (n) (if (eq n 0) 1 (* n (fact (- n 1))))))
106+
(eval (quote (fact 4))) ; Takes 10 seconds or so.
107+
24
108+
109+
This essentially means we have a Lisp interpreter in Lisp. evalify.rb
110+
is a helper script to convert a normal Lisp program into the Lisp in
111+
Lisp. You can run the FizzBuzz program like:
112+
113+
$ ./evalify.rb fizzbuzz.l | sed -f sedlisp.sed
114+
...
115+
PRINT: 1
116+
PRINT: 2
117+
PRINT: Fizz
118+
119+
This takes very long time. For me, it took 45 minutes.
120+
121+
Unfortunately, you cannot nest the eval one more time. This is
122+
probably a limitation of eval.l.
123+
124+
test.l is the test program I was using during the development. test.rb
125+
runs it with sedlisp.sed and purelisp.rb and compare their
126+
results. You can run the test with evalify.rb by passing -e:
127+
128+
$ ./test.rb -e
129+
130+
131+
Limitations
132+
-----------
133+
134+
There should be a lot of limitations. sedlisp behaves very strangely
135+
when you pass a broken Lisp code.

eval.l

+124
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
(defun cadr (s) (car (cdr s)))
2+
(defun cddr (s) (cdr (cdr s)))
3+
4+
(defun table-add (m k v) (cons k (cons v m)))
5+
(defun table-get (m k) (if m (table-get-impl m k) NOT-FOUND))
6+
(defun table-get-impl (m k) (if (eq (car m) k) (cadr m) (table-get (cddr m) k)))
7+
8+
(define gval-table ())
9+
(defun gval-table-add (k v) (define gval-table (table-add gval-table k v)))
10+
11+
(define val-table ())
12+
13+
(defun eval (s) (if (atom s) (eval-val s) (eval-if (car s) (cdr s))))
14+
15+
(defun eval-gval-1 (v s) (if (eq v NOT-FOUND) s v))
16+
(defun eval-gval (s) (eval-gval-1 (table-get gval-table s) s))
17+
18+
(defun eval-val-1 (v s) (if (eq v NOT-FOUND) (eval-gval s) v))
19+
(defun eval-val (s) (eval-val-1 (table-get val-table s) s))
20+
21+
(defun eval-if (o s) (if (eq o if) (run-if s) (eval-defun o s)))
22+
(defun eval-defun (o s) (if (eq o defun) (run-defun s) (eval-lambda o s)))
23+
(defun eval-lambda (o s) (if (eq o lambda) (run-lambda s) (eval-quote o s)))
24+
(defun eval-quote (o s) (if (eq o quote) (run-quote s) (eval-define o s)))
25+
(defun eval-define (o s) (if (eq o define) (run-define s) (eval-func (eval o) s)))
26+
(defun is-func (o) (if (atom o) nil (eq (car o) lambda)))
27+
(defun eval-func (o s) (if (is-func o) (run-func (cdr o) s) (eval-add o s)))
28+
(defun eval-add (o s) (if (eq o +) (run-add s) (eval-sub o s)))
29+
(defun eval-sub (o s) (if (eq o -) (run-sub s) (eval-mul o s)))
30+
(defun eval-mul (o s) (if (eq o *) (run-mul s) (eval-div o s)))
31+
(defun eval-div (o s) (if (eq o /) (run-div s) (eval-mod o s)))
32+
(defun eval-mod (o s) (if (eq o mod) (run-mod s) (eval-eq o s)))
33+
(defun eval-eq (o s) (if (eq o eq) (run-eq s) (eval-car o s)))
34+
(defun eval-car (o s) (if (eq o car) (run-car s) (eval-cdr o s)))
35+
(defun eval-cdr (o s) (if (eq o cdr) (run-cdr s) (eval-cons o s)))
36+
(defun eval-cons (o s) (if (eq o cons) (run-cons s) (eval-atom o s)))
37+
(defun eval-atom (o s) (if (eq o atom) (run-atom s) (eval-neg o s)))
38+
(defun eval-neg (o s) (if (eq o neg?) (run-neg s) (eval-print o s)))
39+
(defun eval-print (o s) (if (eq o print) (run-print s) (undefined-func o)))
40+
(defun undefined-func (o) (print (cons o (quote (undefined func)))))
41+
42+
(defun run-if (s) (if (eval (car s)) (eval (cadr s)) (eval (car (cddr s)))))
43+
(defun run-defun (s) (gval-table-add (car s) (run-lambda (cdr s))))
44+
(defun run-lambda (s) (cons lambda s))
45+
(defun run-quote (s) (car s))
46+
(defun run-define (s) (gval-table-add (car s) (eval (cadr s))))
47+
48+
(defun create-val-table (a p) (if a (cons (car a) (cons (eval (car p)) (create-val-table (cdr a) (cdr p)))) ()))
49+
(defun set-vals (a p) (define val-table (create-val-table a p)))
50+
51+
(defun run-func-2 (a b c) b)
52+
(defun run-func-1 (v l s) (run-func-2 (set-vals (car l) s) (eval (cadr l)) (define val-table v)))
53+
;(defun run-func-1 (v l s) (run-func-2 (set-vals (car l) s) (eval (cadr l)) (define val-table v)))
54+
(defun run-func (l s) (run-func-1 val-table l s))
55+
56+
(defun run-add (s) (+ (eval (car s)) (eval (cadr s))))
57+
(defun run-sub (s) (- (eval (car s)) (eval (cadr s))))
58+
(defun run-mul (s) (* (eval (car s)) (eval (cadr s))))
59+
(defun run-div (s) (/ (eval (car s)) (eval (cadr s))))
60+
(defun run-mod (s) (mod (eval (car s)) (eval (cadr s))))
61+
(defun run-eq (s) (eq (eval (car s)) (eval (cadr s))))
62+
(defun run-car (s) (car (eval (car s))))
63+
(defun run-cdr (s) (cdr (eval (car s))))
64+
(defun run-cons (s) (cons (eval (car s)) (eval (cadr s))))
65+
(defun run-atom (s) (atom (eval (car s))))
66+
(defun run-neg (s) (neg? (eval (car s))))
67+
(defun run-print (s) (print (eval (car s))))
68+
69+
; TEST
70+
71+
;(eval (quote (cons (quote (1 2)) (quote (3 ((5 6)) 4)))))
72+
;(eval (quote (- 3 (+ 3 (if (eq 4 2) (+ 2 (+ 3 2)) (- (+ 4 1) (+ 3 9)))))))
73+
74+
;(define gval-table (table-add gval-table foo hoge))
75+
;(define gval-table (table-add gval-table bar fuga))
76+
;(define gval-table (table-add gval-table foo hige))
77+
;(table-get gval-table foo)
78+
79+
;(eval (quote (defun fizzbuzz (n) (if (eq n 101) nil (if (print (if (eq (mod n 15) 0) FizzBuzz (if (eq (mod n 5) 0) Buzz (if (eq (mod n 3) 0) Fizz n)))) (fizzbuzz (+ n 1)) nil)))))
80+
;(eval (quote (fizzbuzz 1)))
81+
82+
83+
84+
;(eval (quote (* 2 3)))
85+
86+
;(eval (quote (defun f (n) n)))
87+
;(eval (quote (f 42)))
88+
89+
;(eval (quote ((lambda (n) (+ n 4)) 42)))
90+
;(eval (quote (lambda (n) (+ n 4))))
91+
92+
;(eval (quote (define func (lambda (n) (+ n n)))))
93+
;(eval (quote (func 42)))
94+
95+
;(eval (quote (define func (lambda () (print FOO)))))
96+
;(eval (quote (func)))
97+
98+
;(print START)
99+
;(eval (quote (defun mul (n m) (if (eq n 0) 0 (+ m (mul (- n 1) m))))))
100+
;(print DEFINED)
101+
;(eval (quote (print (mul 2 3))))
102+
103+
;(print (run-func-1 1 2 3))
104+
105+
;(eval (quote (print (mul 2 3))))
106+
107+
;(eval (quote (defun mul (n m) (if (eq n 0) 0 (+ m (mul (- n 1) m))))))
108+
;(print START)
109+
;(eval (quote (* 2 3)))
110+
111+
112+
;(define val-table (table-add nil foo hoge))
113+
;(push-vals)
114+
;(print val-stack)
115+
;(pop-vals)
116+
;(print val-stack)
117+
118+
;(eval (quote (define foo 42)))
119+
;(eval (quote foo))
120+
121+
;(eval (quote (defun func (c) 3)))
122+
;(eval (quote (defun func2 (b) (+ (func) b))))
123+
;(eval (quote (defun func2 (b) (+ b (func 99)))))
124+
;(eval (quote (func2 42)))

evalify.rb

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
#!/usr/bin/env ruby
2+
3+
def evalify(c)
4+
o = File.read('eval.l').sub(/; TEST.*/ms, '')
5+
c.lines.each do |line|
6+
line.sub!(/;.*/, '')
7+
next if line =~ /^$/
8+
o += "(eval (quote #{line.chomp}))\n"
9+
end
10+
o
11+
end
12+
13+
if $0 == __FILE__
14+
puts evalify($<.read)
15+
end

fizzbuzz.l

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
(defun fizzbuzz (n) (if (eq n 101) nil (if (print (if (eq (mod n 15) 0) FizzBuzz (if (eq (mod n 5) 0) Buzz (if (eq (mod n 3) 0) Fizz n)))) (fizzbuzz (+ n 1)) nil)))
2+
(fizzbuzz 1)

0 commit comments

Comments
 (0)