diff options
-rw-r--r-- | input.lisp | 15 | ||||
-rw-r--r-- | parser.lisp | 26 |
2 files changed, 32 insertions, 9 deletions
@@ -5,17 +5,22 @@ (file nil :read-only t) (data nil :read-only t)) -(defun has-data? (input) - (< (input-cursor input) +(defun has-data? (input &optional (window-size 1)) + (< (+ window-size -1 (input-cursor input)) (length (input-data input)))) -(defun element (input) +(defun peek-1 (input) (char (input-data input) (input-cursor input))) -(defun advance (input) +(defun peek-n (input window-size) + (subseq (input-data input) + (input-cursor input) + window-size)) + +(defun advance (input &optional (amount 1)) (let ((new-input (copy-structure input))) - (incf (input-cursor new-input)) + (incf (input-cursor new-input) amount) new-input)) (declaim (ftype (function (simple-string) (values input &optional)) from-string)) diff --git a/parser.lisp b/parser.lisp index 04d3f2b..a1ef1a8 100644 --- a/parser.lisp +++ b/parser.lisp @@ -33,7 +33,7 @@ (lambda (input) (make-critical-failure :place input :message message))) -(defun either (first-parser &rest other-parsers) +(defun either (first-parser second-parser &rest other-parsers) (lambda (input) (labels ((either-rec (body) (if (cdr body) @@ -42,17 +42,26 @@ (either-rec (cdr body)) r)) (funcall (car body) input)))) - (either-rec (cons first-parser other-parsers))))) + (either-rec (cons first-parser (cons second-parser other-parsers)))))) (defun unit (&optional (predicate #'characterp)) (lambda (input) (if (input::has-data? input) - (let ((c (input::element input))) + (let ((c (input::peek-1 input))) (if (funcall predicate c) (make-parsing :tree c :left (input::advance input)) (make-normal-failure :place input :message "Predicate not satisfied."))) (make-normal-failure :place input :message "Reached end of input.")))) +(defun literal (predicate) + (lambda (input) + (if (input::has-data? input (length predicate)) + (let ((str (input::peek-n input (length predicate)))) + (if (string= predicate str) + (make-parsing :tree str :left (input::advance input (length predicate))) + (make-normal-failure :place input :message "Predicate not satisfied."))) + (make-normal-failure :place input :message "Reached end of input.")))) + (defmacro comp (bindings &body body) (if (null bindings) `(new (progn ,@body)) @@ -65,7 +74,7 @@ (defparameter nothing (new nil)) -(defun zero-or-one (p) +(defun optional (p) (either p nothing)) (defun zero-or-more (p) @@ -78,3 +87,12 @@ (comp ((x p) (xs (zero-or-more p))) (cons x xs))) + +(defun separated-list (p separator) + (comp ((v p) + (sep (optional (the-char separator))) + (vn (if sep + (either (separated-list p separator) + (fail "Value expected.")) + nothing))) + (cons v vn))) |