;;; -*- Mode:LISP; Package:USER; Base:10; Readtable:CL -*- (defun re-parse (pat) (let ((result nil) (p 0) (pend (string-length pat)) last-start zero-times-ok many-times-ok c ) (labels ((pat-fetch () (when (= p pend) (ferror nil "end of pattern")) (setq c (char pat p)) (incf p) c) (pat-unfetch () (decf p)) (pat-push (item) (cond ((null result) (setq result (cons item nil))) (t (setf (cdr (last result)) (cons item nil))))) (pat-insert (place item) (let ((new-cell (cons nil nil))) (setf (cdr new-cell) (cdr place)) (setf (cdr place) new-cell) (setf (car new-cell) (car place)) (setf (car place) item))) (normal-char () (let ((l (last result))) (cond ((and (consp (car l)) (eq (caar l) :exact) (or (= p pend) (not (memq (char pat p) '(#\* #\^ #\+ #\?))))) (setf (cadar l) (string-append (cadar l) c))) (t (pat-push (list :exact (string c))) (setq last-start (last result)))))) ) (do-forever (cond ((= p pend) (dolist (x result) (when (and (consp x) (memq (car x) '(:on-failure-jump :dummy-failure-jump))) (when (null (cdr (cdr x))) (ferror nil "on-failure-jump to end of pattern")) (setf (cdr x) (cdr (cdr x))))) (return result)) (t (case (pat-fetch) (#\$ (cond ((or (eq p pend) (and (eq (char pat p) #\\) (memq (char pat (1+ p)) '(#\) #\|)))) (pat-push :endline)) (t (normal-char)))) (#\^ (cond ((null last-start) (pat-push :begline)) (t (normal-char)))) ((#\* #\+ #\?) (setq zero-times-ok nil) (setq many-times-ok nil) (do-forever (if (not (eq c #\+)) (setq zero-times-ok t)) (if (not (eq c #\?)) (setq many-times-ok t)) (pat-fetch) (when (not (memq c '(#\* #\+ #\?))) (pat-unfetch) (return nil))) (when many-times-ok (pat-push (cons :maybe-finalize-jump last-start))) (pat-insert last-start (cons :on-failure-jump (last result))) (when (not zero-times-ok) (pat-insert last-start (cons :dummy-failure-jump (last result))))) (#\. (pat-push :anychar) (setq last-start (last result))) (t (normal-char))))))))) (defun re-exec (pat string) (let ((p pat) op exp (d 0) (dend (string-length string)) fstack ) (labels ((next () (setq exp (car p)) (cond ((consp exp) (setq op (car exp))) (t (setq op exp))) (setq p (cdr p)) op) (dnext () (cond ((= d dend) (fail)) (t (prog1 (char string d) (incf d))))) (fail () (cond ((null fstack) (return-from re-exec nil)) (t (let ((x (pop fstack))) (setq p (car x)) (setq d (cadr x))) :fail))) ) (do-forever (cond ((null p) (return d)) (t (ecase (next) (:anychar (let ((c (dnext))) (cond ((eq c :fail)) ((eq c #\return) (fail)) (t nil)))) (:begline (when (and (not (= d 0)) (not (= (char string (1- d)) #\return))) (fail))) (:endline (when (and (not (= d dend)) (not (= (char string d) #\return))) (fail))) (:on-failure-jump (push (list (cdr exp) d) fstack)) (:maybe-finalize-jump (setq p (cdr exp))) (:exact (let ((ex (cadr exp))) (cond ((< (- dend d) (string-length ex)) (fail)) (t (dotimes (i (string-length ex) (incf d (string-length ex))) (when (not (eq (char string (+ d i)) (char ex i))) (return (fail)))))))) )))))))