SMOLNET PORTAL home about changes
(uiop:define-package :st-buchberger/src/parser
 (:nicknames :parser)
 (:export #:polynomial #:term #:term-monomial #:*zero-polynomial*
  #:term-coefficient #:monomial-indeterminates #:polynomial-terms
  #:parse-polynomial #:parse-term #:parse-coefficient
  #:parse-monomial #:parse-expt-symbol))

(in-package :st-buchberger/src/parser)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;
;; Grammar
;; =======
;;
;; polynomial  : term
;;             | "(" "-" term+ ")"
;;             | "(" "+" term* ")"
;;
;; term        : coefficient
;;             | monomial
;;             | "(" "*" coefficient monomial ")"
;;             | "(" "-" term ")"
;;
;; coefficient : rational
;;
;; monomial    : expt-symbol
;;             | "(" expt-symbol+ ")"
;;
;; expt-symbol : symbol
;;             | "(" "expt" symbol non-negative-integer ")"
;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

(defstruct polynomial
  terms)

(defstruct term
  coefficient
  monomial)

(defstruct monomial
  "Association list whose keys are indeterminates (symbols) and the
corresponding values are the powers."
  indeterminates)

(defparameter *zero-polynomial*
  (make-polynomial :terms (list (make-term :coefficient 0
                                           :monomial (make-monomial
                                                      :indeterminates nil))))
  "Representation of the zero polynomial.")

(defun parse-polynomial (sexp)
  "Parse polynomial in SEXP."
  (cond
    ((null sexp)
     (error "Invalid expression: ~S." sexp))
    ((and (consp sexp) (eq (first sexp) '+))
     (if (zerop (length (rest sexp)))
         *zero-polynomial*
         (make-polynomial :terms (loop :for x :in (rest sexp)
                                       :collect (parse-term x)))))
    ((and (consp sexp) (eq (first sexp) '-))
     (case (length (rest sexp))
       (0 *zero-polynomial*)
       (1 (make-polynomial :terms (list (parse-term sexp))))
       (t (make-polynomial :terms (loop :for x :in (rest sexp)
                                        :for term := (parse-term x)
                                        :for i :from 0
                                        :when (plusp i) :do
                                          (setf (term-coefficient term)
                                                (- (term-coefficient term)))
                                        :collect term)))))
    (t (make-polynomial :terms (list (parse-term sexp))))))

(defun parse-term (sexp)
  "Parse term in SEXP."
  (cond
    ((atom sexp)
     (if (numberp sexp)
         (make-term :coefficient (parse-coefficient sexp)
                    :monomial (make-monomial :indeterminates nil))
         (make-term :coefficient 1 :monomial (parse-monomial sexp))))
    ((consp sexp)
     (destructuring-bind (first . rest) sexp
       (case first
         (* (let ((coeff (car rest)))
              (if (numberp coeff)
                  (make-term :coefficient (parse-coefficient coeff)
                             :monomial (parse-monomial (cdr rest)))
                  (make-term :coefficient 1
                             :monomial (parse-monomial rest)))))
         (- (let ((term (apply #'parse-term rest)))
              (setf (term-coefficient term) (- (term-coefficient term)))
              term))
         (t (make-term :coefficient 1
                       :monomial (parse-monomial sexp))))))))

(defun parse-coefficient (sexp)
  "Parse coefficient in SEXP."
  (unless (and (numberp sexp) (typep sexp 'rational))
    (error "Invalid coefficient: ~S." sexp))
  sexp)

(defun parse-monomial (sexp)
  "Parse monomial in SEXP."
  (make-monomial
   :indeterminates (if (atom sexp)
                       (list (parse-expt-symbol sexp))
                       (if (eq (car sexp) 'expt)
                           (list (parse-expt-symbol sexp))
                           (loop :for x :in sexp
                                 :collect (parse-expt-symbol x))))))

(defun parse-expt-symbol (sexp)
  "Parse (possibly exponentiated) symbol in SEXP."
  (flet ((error-invalid-expt-symbol (sexp)
           (error "Invalid (possibly exponentiated) symbol: ~S." sexp)))
    (cond
      ((atom sexp)
       (unless (symbolp sexp)
         (error-invalid-expt-symbol sexp))
       (cons sexp 1))
      (t
       (destructuring-bind (op symbol power) sexp
         (unless (and (eq op 'expt)
                      (symbolp symbol)
                      (typep power '(integer 0)))
           (error-invalid-expt-symbol sexp))
         (cons symbol power))))))
Response: text/plain
Original URLgopher://tilde.institute/0/~screwtape/st-buchberger/src/p...
Content-Typetext/plain; charset=utf-8