Changeset trunk,16 for trunk


Ignore:
Timestamp:
06/23/2007 06:11:55 AM (19 years ago)
Author:
dsowen
revision id:
svn-v3-trunk0:2948df59-2b31-0410-8e06-c40c0b09d5b6:trunk:16
Message:

Rearranging around the new macros.

Location:
trunk
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/package.lisp

    r15 r16  
    1 (defpackage #:parse
     1(defpackage #:dso-parse
    22  (:documentation
    33   "Defines macros for matching input against rules and building trees
  • trunk/parse.lisp

    r3 r16  
    1 (defpackage #:parse
    2   (:use #:cl #:cl-ppcre)
    3   (:export #:defgrammar
    4            #:token))
    5 
    6 (in-package #:parse)
    7 
    8 
    9 
    10 (defstruct token
    11   class
    12   string)
    13 
    14 ;;;; A parser returns, as a list, all parts matched; and, the
    15 ;;;; remainder of the token-list.  Named parts appear as sub-trees.
    16 
    17 
    18 
    19 (defmacro with-gensyms (syms &body body)
    20   `(let (,@(mapcar (lambda (sym) `(,sym (gensym ,(symbol-name sym)))) syms))
    21     ,@body))
    22 
    23 (defun substring (string &key (start 0) end length)
    24   (when (and end length) (error "Specify only one of END or LENGTH."))
    25   (when end (setf length (- end start)))
    26   (unless length (setf length (- (length string) start)))
    27   (make-array length
    28               :element-type 'character
    29               :displaced-to string
    30               :displaced-index-offset start))
    31 
    32 (defmacro scase (sym &body clauses)
    33   (with-gensyms (sym-name)
    34     `(let ((,sym-name (symbol-name ,sym)))
    35       (cond
    36         ,@(mapcar #'(lambda (clause)
    37                       (if (eq t (first clause))
    38                           clause
    39                           (let ((clause-sym-name (symbol-name (first clause)))
    40                                 (clause-body (rest clause)))
    41                             `((string= ,sym-name ,clause-sym-name)
    42                               ,@clause-body))))
    43                   clauses)))))
    44 
    45 (defmacro specials ((&body decls) &body body)
    46   "Like LET, but declares the bound variables to be special."
    47   `(let ,decls
    48     (declare (special ,@(mapcar #'first decls)))
    49     ,@body))
    50 
    51 (defun as-list (item) (if (listp item) item (list item)))
    52 
    53 
    54 
    55 
    56 
    57 ;; This is the entry-point for now.
    58 
    59 (defun make-parser (rule)
    60   (declare (ignore rule))
    61   nil)
    62 
    63 
    64 
    65 (defun parse-sequence (rule-parsers token-list tree)
    66   (if rule-parsers
    67       (multiple-value-bind (matched rlist mtree)
    68           (funcall (first rule-parsers) token-list)
    69         (when matched
    70           (parse-sequence (rest rule-parsers) rlist (append tree mtree))))
    71       (values t token-list tree)))
    72 
    73 (defun parse-choice (rule-parsers token-list)
    74   (if rule-parsers
    75       (multiple-value-bind (matched rlist mtree)
    76           (funcall (first rule-parsers) token-list)
    77         (if matched
    78             (values t rlist mtree)
    79             (parse-choice (rest rule-parsers) token-list)))
    80       nil))
    81 
    82 (defun parse-anycount (rule-parser token-list tree)
    83   (multiple-value-bind (matched rlist mtree) (funcall rule-parser token-list)
    84     (if matched
    85         (parse-anycount rule-parser rlist (append tree mtree))
    86         (values t token-list tree))))
    87 
    88 (defun parse-eqcount (count rule-parser token-list tree)
    89   (if (> count 0)
    90       (multiple-value-bind (matched rlist mtree)
    91           (funcall rule-parser token-list)
    92         (when matched
    93           (parse-eqcount (1- count) rule-parser rlist (append tree mtree))))
    94       (values t token-list tree)))
    95 
    96 (defun parse-mincount (count rule-parser token-list tree)
    97   (if (> count 0)
    98       (multiple-value-bind (matched rlist mtree)
    99           (funcall rule-parser token-list)
    100         (when matched
    101           (parse-mincount (1- count) rule-parser rlist (append tree mtree))))
    102       (parse-anycount rule-parser token-list tree)))
    103 
    104 (defun parse-maxcount (count rule-parser token-list tree)
    105   (if (> count 0)
    106       (multiple-value-bind (matched rlist mtree)
    107           (funcall rule-parser token-list)
    108         (if matched
    109             (parse-maxcount (1- count) rule-parser rlist (append tree mtree))
    110             (values t token-list tree)))
    111       (values t token-list tree)))
    112 
    113 
    114 
    115 ;; This needs to be changed to just use the function of the given
    116 ;; symbol-name, so that any format of sequence may be supported.
    117 (defun make-token-parser (token-class)
    118   (declare (special definition-names
    119                     *import*))
    120   (unless (or (member token-class definition-names)
    121               (member token-class *import*))
    122     (warn "Parser ~A is neither defined nor imported." token-class))
    123   (if (member token-class definition-names)
    124       `(function ,token-class)
    125       (with-gensyms (token-list token)
    126         `(lambda (,token-list)
    127           (let ((,token (first ,token-list)))
    128             (when (and ,token-list (eq (token-class ,token) ',token-class))
    129               (values t (rest ,token-list) (list ,token))))))))
    130 
    131 (defun make-character-parser (ch)
    132   (with-gensyms (str)
    133     `(lambda (,str)
    134       (when (and (> (length ,str) 0) (char= (char ,str 0) ,ch))
    135         (values
    136          t
    137          (substring ,str :start 1)
    138          (list ,ch))))))
    139 
    140 (defun make-regex-parser (regex)
    141   (declare (special *regex-flags*))
    142   (let ((regex `(:sequence (:flags ,@*regex-flags*) :start-anchor
    143                  (:register (:regex ,regex)))))
    144     (with-gensyms (str start end)
    145       `(lambda (,str)
    146         (multiple-value-bind (,start ,end) (scan (quote ,regex) ,str)
    147           (when ,start
    148             (values
    149              t
    150              (substring ,str :start ,end)
    151              (list (substring ,str :end ,end)))))))))
    152 
    153 
    154 (defun make-sequence-parser (rules)
    155   (with-gensyms (rule-parsers token-list)
    156     `(let ((,rule-parsers (list ,@(mapcar #'make-parser rules))))
    157       (lambda (,token-list) (parse-sequence ,rule-parsers ,token-list nil)))))
    158 
    159 (defun make-choice-parser (rules)
    160   (with-gensyms (rule-parsers token-list)
    161     `(let ((,rule-parsers (list ,@(mapcar #'make-parser rules))))
    162       (lambda (,token-list) (parse-choice ,rule-parsers ,token-list)))))
    163 
    164 (defun make-anycount-parser (rule)
    165   (with-gensyms (rule-parser token-list)
    166     `(let ((,rule-parser ,(make-parser rule)))
    167       (lambda (,token-list) (parse-anycount ,rule-parser ,token-list nil)))))
    168 
    169 (defun make-eqcount-parser (count rule)
    170   (with-gensyms (rule-parser token-list)
    171     `(let ((,rule-parser ,(make-parser rule)))
    172       (lambda (,token-list)
    173         (parse-eqcount ,count ,rule-parser ,token-list nil)))))
    174 
    175 (defun make-maxcount-parser (count rule)
    176   (with-gensyms (rule-parser token-list)
    177     `(let ((,rule-parser ,(make-parser rule)))
    178       (lambda (,token-list)
    179         (parse-maxcount ,count ,rule-parser ,token-list nil)))))
    180 
    181 (defun make-0or1-parser (rule) (make-maxcount-parser 1 rule))
    182 
    183 (defun make-+-parser (rule)
    184   (with-gensyms (rule-parser token-list)
    185     `(let ((,rule-parser ,(make-parser rule)))
    186       (lambda (,token-list)
    187         (parse-mincount 1 ,rule-parser ,token-list nil)))))
    188 
    189 (defun make-required-pred (rule)
    190   (with-gensyms (rule-parser token-list)
    191     `(let ((,rule-parser ,(make-parser rule)))
    192       (lambda (,token-list)
    193         (when (funcall ,rule-parser ,token-list)
    194           (values t ,token-list nil))))))
    195 
    196 (defun make-forbidden-pred (rule)
    197   (with-gensyms (rule-parser token-list)
    198     `(let ((,rule-parser ,(make-parser rule)))
    199       (lambda (,token-list)
    200         (unless (funcall ,rule-parser ,token-list)
    201           (values t ,token-list nil))))))
    202 
    203 (defun make-match-parser (rule)
    204   (with-gensyms (rule-parser token-list matched rlist)
    205     `(let ((,rule-parser ,(make-parser rule)))
    206       (lambda (,token-list)
    207         (multiple-value-bind (,matched ,rlist)
    208             (funcall ,rule-parser ,token-list)
    209           (when ,matched (values t ,rlist nil)))))))
    210 
    211 (defmacro dispatch (sym fun)
    212   `(progn
    213     (when (cddr rule) (error ,(format nil "~A takes one argument" sym)))
    214     (,fun (second rule))))
    215 
    216 (setf (symbol-function 'make-parser) (lambda (rule)
    217   (etypecase rule
    218     (symbol (make-token-parser rule))
    219     (character (make-character-parser rule))
    220     (string (make-regex-parser rule))
    221     (list
    222      (if (symbolp (first rule))
    223          (scase (first rule)
    224            (& (dispatch & make-required-pred))
    225            (! (dispatch ! make-forbidden-pred))
    226            (* (dispatch * make-anycount-parser))
    227            (? (dispatch ? make-0or1-parser))
    228            (+ (dispatch + make-+-parser))
    229            (= (make-match-parser (cdr rule)))
    230            (/ (make-choice-parser (cdr rule)))
    231            (t (make-sequence-parser rule)))
    232          (make-sequence-parser rule))))))
    233 
    234 
    235 
    236 
    2371(defun hash-names (names &optional (map (make-hash-table)))
    2382  (if names
Note: See TracChangeset for help on using the changeset viewer.