protocol. The final output of the `expr' parse is the result of
evaluating the parsed expression. (Of course, the definition of
`evaluation' here is determined entirely by the methods on
- `apply-operator', so the final value may be a parse tree, for example.)"
+ `apply-operator', so the final value may be a parse tree, for example.)
+
+ Alternatively, the BINOP, PREOP, and POSTOP parsers may be /lists/ of
+ parsers (distinguished because the head of a parser form is expected to be
+ an atom). These are implicitly `or'red together. Within such a list, a
+ parser form beginning `:op' is given special interpretation. The syntax
+ is expected to be
+
+ (:op MAKE-OP RECOG &rest ARGS)
+
+ which has the following effects:
+
+ * around the expression parser, the expression
+
+ (MAKE-OP . ARGS)
+
+ is evaluated once and the result stashed away; and
+
+ * a parser of the form
+
+ (seq (RECOG) OP)
+
+ is added as one of the alternatives of the disjunction, where OP is the
+ cached operator built in the first step."
(flet ((wrap (parser)
`(parser (,nestedp)
(declare (ignorable ,nestedp))
- ,parser)))
- `(parse-expression ,(wrap operand)
- ,(wrap binop)
- ,(wrap preop)
- ,(wrap postop))))
+ ,parser))
+ (hack-oplist (oplist)
+ (if (or (atom oplist) (atom (car oplist))) (values nil oplist)
+ (let ((binds nil) (ops nil))
+ (dolist (op oplist)
+ (if (and (consp op) (eq (car op) :op))
+ (destructuring-bind
+ (recog make-op &rest args) (cdr op)
+ (with-gensyms (var)
+ (push `(,var (,make-op ,@args)) binds)
+ (push `(seq ((nil ,recog)) ,var) ops)))
+ (push op ops)))
+ (values (nreverse binds) `(or ,@(nreverse ops)))))))
+ (multiple-value-bind (binvars binops) (hack-oplist binop)
+ (multiple-value-bind (prevars preops) (hack-oplist preop)
+ (multiple-value-bind (postvars postops) (hack-oplist postop)
+ `(let (,@binvars ,@prevars ,@postvars)
+ (parse-expression ,(wrap operand)
+ ,(wrap binops)
+ ,(wrap preops)
+ ,(wrap postops))))))))
;;;--------------------------------------------------------------------------
;;; Numerical precedence.
name
(mapcar #'car args))
(cons :invalid nil)))))
- (let ((add (binop "+" (x y 5)
- (dispatch "+" (list x y) (list :int #'+ :int :int))))
- (sub (binop "-" (x y 5)
- (dispatch "-" (list x y) (list :int #'- :int :int))))
- (mul (binop "*" (x y 7)
- (dispatch "*" (list x y) (list :int #'* :int :int))))
- (div (binop "/" (x y 7)
- (dispatch "/" (list x y)
- (list :int
- (lambda (x y)
- (cond ((zerop y)
- (cerror*
- "Division by zero")
- (cons :invalid nil))
- (t
- (floor x y))))
- :int :int))))
- (nop (preop "+" (x 9)
- (dispatch "+" (list x) (list :int #'+ :int))))
- (neg (preop "-" (x 9)
- (dispatch "-" (list x) (list :int #'- :int))))
- (lp (lparen #\)))
- (rp (rparen #\))))
-
- (defun parse-expression (scanner)
- "Parse and evaluate a simple expression.
+
+ (defun parse-expression (scanner)
+ "Parse and evaluate a simple expression.
The result is a pair (TYPE . VALUE). Currently, type types are `:id',
- `:int', `:string', `:char', `:fragment', `:type'. If an error prevented a sane value from
- being produced, the type `:invalid' is returned.
+ `:int', `:string', `:char', `:fragment', `:type'. If an error prevented a
+ sane value from being produced, the type `:invalid' is returned.
The syntax of expressions is rather limited at the moment, but more may be
added later.
| `<' declspec+ declarator[empty] `>' | `?' lisp-expression
Only operators for dealing with integers are provided."
- (with-parser-context (token-scanner-context :scanner scanner)
- (parse (expr (:nestedp nestedp)
- (lisp (flet ((prop (type value)
- (scanner-step scanner)
- (values (cons type value) t t)))
- (case (token-type scanner)
- ((:int :id :char :string)
- (prop (token-type scanner)
- (token-value scanner)))
- (#\?
- (let* ((stream (make-scanner-stream scanner))
- (sexp (read stream t)))
+ (with-parser-context (token-scanner-context :scanner scanner)
+ (parse (expr (:nestedp nestedp)
+ (lisp (flet ((prop (type value)
(scanner-step scanner)
- (multiple-value-bind (type value)
- (restart-case (decode-property (eval sexp))
- (continue () (values :invalid nil)))
- (values (cons type value) t t))))
- (#\{
- (values (cons :fragment
- (parse-delimited-fragment scanner
- #\{ #\}))
- t t))
- (#\<
- (parse (seq (#\<
- (ds (parse-c-type scanner))
- (dc (parse-declarator
- scanner ds
- :kernel (lambda ()
- (values nil t nil))
- :abstractp t))
- #\>)
- (values (cons :type (car dc))
- t t))))
- (t
- (values (list :int :id :char :string #\? #\{ #\<)
- nil nil)))))
- (or (seq (#\+) add)
- (seq (#\-) sub)
- (seq (#\*) mul)
- (seq (#\/) div))
- (or (seq (#\() lp)
- (seq (#\+) nop)
- (seq (#\-) neg))
- (when nestedp (seq (#\)) rp))))))))
+ (values (cons type value) t t)))
+ (case (token-type scanner)
+ ((:int :id :char :string)
+ (prop (token-type scanner)
+ (token-value scanner)))
+ (#\?
+ (let* ((stream (make-scanner-stream scanner))
+ (sexp (read stream t)))
+ (scanner-step scanner)
+ (multiple-value-bind (type value)
+ (restart-case (decode-property (eval sexp))
+ (continue () (values :invalid nil)))
+ (values (cons type value) t t))))
+ (#\{
+ (values (cons :fragment
+ (parse-delimited-fragment scanner
+ #\{ #\}))
+ t t))
+ (#\<
+ (parse (seq (#\<
+ (ds (parse-c-type scanner))
+ (dc (parse-declarator
+ scanner ds
+ :kernel (lambda ()
+ (values nil t nil))
+ :abstractp t))
+ #\>)
+ (values (cons :type (car dc))
+ t t))))
+ (t
+ (values (list :int :id :char :string #\? #\{ #\<)
+ nil nil)))))
+
+ ((:op #\* binop "*" (x y 7)
+ (dispatch "*" (list x y) (list :int #'* :int :int)))
+ (:op #\/ binop "/" (x y 7)
+ (dispatch "/" (list x y)
+ (list :int
+ (lambda (x y)
+ (cond ((zerop y)
+ (cerror*
+ "Division by zero")
+ (cons :invalid nil))
+ (t
+ (floor x y))))
+ :int :int)))
+ (:op #\+ binop "+" (x y 5)
+ (dispatch "+" (list x y) (list :int #'+ :int :int)))
+ (:op #\- binop "-" (x y 5)
+ (dispatch "-" (list x y) (list :int #'- :int :int))))
+
+ ((:op #\+ preop "+" (x 9)
+ (dispatch "+" (list x) (list :int #'+ :int)))
+ (:op #\- preop "-" (x 9)
+ (dispatch "-" (list x) (list :int #'- :int)))
+ (:op #\( lparen #\)))
+
+ ((:op (when nestedp #\)) rparen #\))))))))
;;;--------------------------------------------------------------------------
;;; Parsing property sets.