Changeset 16 for trunk/lex.lisp
- Timestamp:
- 12/01/2007 10:52:59 PM (19 years ago)
- File:
-
- 1 edited
-
trunk/lex.lisp (modified) (2 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/lex.lisp
r12 r16 22 22 (:documentation "Allows the definition of lexers. See DEFLEXER.") 23 23 (:use #:cl #:cl-ppcre) 24 (:export #:deflexer ))24 (:export #:deflexer #:make-lexer)) 25 25 26 26 (in-package #:dso-lex) … … 35 35 `(:sequence (:flags :single-line-mode-p) :start-anchor ,@mapped))) 36 36 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 59 definitions, each being a list of a regular expression, the name of 60 the class, and an optional filter. The returned function takes as 61 arguments an input sequence and an optional start position. 62 63 Currently, matching is done using *only* priority (first match wins), 64 and does not look for the longest match. 65 66 Example: 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 39 76 consists of token-class definitions, each being a list of a regular 40 77 expression, the name of the class, and an optional filter. 41 78 42 79 Currently, 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))))))))) 80 and does not look for the longest match. 81 82 Example: 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.
