Changeset 16 for trunk/lex.lisp


Ignore:
Timestamp:
12/01/2007 10:52:59 PM (19 years ago)
Author:
dsowen
Message:

Additional interface to create lexers.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/lex.lisp

    r12 r16  
    2222    (:documentation "Allows the definition of lexers.  See DEFLEXER.")
    2323  (:use #:cl #:cl-ppcre)
    24   (:export #:deflexer))
     24  (:export #:deflexer #:make-lexer))
    2525
    2626(in-package #:dso-lex)
     
    3535    `(:sequence (:flags :single-line-mode-p) :start-anchor ,@mapped)))
    3636
    37 (defmacro deflexer (name &body body)
    38   "Defines lexers, called as a function of the given NAME.  The body
     37(defun lexer-form (input-var start-var defs)
     38  (let ((regex (combine (mapcar #'first defs)))
     39        (classes (map 'vector #'second defs))
     40        (filters (map 'vector #'third defs)))
     41    `(let ((parts (nth-value 3 (scan (quote ,regex) ,input-var
     42                                     :start ,start-var))))
     43       (let ((idx (position-if #'identity parts)))
     44         (when idx
     45           (let ((end (aref parts idx)))
     46             (let ((image (make-array (- end ,start-var)
     47                                      :element-type 'character
     48                                      :displaced-to ,input-var
     49                                      :displaced-index-offset ,start-var))
     50                   (filter (aref ,filters idx)))
     51               (values (aref ,classes idx)
     52                       (if filter (funcall filter image) image)
     53                       end))))))))
     54
     55
     56
     57(defun make-lexer (defs)
     58  "Returns a lexer function.  The DEFS consists of token-class
     59definitions, each being a list of a regular expression, the name of
     60the class, and an optional filter.  The returned function takes as
     61arguments an input sequence and an optional start position.
     62
     63Currently, matching is done using *only* priority (first match wins),
     64and does not look for the longest match.
     65
     66Example:
     67
     68(let ((lexer (make-lexer '((\"[0-9]+\" number parse-integer)
     69                           (\"[a-zA-Z]\" letter)))))
     70  (funcall lexer \"2pi\" 1))"
     71  (eval `(lambda (input &optional (start 0))
     72           ,(lexer-form 'input 'start defs))))
     73
     74(defmacro deflexer (name &body defs)
     75  "Defines a lexer, called as a function of the given NAME.  The body
    3976consists of token-class definitions, each being a list of a regular
    4077expression, the name of the class, and an optional filter.
    4178
    4279Currently, matching is done using *only* priority (first match wins),
    43 and 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)))))))))
     80and does not look for the longest match.
     81
     82Example:
     83
     84(deflexer lexer
     85  (\"[0-9]+\" number parse-integer)
     86  (\"[a-zA-Z]\" letter))
     87
     88(lexer \"2pi\" 1)"
     89  `(defun ,name (input &optional (start 0))
     90     ,(lexer-form 'input 'start defs)))
Note: See TracChangeset for help on using the changeset viewer.