Skip to content

Commit e9401bb

Browse files
authored
Merge pull request #31 from ryukinix/pratt-parser
feat: add pratt parser
2 parents 41b0a2b + b540fd8 commit e9401bb

File tree

9 files changed

+134
-30
lines changed

9 files changed

+134
-30
lines changed

.github/workflows/deploy.yml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
2+
name: Deploy
3+
4+
on:
5+
push:
6+
branches:
7+
- master
8+
9+
jobs:
10+
build:
11+
runs-on: ubuntu-latest
12+
steps:
13+
- uses: actions/checkout@v2
14+
- name: Run docker publish
15+
run: make docker-publish

.github/workflows/main.yml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
2+
name: CI
3+
4+
on: [pull_request]
5+
6+
jobs:
7+
build:
8+
runs-on: ubuntu-latest
9+
steps:
10+
- uses: actions/checkout@v2
11+
- name: Run docker check
12+
run: make docker-check

Makefile

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
SBCL_CMD := sbcl --noinform --disable-debugger --load
22
OBJECTS := lisp-inference
33
DOCKER_IMG = lisp-inference
4-
PUBLIC_IMG = ryukinix/$(DOCKER_IMG)
4+
VERSION := latest
5+
PUBLIC_IMG = ryukinix/$(DOCKER_IMG):$(VERSION)
56

67
all: $(OBJECTS)
78

@@ -20,14 +21,14 @@ server:
2021
docker-build:
2122
docker build -t $(DOCKER_IMG) .
2223

23-
docker-run:
24+
docker-run: docker-build
2425
docker run --rm -it --network=host $(DOCKER_IMG)
2526

26-
docker-check:
27+
docker-check: docker-build
2728
docker run --rm -t --entrypoint=ros $(DOCKER_IMG) run -s lisp-inference/test -l run-test.lisp
2829

29-
docker-publish:
30+
docker-publish: docker-build
3031
docker tag $(DOCKER_IMG) $(PUBLIC_IMG)
3132
docker push $(PUBLIC_IMG)
3233

33-
.PHONY: check
34+
.PHONY: check docker-build

fix-quicklisp.lisp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,10 @@
11
(eval-when (:load-toplevel :execute)
22
(pushnew (truename (sb-unix:posix-getcwd/)) ql:*local-project-directories* )
3-
(ql:register-local-projects))
3+
(ql:register-local-projects)
4+
5+
;; install ultralisp if necessary
6+
(unless (member "ultralisp" (ql-dist:all-dists)
7+
:key 'ql-dist:name
8+
:test 'string=)
9+
(ql-dist:install-dist "http://dist.ultralisp.org/"
10+
:prompt nil)))

lisp-inference.asd

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,13 @@
1414
:components ((:file "package")
1515
(:file "operators")
1616
(:file "parser")
17+
(:file "pratt")
1718
(:file "equivalences"
1819
:depends-on ("parser" "operators"))
1920
(:file "inferences"
2021
:depends-on ("parser" "operators"))
2122
(:file "truth-table"
22-
:depends-on ("parser" "operators" "equivalences"))))
23+
:depends-on ("pratt" "parser" "operators" "equivalences"))))
2324

2425
(asdf:defsystem #:lisp-inference/web
2526
:description "An web interface for Lisp Inference Truth Table"
@@ -30,6 +31,7 @@
3031
:depends-on (:lisp-inference
3132
:weblocks
3233
:weblocks-ui
34+
:clack-handler-hunchentoot
3335
:find-port
3436
:str)
3537
:pathname "web"

src/package.lisp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#:simplification-first
1616
#:simplification-second
1717
#:syllogism-hypothetical
18+
#:parse-logic ;; pratt
1819
#:absorption ;; parser
1920
#:propositionp
2021
#:operationp

src/pratt.lisp

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
(in-package :lisp-inference)
2+
3+
(defparameter *binding-precedence*
4+
'(
5+
("^" . 80)
6+
("v" . 70)
7+
("[+]" . 60)
8+
("=>" . 50)
9+
("->" . 50)
10+
("<=>" . 40)
11+
("<->" . 40)))
12+
13+
(defvar *tokens* nil)
14+
(defvar *pos* 0)
15+
16+
17+
(defun read-token (stream)
18+
(cond
19+
((peek-char nil stream nil nil)
20+
(let ((c (peek-char nil stream)))
21+
(cond
22+
((find c "()") (list (string (read-char stream))))
23+
((char= c #\~) (list (string (read-char stream))))
24+
((member c '(#\Space #\Tab #\Newline)) (read-char stream) (read-token stream))
25+
((alpha-char-p c)
26+
(let ((sym (read stream)))
27+
(list (string-downcase (string sym)))))
28+
(t
29+
(let ((token (with-output-to-string (out)
30+
(loop for ch = (peek-char nil stream nil nil)
31+
while (and ch (find ch "<=>-[+]"))
32+
do (write-char (read-char stream) out)))))
33+
(if (string= token "") (list (string (read-char stream))) (list token)))))))))
34+
35+
(defun tokenize (input)
36+
(with-input-from-string (in input)
37+
(loop for token = (read-token in)
38+
while token
39+
append token)))
40+
41+
(defun next-token ()
42+
(nth *pos* *tokens*))
43+
44+
(defun advance ()
45+
(prog1 (next-token) (incf *pos*)))
46+
47+
(defun match (tok)
48+
(when (equal (next-token) tok) (advance) t))
49+
50+
(defun get-binding (tok)
51+
(or (cdr (assoc tok *binding-precedence* :test #'string=)) 0))
52+
53+
(defun nud (token)
54+
(cond
55+
((string= token "~") `(~ ,(parse-expression 90)))
56+
((string= token "(")
57+
(prog1 (parse-expression) (match ")")))
58+
(t (intern (string-upcase token)))))
59+
60+
(defun led (token left)
61+
(let ((right (parse-expression
62+
(if (member token '("=>" "<=>") :test #'string=)
63+
(1- (get-binding token)) ;; Right-associative
64+
(get-binding token)))))
65+
(list (intern (string-upcase token)) left right)))
66+
67+
(defun parse-expression (&optional (rbp 0))
68+
(let* ((token (advance))
69+
(left (nud token)))
70+
(loop while (and (next-token) (< rbp (get-binding (next-token))))
71+
do (setf left (led (advance) left)))
72+
left))
73+
74+
;; entrypoint
75+
(defun parse-logic (input)
76+
(setf *tokens* (tokenize input)
77+
*pos* 0)
78+
(parse-expression))

src/truth-table.lisp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,7 @@ a tautology."
203203
"A easy way to generate a truth table"
204204
`(print-truth-table (quote ,exp)))
205205

206+
;; TODO: implement a pratt parser
206207
(defmacro truth-infix (exp)
207208
"A easy and infix way of EXP generate a truth table.
208209
Ex.: (truth-infix (p ^ q)) "
@@ -212,9 +213,9 @@ a tautology."
212213
(defun main ()
213214
(format t "Example of usage: (p ^ q)~%Operators: ~a ~%" *valid-operators*)
214215
(let ((*output-stream* *standard-output*))
215-
(handler-case (loop do (princ-n "TRUTH-TABLE> ")
216+
(handler-case (loop do (princ-n "TRUTH-TABLE> ")
216217
do (force-output *output-stream*)
217-
do (print-truth-table (infix-to-prefix (read))))
218+
do (print-truth-table (parse-logic (read-line))))
218219
(end-of-file () )
219220
#+sbcl (sb-sys:interactive-interrupt () nil))
220221

web/webapp.lisp

Lines changed: 8 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,7 @@
2222
(defvar *proposition* "P => Q" "Default proposition")
2323
(defvar *port* (find-port:find-port))
2424
(defvar *notes*
25-
'("My lexer doesn't work very well with parenthesis."
26-
"Please, don't be evil. Use less than 10 variables."
25+
'("Please, don't be evil. Use less than 10 variables."
2726
"Yes, [+] it's a XOR. Mathematically: p ⊕ q."
2827
"(=> ->) and (<=> <->) are aliases."))
2928

@@ -40,35 +39,23 @@
4039
:initform nil
4140
:accessor truth)))
4241

43-
(defun parse-string (string)
44-
"Translate string to a list expression"
45-
(if (and (str:starts-with-p "(" string)
46-
(str:ends-with-p ")" string))
47-
(read-from-string string)
48-
(read-from-string (str:concat "(" string ")"))))
49-
5042
(defun truth-table (exp)
5143
(with-output-to-string (s)
5244
(let ((inference:*output-stream* s))
53-
(inference:print-truth-table (inference:infix-to-prefix exp)))))
45+
(inference:print-truth-table (inference:parse-logic exp)))))
5446

55-
(defun create-table (exp)
47+
(defun create-table (exp-string)
5648
(make-instance 'table
57-
:prop (format nil "~a" exp)
58-
:truth (truth-table exp)))
49+
:prop exp-string
50+
:truth (truth-table exp-string)))
5951

6052
(defgeneric update-table (table exp))
6153

62-
(defmethod update-table (table (exp list))
63-
(setf (prop table) (format nil "~a" exp))
54+
(defmethod update-table (table (exp string))
55+
(setf (prop table) exp)
6456
(setf (truth table) (truth-table exp))
6557
(update table))
6658

67-
(defmethod update-table (table (exp string))
68-
(update-table
69-
table
70-
(parse-string exp)))
71-
7259
(defmethod render ((table table))
7360
(with-html
7461
(:h1 :align "center" "Lisp Inference Truth Table System")
@@ -100,7 +87,7 @@
10087

10188
(defmethod weblocks/session:init ((app truth-table))
10289
(declare (ignorable app))
103-
(create-table (parse-string *proposition*)))
90+
(create-table *proposition*))
10491

10592
(defun start (&optional (port *port*))
10693
(weblocks/debug:on)

0 commit comments

Comments
 (0)