Index: trunk/parsing.lisp
===================================================================
--- trunk/parsing.lisp	(revision trunk,17)
+++ trunk/parsing.lisp	(revision trunk,17)
@@ -0,0 +1,21 @@
+(in-package '#:dso-parse)
+
+
+
+(defmacro defparser (name rule &optional filter)
+  "Defines a function named NAME that parses its input according to
+RULE (see IF-MATCHES).  On success, returns the values T, the
+unconsumed input, and the tree (labeled with NAME).  On failure ,
+returns NIL.
+
+The tree may optionally be filtered by FILTER before being labeled."
+  `(defun ,name (input)
+    (if-matches input ,rule (next match)
+     (values t next (list ',name ,(if filter `(,filter match) 'match))))))
+
+(defmacro defgrammar (() &body definitions)
+  "Defines a grammar, being a collection of parsers."
+  (flet ((x (definition)
+	   (destructuring-bind (name rule &optional filter) definition
+	     `(defparser ,name ,rule ,filter))))
+    `(progv () ,@(mapcar #'x definitions))))
Index: trunk/util.lisp
===================================================================
--- trunk/util.lisp	(revision trunk,17)
+++ trunk/util.lisp	(revision trunk,17)
@@ -0,0 +1,16 @@
+(in-package '#:dso-parse)
+
+
+
+(defmacro with-gensyms (syms &body body)
+  `(let (,@(mapcar (lambda (sym) `(,sym (gensym ,(symbol-name sym)))) syms))
+    ,@body))
+
+(defun substring (string &key (start 0) end length)
+  (when (and end length) (error "Specify only one of END or LENGTH."))
+  (when end (setf length (- end start)))
+  (unless length (setf length (- (length string) start)))
+  (make-array length
+	      :element-type 'character
+	      :displaced-to string
+	      :displaced-index-offset start))
