source: tags/dso-lex-0.2.1/lex.lisp

Last change on this file was 12, checked in by dsowen, 19 years ago

Fixed: Support different mode for repeatedly lexing tail to avoid
slow-downs from deeply-displaced arrays.

File size: 2.1 KB
Line 
1#|
2Copyright (C) 2007  David Owen <dsowen@fugue88.ws>
3
4This library is free software; you can redistribute it and/or
5modify it under the terms of the GNU Lesser General Public
6License as published by the Free Software Foundation; either
7version 2.1 of the License, or (at your option) any later version.
8
9This library is distributed in the hope that it will be useful,
10but WITHOUT ANY WARRANTY; without even the implied warranty of
11MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12Lesser General Public License for more details.
13
14You should have received a copy of the GNU Lesser General Public
15License along with this library; if not, write to the Free Software
16Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17|#
18
19
20
21(defpackage #:dso-lex
22    (:documentation "Allows the definition of lexers.  See DEFLEXER.")
23  (:use #:cl #:cl-ppcre)
24  (:export #:deflexer))
25
26(in-package #:dso-lex)
27
28
29
30(defun combine (regex-list)
31  (let ((mapped (mapcar
32                 (lambda (regex) `(:register (:regex ,regex)))
33                 regex-list)))
34    (when (rest mapped) (setq mapped `((:alternation ,@mapped))))
35    `(:sequence (:flags :single-line-mode-p) :start-anchor ,@mapped)))
36
37(defmacro deflexer (name &body body)
38  "Defines lexers, called as a function of the given NAME.  The body
39consists of token-class definitions, each being a list of a regular
40expression, the name of the class, and an optional filter.
41
42Currently, matching is done using *only* priority (first match wins),
43and does not look for the longest match."
44  (let ((regex (combine (mapcar #'first body)))
45        (classes (map 'vector #'second body))
46        (filters (map 'vector #'third body)))
47    `(defun ,name (input &optional (start 0))
48      (let ((parts (nth-value 3 (scan (quote ,regex) input :start start))))
49        (let ((idx (position-if #'identity parts)))
50          (when idx
51            (let ((end (aref parts idx)))
52              (let ((image (make-array (- end start)
53                                       :element-type 'character
54                                       :displaced-to input
55                                       :displaced-index-offset start))
56                    (filter (aref ,filters idx)))
57                (values (aref ,classes idx)
58                        (if filter (funcall filter image) image)
59                        end)))))))))
Note: See TracBrowser for help on using the repository browser.