From: Mark Wooding Date: Tue, 20 Aug 2019 01:34:14 +0000 (+0100) Subject: src/lexer-{proto,impl}.lisp, src/pset-parse.lisp: Other C operators. X-Git-Url: https://git.distorted.org.uk/~mdw/sod/commitdiff_plain/fe471148e34552002cfb25d235f62fd557865dda src/lexer-{proto,impl}.lisp, src/pset-parse.lisp: Other C operators. Add almost all of the familiar C operators. Some of these need their own tokens added. There's a lexical gotcha now, since `x << y' and `x < < y ...' mean different things: the former parses as `x shift- left-by y', while the latter parses as `x is-less-than some-type- beginning-with-y'. --- diff --git a/doc/syntax.tex b/doc/syntax.tex index fc34e4e..c50608c 100644 --- a/doc/syntax.tex +++ b/doc/syntax.tex @@ -130,7 +130,8 @@ binary. However, length and signedness indicators are not permitted. \subsection{Punctuation} \label{sec:syntax.lex.punct} \begin{grammar} - ::= "\dots" + ::= "<<" | ">>" | "||" | "&&" + | "<=" | ">=" | "==" | "!=" | "\dots" \alt any nonalphanumeric character other than "_", "\"", or "'" \end{grammar} @@ -367,7 +368,36 @@ keyword arguments. ::= "=" - ::= + ::= + + ::= + | "||" + + ::= + | "&&" + + ::= + | "|" + + ::= + | "^" + + ::= + | "&" + + ::= + | "==" + | "!=" + + ::= + | "<" + | "<=" + | ">=" + | ">" + + ::= + | "<<" + | ">>" ::= | "+" diff --git a/src/lexer-impl.lisp b/src/lexer-impl.lisp index de76371..ccaca5c 100644 --- a/src/lexer-impl.lisp +++ b/src/lexer-impl.lisp @@ -188,6 +188,14 @@ ;; Some special punctuation sequences are single tokens. ("..." (values :ellipsis nil)) + ("==" (values :eq)) + ("!=" (values :ne)) + ("<=" (values :le)) + (">=" (values :ge)) + ("&&" (values :and)) + ("||" (values :or)) + ("<<" (values :shl)) + (">>" (values :shr)) ;; Any other character is punctuation. (:any (values it nil)) diff --git a/src/lexer-proto.lisp b/src/lexer-proto.lisp index a811298..a237a92 100644 --- a/src/lexer-proto.lisp +++ b/src/lexer-proto.lisp @@ -65,6 +65,14 @@ (:char "") (:eof "") (:ellipsis "`...'") + (:shl "`<<'") + (:shr "`>>'") + (:eq "`=='") + (:ne "`!='") + (:le "`<='") + (:ge "`>='") + (:and "`&&'") + (:or "`||'") (t (format nil "" type value))))) (show-expected (thing) (acond ((gethash thing *indicator-map*) it) diff --git a/src/pset-parse.lisp b/src/pset-parse.lisp index cfd2b4a..e3c0d4b 100644 --- a/src/pset-parse.lisp +++ b/src/pset-parse.lisp @@ -77,7 +77,25 @@ ;; Evaluate X and Y to integers, and apply INTOP to the ;; results, giving another integer. (oplambda - (values :int (funcall intop (want :int x) (want :int y)))))) + (values :int (funcall intop (want :int x) (want :int y))))) + + (compareop (intop strop x y) + ;; Evaluate X and Y. If they're integers, then apply INTOP to + ;; them; if they're strings, apply STROP. The result is a + ;; boolean. + (oplambda + (multiple-value-bind (xty xval) (funcall x) + (case xty + (:int + (values :boolean + (funcall intop xval (want :int y)))) + ((:id :string :symbol) + (values :boolean + (funcall strop + (coerce-property-value xval xty :id) + (want :id y)))) + (t + (error "Can't compare objects of type ~(~A~)" xty))))))) (with-parser-context (token-scanner-context :scanner scanner) (when-parse () @@ -145,10 +163,42 @@ (when (zerop y) (error "Division by zero")) (values :int (floor x y))))) (:op #\+ binop "+" (x y 60) (int-binop #'+ x y)) - (:op #\- binop "-" (x y 60) (int-binop #'- x y))) + (:op #\- binop "-" (x y 60) (int-binop #'- x y)) + (:op :shl binop "<<" (x y 50) (int-binop #'ash x y)) + (:op :shr binop ">>" (x y 50) + (int-binop (lambda (x y) (ash x (- y))) x y)) + (:op #\< binop "<" (x y 45) + (compareop #'< #'string< x y)) + (:op :le binop "<=" (x y 45) + (compareop #'<= #'string<= x y)) + (:op :ge binop ">=" (x y 45) + (compareop #'>= #'string>= x y)) + (:op #\> binop ">" (x y 45) + (compareop #'> #'string> x y)) + (:op :eq binop "==" (x y 40) + (compareop #'= #'string= x y)) + (:op :ne binop "!=" (x y 40) + (compareop #'/= #'string/= x y)) + (:op #\& binop "&" (x y 37) (int-binop #'logand x y)) + (:op #\^ binop "^" (x y 35) (int-binop #'logxor x y)) + (:op #\| binop "|" (x y 32) (int-binop #'logior x y)) + (:op :and binop "&&" (x y 27) + (oplambda (if (want :boolean x) (funcall y) + (values :boolean nil)))) + (:op :or binop "||" (x y 22) + (oplambda + (multiple-value-bind (xty xval) (funcall x) + (if (coerce-property-value xval xty :boolean) + (values xty xval) + (funcall y)))))) ;; Prefix operators. - ((:op #\+ preop "+" (x 90) (int-unop #'identity x)) + ((:op #\~ preop "~" (x 90) (int-unop #'lognot x)) + (:op #\! preop "!" (x 90) + (oplambda + (values :boolean + (not (want :boolean (funcall x)))))) + (:op #\+ preop "+" (x 90) (int-unop #'identity x)) (:op #\- preop "-" (x 90) (int-unop #'- x)) (:op #\( lparen #\)))