1
;;; Example file for cl-yacc-ebnf.
2
;;;
3
;;; (c) 2009 Mikhail Novikov, Plato Wu
4
;;;
5
;;; This file is part of cl-yacc-ebnf.
6
;;;
7
;;; Permission is hereby granted, free of charge, to any person obtaining a copy
8
;;; of this software and associated documentation files (the "Software"), to deal
9
;;; in the Software without restriction, including without limitation the rights
10
;;; to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
11
;;; copies of the Software, and to permit persons to whom the Software is
12
;;; furnished to do so, subject to the following conditions:
13
;;;
14
;;; The above copyright notice and this permission notice shall be included in
15
;;; all copies or substantial portions of the Software.
16
;;;
17
;;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
18
;;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
19
;;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL THE
20
;;; AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
21
;;; LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
22
;;; OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
23
;;; THE SOFTWARE.
24
25
(defpackage #:yacc-ebnf-example
26
  (:export #:ebnf-example)
27
  (:use #:cl #:yacc #:yacc-ebnf))
28
29
(in-package #:yacc-ebnf-example)
30
31
;;; The lexer
32
33
(define-condition lexer-error (yacc-runtime-error)
34
  ((character :initarg :character :reader lexer-error-character))
35
  (:report (lambda (e stream)
36
             (format stream "Lexing failed~@[: unexpected character ~S~]"
37
                     (lexer-error-character e)))))
38
39
(defun lexer-error (char)
40
  (error (make-condition 'lexer-error :character char)))
41
42
(defun lexer (&optional (stream *standard-input*))
43
  (loop
44
     (let ((c (read-char stream nil nil)))
45
       (cond
46
         ((member c '(nil #\Newline)) (return-from lexer (values nil nil)))
47
         ((member c '(#\- #\.))
48
          (let ((symbol (intern (string c) '#.*package*)))
49
            (return-from lexer (values symbol symbol))))
50
         ((digit-char-p c)
51
          (return-from lexer (values 'digit c)))
52
         (t
53
          (lexer-error c))))))
54
55
;;; The parser
56
57
(define-ebnf-parser *expression-ebnf-parser*
58
  (:start-symbol S)
59
  (:terminals (|.| - digit))
60
  (:precedence nil)
61
  (S ((:option -) (:plus D) (:option |.| (:plus D))) ())
62
  (D digit))
63
64
;;; The toplevel loop
65
66
(defun ebnf-example ()
67
  (format t "A EBNF example:
68
             S := '-'? D+ ('.' D+)?
69
             D := '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9'~%")
70
  (loop
71
     (with-simple-restart (abort "Return to ebnf-example toplevel.")
72
       (format t "? ")
73
       (let ((e (parse-with-lexer #'lexer *expression-ebnf-parser*)))
74
         (when (null e)
75
           (return-from ebnf-example))
76
         (format t " => ~A~%" (print e))))))