Lots more has happened.
authorMark Wooding <mdw@distorted.org.uk>
Sat, 17 Oct 2009 00:10:34 +0000 (01:10 +0100)
committerMark Wooding <mdw@distorted.org.uk>
Sat, 17 Oct 2009 00:10:34 +0000 (01:10 +0100)
  * all reserved words are now banished
  * an ilayout now consists of, for each chain, a union of the ichains
    for each class on the chain -- makes referring to the bit which
    represents a superclass instance trivial; not yet hacked the
    effective method codegen to cope
  * unnecessary ichain and vt structures (ones which are copies of a
    superclass's) are suppressed -- we use the original directly
    (must document the new chain-tail tracking stuff); only one new
    ichain and vtable structure per class (though we still need all-new
    vtmsgs for each superclass).
  * header file output is complete and functional

15 files changed:
builtin.lisp
class-builder.lisp
class-defs.lisp
class-finalize.lisp
class-layout.lisp
class-output.lisp
examples.lisp
lex.lisp
methods.lisp
module-output.lisp [new file with mode: 0644]
module.lisp
output.lisp
parse-c-types.lisp
sod.c
sod.h

index 26d384b..21fa1e3 100644 (file)
@@ -187,12 +187,12 @@ static const SodClass *const ~A__cpl[] = {
              ,(lambda (class)
                 (format nil "sizeof(struct ~A)"
                         (ilayout-struct-tag class))))
-    ("imprint" ,(c-type (* (fun (* void) ("p" (* void)))))
+    ("imprint" ,(c-type (* (fun (* void) ("/*p*/" (* void)))))
               :prepare-function 'output-imprint-function
               :initializer-function
               ,(lambda (class)
                  (format nil "~A__imprint" class)))
-    ("init" ,(c-type (* (fun (* void) ("p" (* void)))))
+    ("init" ,(c-type (* (fun (* void) ("/*p*/" (* void)))))
            :prepare-function 'output-init-function
            :initializer-function
            ,(lambda (class)
@@ -300,7 +300,7 @@ static const SodClass *const ~A__cpl[] = {
 
 (defun make-builtin-module ()
   (let ((module (make-instance 'module
-                              :name (make-pathname :name "BUILTIN"
+                              :name (make-pathname :name "SOD-BASE"
                                                    :type "SOD"
                                                    :case :common)
                               :state nil))
index 2d77d70..7acbeae 100644 (file)
     (check-method-type method message type)))
 
 ;;;--------------------------------------------------------------------------
-;;; Builder macro.
+;;; Builder macros.
 
 (defmacro define-sod-class (name (&rest superclasses) &body body)
   (let ((plist nil)
                                                  ,@plist))))
         ,@body
         (finalize-sod-class ,classvar)
-        (record-sod-class ,classvar)))))
-
-#+test
-(define-sod-class "AbstractStack" ("SodObject")
-  :nick 'abstk
-  (message "emptyp" (fun int))
-  (message "push" (fun void ("item" (* void))))
-  (message "pop" (fun (* void)))
-  (method "abstk" "pop" (fun void) #{
-     assert(!me->_vt.emptyp());
-   }
-   :role :before))
+        (add-to-module *module* ,classvar)))))
 
 ;;;----- That's all, folks --------------------------------------------------
index 8640cf5..512505b 100644 (file)
@@ -53,6 +53,8 @@
 
    (class-precedence-list :type list :accessor sod-class-precedence-list)
 
+   (type :type c-class-type :accessor sod-class-type)
+
    (chain-head :type sod-class :accessor sod-class-chain-head)
    (chain :type list :accessor sod-class-chain)
    (chains :type list :accessor sod-class-chains)
            (t
             (setf (c-type-class type) class))))))
 
-(defun sod-class-type (class)
-  "Returns the C type corresponding to CLASS."
-  (find-class-type (sod-class-name class)))
-
 (define-c-type-syntax class (name &rest quals)
   "Returns a type object for the named class."
   (if quals
index cf1ff73..fa8cc7d 100644 (file)
          (error "Invalid message name `~A' on class `~A'"
                 (sod-message-name message) class))))
 
-      ;; Check that the slots and messages have distinct names.
+    ;; Check that the slots and messages have distinct names.
     (with-slots (slots messages class-precedence-list) class
       (flet ((check-list (list what namefunc)
               (let ((table (make-hash-table :test #'equal)))
        (error "In `~A~, chain-to class `~A' is not a proper superclass"
               class chain-link)))
 
+    ;; Check for circularity in the superclass graph.  Since the superclasses
+    ;; should already be acyclic, it suffices to check that our class is not
+    ;; a superclass of any of its own direct superclasses.
+    (let ((circle (find-if (lambda (super)
+                            (sod-subclass-p super class))
+                          (sod-class-direct-superclasses class))))
+      (when circle
+       (error "Circularity: ~A is already a superclass of ~A"
+              class circle)))
+
+    ;; Check that the class has a unique root superclass.
+    (find-root-superclass class)
+
     ;; Check that the metaclass is a subclass of each direct superclass's
     ;; metaclass.
     (with-slots (metaclass direct-superclasses) class
                     (eq class metaclass))
           (finalize-sod-class metaclass)))
 
+       ;; Stash the class's type.
+       (setf (sod-class-type class)
+            (make-class-type (sod-class-name class)))
+
        ;; Clobber the lists of items if they've not been set.
        (dolist (slot '(slots instance-initializers class-initializers
                       messages methods))
index df068ed..a37852e 100644 (file)
@@ -99,7 +99,9 @@
 (defclass vtable-pointer ()
   ((class :initarg :class :type sod-class :reader vtable-pointer-class)
    (chain-head :initarg :chain-head :type sod-class
-              :reader vtable-pointer-chain-head))
+              :reader vtable-pointer-chain-head)
+   (chain-tail :initarg :chain-tail :type sod-class
+              :reader vtable-pointer-chain-tail))
   (:documentation
    "A pointer to the vtable for CLASS corresponding to a particular CHAIN."))
 
 (defclass ichain ()
   ((class :initarg :class :type sod-class :reader ichain-class)
    (chain-head :initarg :chain-head :type sod-class :reader ichain-head)
+   (chain-tail :initarg :chain-tail :type sod-class :reader ichain-tail)
    (body :initarg :body :type list :reader ichain-body))
   (:documentation
    "All of the instance layout for CLASS corresponding to a particular CHAIN.
                                (sod-class-slots class))))
 
 (defmethod compute-ichain ((class sod-class) chain)
-  (let* ((head (car chain))
+  (let* ((chain-head (car chain))
+        (chain-tail (find chain-head (mapcar #'car (sod-class-chains class))
+                          :key #'sod-class-chain-head))
         (vtable-pointer (make-instance 'vtable-pointer
                                        :class class
-                                       :chain-head head))
+                                       :chain-head chain-head
+                                       :chain-tail chain-tail))
         (islots (remove-if-not #'islots-slots
                                (mapcar (lambda (super)
                                          (compute-islots super class))
                                        chain))))
     (make-instance 'ichain
                   :class class
-                  :chain-head head
+                  :chain-head chain-head
+                  :chain-tail chain-tail
                   :body (cons vtable-pointer islots))))
 
 (defmethod compute-ilayout ((class sod-class))
 (defclass method-entry ()
   ((method :initarg :method :type effective-method
           :reader method-entry-effective-method)
-   (chain-head :initarg :chain-head
-              :type sod-class
-              :reader method-entry-chain-head))
+   (chain-head :initarg :chain-head :type sod-class
+              :reader method-entry-chain-head)
+   (chain-tail :initarg :chain-tail :type sod-class
+              :reader method-entry-chain-tail))
   (:documentation
    "An entry point into an effective method.
 
            (method-entry-effective-method entry)
            (sod-class-nickname (method-entry-chain-head entry)))))
 
-(defgeneric make-method-entry (effective-method chain-head)
+(defgeneric make-method-entry (effective-method chain-head chain-tail)
   (:documentation
    "Return a METHOD-ENTRY for an EFFECTIVE-METHOD called via CHAIN-HEAD.
 
    (subclass :initarg :subclass :type sod-class :reader vtmsgs-subclass)
    (chain-head :initarg :chain-head :type sod-class
               :reader vtmsgs-chain-head)
+   (chain-tail :initarg :chain-tail :type sod-class
+              :reader vtmsgs-chain-tail)
    (entries :initarg :entries :type list :reader vtmsgs-entries))
   (:documentation
    "The message dispatch table for a particular CLASS.
 
-   The BODY contains a list of effective method objects for the messages
-   defined on CLASS, customized for calling from the chain headed by
+   The BODY contains a list of effective method entry objects for the
+   messages defined on CLASS, customized for calling from the chain headed by
    CHAIN-HEAD."))
 
 (defmethod print-object ((vtmsgs vtmsgs) stream)
            (vtmsgs-class vtmsgs)
            (vtmsgs-entries vtmsgs))))
 
-(defgeneric compute-vtmsgs (class subclass chain-head)
+(defgeneric compute-vtmsgs (class subclass chain-head chain-tail)
   (:documentation
    "Return a VTMSGS object containing method entries for CLASS.
 
   ((class :initarg :class :type sod-class :reader vtable-class)
    (chain-head :initarg :chain-head :type sod-class
               :reader vtable-chain-head)
+   (chain-tail :initarg :chain-tail :type sod-class
+              :reader vtable-chain-tail)
    (body :initarg :body :type list :reader vtable-body))
   (:documentation
    "VTABLEs hold all of the per-chain static information for a class.
 (defmethod compute-vtmsgs
     ((class sod-class)
      (subclass sod-class)
-     (chain-head sod-class))
+     (chain-head sod-class)
+     (chain-tail sod-class))
   (flet ((make-entry (message)
           (let ((method (find message
                               (sod-class-effective-methods subclass)
                               :key #'effective-method-message)))
-            (make-method-entry method chain-head))))
+            (make-method-entry method chain-head chain-tail))))
     (make-instance 'vtmsgs
                   :class class
                   :subclass subclass
                   :chain-head chain-head
+                  :chain-tail chain-tail
                   :entries (mapcar #'make-entry
                                    (sod-class-messages class)))))
 
 (defvar *done-metaclass-chains*)
 (defvar *done-instance-chains*)
 
-(defgeneric compute-vtable-items (class super chain-head emit)
+(defgeneric compute-vtable-items (class super chain-head chain-tail emit)
   (:documentation
    "Emit vtable items for a superclass of CLASS.
 
 
 (defmethod compute-vtable-items
     ((class sod-class) (super sod-class) (chain-head sod-class)
-     (emit function))
+     (chain-tail sod-class) (emit function))
 
   ;; If this class introduces new metaclass chains, then emit pointers to
   ;; them.
 
   ;; Finally, if there are interesting methods, emit those too.
   (when (sod-class-messages super)
-    (funcall emit (compute-vtmsgs super class chain-head))))
+    (funcall emit (compute-vtmsgs super class chain-head chain-tail))))
+
+(defun find-root-superclass (class)
+  "Returns the `root' superclass of CLASS.
+
+   The root superclass is the superclass which itself has no direct
+   superclasses.  In universes not based on the provided builtin module, the
+   root class may not be our beloved SodObject; however, there must be one
+   (otherwise the class graph is cyclic, which should be forbidden), and we
+   instist that it be unique."
+
+  ;; The root superclass must be a chain head since the chains partition the
+  ;; superclasses; the root has no superclasses so it can't have a link and
+  ;; must therefore be a head.  This narrows the field down quite a lot.
+  ;;
+  ;; Note!  This function gets called from CHECK-SOD-CLASS before the class's
+  ;; chains have been computed.  Therefore we iterate over the direct
+  ;; superclass's chains rather than the class's own.  This misses a chain
+  ;; only in the case where the class is its own chain head.  There are two
+  ;; subcases: if there are no direct superclasses at all, then the class is
+  ;; its own root; otherwise, it clearly can't be the root and the omission
+  ;; is harmless.
+  (let* ((supers (sod-class-direct-superclasses class))
+        (roots (if supers
+                   (remove-if #'sod-class-direct-superclasses
+                              (mapcar (lambda (super)
+                                        (sod-class-chain-head super))
+                                      supers))
+                   (list class))))
+    (cond ((null roots) (error "Class ~A has no root class!" class))
+         ((cdr roots) (error "Class ~A has multiple root classes ~
+                              ~{~A~#[~; and ~;, ~]~}"
+                             class roots))
+         (t (car roots)))))
+
+(defun find-root-metaclass (class)
+  "Returns the `root' metaclass of CLASS.
+
+   The root metaclass is the metaclass of the root superclass -- see
+   FIND-ROOT-SUPERCLASS."
+  (sod-class-metaclass (find-root-superclass class)))
 
 (defmethod compute-vtable ((class sod-class) (chain list))
   (let* ((chain-head (car chain))
+        (chain-tail (find chain-head (mapcar #'car (sod-class-chains class))
+                          :key #'sod-class-chain-head))
         (*done-metaclass-chains* nil)
         (*done-instance-chains* (list chain-head))
         (done-superclasses nil)
 
       ;; Find the root chain in the metaclass and write a pointer.
       (let* ((metaclass (sod-class-metaclass class))
-            (metaclass-chains (sod-class-chains metaclass))
-            (metaclass-chain-heads (mapcar (lambda (chain)
-                                             (sod-class-chain-head
-                                              (car chain)))
-                                           metaclass-chains))
-            (metaclass-root-chain (find-if-not
-                                   #'sod-class-direct-superclasses
-                                   metaclass-chain-heads)))
-       (emit (make-class-pointer class chain-head
-                                 metaclass metaclass-root-chain))
-       (push metaclass-root-chain *done-metaclass-chains*))
+            (metaclass-root (find-root-metaclass class))
+            (metaclass-root-head (sod-class-chain-head metaclass-root)))
+       (emit (make-class-pointer class chain-head metaclass
+                                 metaclass-root-head))
+       (push metaclass-root-head *done-metaclass-chains*))
 
       ;; Write an offset to the instance base.
       (emit (make-base-offset class chain-head))
            (compute-vtable-items class
                                  sub
                                  chain-head
+                                 chain-tail
                                  #'emit)
            (push sub done-superclasses))))
 
       (make-instance 'vtable
                     :class class
                     :chain-head chain-head
+                    :chain-tail chain-tail
                     :body (nreverse items)))))
 
 (defgeneric compute-effective-methods (class)
   (format nil "~A__islots" class))
 
 (defun ichain-struct-tag (class chain-head)
-  (format nil "~A__ichain_~A" class(sod-class-nickname chain-head)))
+  (format nil "~A__ichain_~A" class (sod-class-nickname chain-head)))
+
+(defun ichain-union-tag (class chain-head)
+  (format nil "~A__ichainu_~A" class (sod-class-nickname chain-head)))
 
 (defun ilayout-struct-tag (class)
   (format nil "~A__ilayout" class))
 (defun vtable-name (class chain-head)
   (format nil "~A__vtable_~A" class (sod-class-nickname chain-head)))
 
-;;;--------------------------------------------------------------------------
-;;; Hacks for now.
-
-(defclass hacky-effective-method (effective-method)
-  ((direct-methods :initarg :direct-methods)))
-
-(defmethod print-object ((method hacky-effective-method) stream)
-  (if *print-escape*
-      (print-unreadable-object (method stream :type t)
-       (format stream "~A ~_~A ~_~:<~@{~S~^ ~_~}~:>"
-               (effective-method-message method)
-               (effective-method-class method)
-               (slot-value method 'direct-methods)))
-      (call-next-method)))
-
-(defmethod message-effective-method-class ((message sod-message))
-  'hacky-effective-method)
-
-(defmethod make-method-entry
-    ((method hacky-effective-method) (chain-head sod-class))
-  (make-instance 'method-entry
-                :method method
-                :chain-head chain-head))
-
 ;;;----- That's all, folks --------------------------------------------------
index 8fdcc82..dc07665 100644 (file)
      (class :vtmsgs :start) (class :vtmsgs :end)
      (class :vtables :start) (class :vtables :end)
      (class :vtable-externs) (class :vtable-externs-after)
-     (class :direct-methods)
+     (class :methods :start) (class :methods) (class :methods :end)
      (class :ichains :start) (class :ichains :end)
      (class :ilayout :start) (class :ilayout :slots) (class :ilayout :end)
      (class :conversions)
+     (class :object)
      (:classes :end))
 
     (:typedefs
     ((class :banner)
      (banner (format nil "Class ~A" class) stream))
     ((class :vtable-externs-after)
-     (terpri stream)))
+     (terpri stream))
+
+    ((class :vtable-externs)
+     (format stream "/* Vtable structures. */~%"))
+
+    ((class :object)
+     (let ((metaclass (sod-class-metaclass class))
+          (metaroot (find-root-metaclass class)))
+       (format stream "/* The class object. */~%~
+                      extern struct ~A ~A__classobj;~%~
+                      #define ~:*~A__class (&~:*~A__classobj.~A.~A)~2%"
+              (ilayout-struct-tag metaclass) class
+              (sod-class-nickname (sod-class-chain-head metaroot))
+              (sod-class-nickname metaroot)))))
 
   ;; Maybe generate an islots structure.
   (when (sod-class-slots class)
       (add-output-hooks slot 'populate-islots sequencer))
     (sequence-output (stream sequencer)
       ((class :islots :start)
-       (format stream "struct ~A {~%" (islots-struct-tag class)))
+       (format stream "/* Instance slots. */~%~
+                      struct ~A {~%"
+              (islots-struct-tag class)))
       ((class :islots :end)
        (format stream "};~2%"))))
 
   ;; Declare the direct methods.
   (when (sod-class-methods class)
-    (dolist (method (sod-class-methods class))
-      (add-output-hooks method :declare-direct-methods sequencer))
     (sequence-output (stream sequencer)
-      ((class :direct-methods)
+      ((class :methods :start)
+       (format stream "/* Direct methods. */~%"))
+      ((class :methods :end)
        (terpri stream))))
 
   ;; Provide upcast macros which do the right thing.
     (sequence-output (stream sequencer)
       ((class :conversions)
        (let ((chain-head (sod-class-chain-head class)))
+        (format stream "/* Conversion macros. */~%")
         (dolist (super (cdr (sod-class-precedence-list class)))
           (let ((super-head (sod-class-chain-head super)))
-            (format stream (concatenate 'string "#define "
-                                        "~:@(~A__CONV_~A~)(p) ((~A *)"
-                                        "~:[SOD_XCHAIN(~A, p)~;p~])~%")
+            (format stream "#define ~:@(~A__CONV_~A~)(p) ((~A *)~
+                                    ~:[SOD_XCHAIN(~A, (p))~;(p)~])~%"
                     class (sod-class-nickname super) super
                     (eq chain-head super-head)
-                    (sod-class-nickname super-head))))))))
+                    (sod-class-nickname super-head))))
+        (terpri stream)))))
 
   ;; Generate vtmsgs structure for all superclasses.
   (add-output-hooks (car (sod-class-vtables class))
                    sequencer))
 
 (defmethod add-output-hooks progn ((class sod-class) reason sequencer)
-  (with-slots (ilayout vtables) class
+  (with-slots (ilayout vtables methods) class
     (add-output-hooks ilayout reason sequencer)
+    (dolist (method methods) (add-output-hooks method reason sequencer))
     (dolist (vtable vtables) (add-output-hooks vtable reason sequencer))))
 
 ;;;--------------------------------------------------------------------------
   (with-slots (class ichains) ilayout
     (sequence-output (stream sequencer)
       ((class :ilayout :start)
-       (format stream "struct ~A {~%" (ilayout-struct-tag class)))
+       (format stream "/* Instance layout. */~%~
+                      struct ~A {~%"
+              (ilayout-struct-tag class)))
       ((class :ilayout :end)
        (format stream "};~2%")))
     (dolist (ichain ichains)
 
 (defmethod add-output-hooks progn
     ((ichain ichain) (reason (eql :h)) sequencer)
-  (with-slots (class chain-head) ichain
-    (sequence-output (stream sequencer)
-      :constraint ((class :ichains :start)
-                  (class :ichain chain-head :start)
-                  (class :ichain chain-head :slots)
-                  (class :ichain chain-head :end)
-                  (class :ichains :end))
-      ((class :ichain chain-head :start)
-       (format stream "struct ~A {~%" (ichain-struct-tag class chain-head)))
-      ((class :ichain chain-head :end)
-       (format stream "};~2%")))))
+  (with-slots (class chain-head chain-tail) ichain
+    (when (eq class chain-tail)
+      (sequence-output (stream sequencer)
+       :constraint ((class :ichains :start)
+                    (class :ichain chain-head :start)
+                    (class :ichain chain-head :slots)
+                    (class :ichain chain-head :end)
+                    (class :ichains :end))
+       ((class :ichain chain-head :start)
+        (format stream "/* Instance chain structure. */~%~
+                        struct ~A {~%"
+                (ichain-struct-tag chain-tail chain-head)))
+       ((class :ichain chain-head :end)
+        (format stream "};~2%")
+        (format stream "/* Union of equivalent superclass chains. */~%~
+                        union ~A {~%~
+                        ~:{  struct ~A ~A;~%~}~
+                        };~2%"
+                (ichain-union-tag chain-tail chain-head)
+                (mapcar (lambda (super)
+                          (list (ichain-struct-tag super chain-head)
+                                (sod-class-nickname super)))
+                        (sod-class-chain chain-tail))))))))
 
 (defmethod add-output-hooks progn
     ((ichain ichain) (reason (eql 'populate-ilayout)) sequencer)
-  (with-slots (class chain-head) ichain
+  (with-slots (class chain-head chain-tail) ichain
     (sequence-output (stream sequencer)
       ((class :ilayout :slots)
-       (format stream "  struct ~A ~A;~%"
-              (ichain-struct-tag class chain-head)
+       (format stream "  union ~A ~A;~%"
+              (ichain-union-tag chain-tail chain-head)
               (sod-class-nickname chain-head))))))
 
-(defmethod add-output-hooks progn ((ichain ichain) reason sequencer)
-  (with-slots (body) ichain
-    (dolist (item body) (add-output-hooks item reason sequencer))))
-
 (defmethod add-output-hooks progn
     ((vtptr vtable-pointer) (reason (eql :h)) sequencer)
-  (with-slots (class chain-head) vtptr
+  (with-slots (class chain-head chain-tail) vtptr
     (sequence-output (stream sequencer)
       ((class :ichain chain-head :slots)
        (format stream "  const struct ~A *_vt;~%"
-              (vtable-struct-tag class chain-head))))))
+              (vtable-struct-tag chain-tail chain-head))))))
 
 (defmethod add-output-hooks progn
     ((islots islots) (reason (eql :h)) sequencer)
     (dolist (item body) (add-output-hooks item reason sequencer))))
 
 (defmethod add-output-hooks progn
+    ((method sod-method) (reason (eql :h)) sequencer)
+  (with-slots (class) method
+    (sequence-output (stream sequencer)
+      ((class :methods)
+       (let ((type (sod-method-function-type method)))
+        (princ "extern " stream)
+        (pprint-c-type (commentify-function-type type) stream
+                       (sod-method-function-name method))
+        (format stream ";~%"))))))
+
+(defmethod add-output-hooks progn
     ((vtable vtable) (reason (eql :h)) sequencer)
-  (with-slots (class chain-head) vtable
+  (with-slots (class chain-head chain-tail) vtable
+    (when (eq class chain-tail)
+      (sequence-output (stream sequencer)
+       :constraint ((class :vtables :start)
+                    (class :vtable chain-head :start)
+                    (class :vtable chain-head :slots)
+                    (class :vtable chain-head :end)
+                    (class :vtables :end))
+       ((class :vtable chain-head :start)
+        (format stream "/* Vtable structure. */~%~
+                        struct ~A {~%"
+                (vtable-struct-tag chain-tail chain-head)))
+       ((class :vtable chain-head :end)
+        (format stream "};~2%"))))
     (sequence-output (stream sequencer)
-      :constraint ((class :vtables :start)
-                  (class :vtable chain-head :start)
-                  (class :vtable chain-head :slots)
-                  (class :vtable chain-head :end)
-                  (class :vtables :end))
-      ((class :vtable chain-head :start)
-       (format stream "struct ~A {~%" (vtable-struct-tag class chain-head)))
-      ((class :vtable chain-head :end)
-       (format stream "};~2%"))
       ((class :vtable-externs)
        (format stream "~@<extern struct ~A ~2I~_~A__vtable_~A;~:>~%"
-              (vtable-struct-tag class chain-head)
+              (vtable-struct-tag chain-tail chain-head)
               class (sod-class-nickname chain-head))))))
 
 (defmethod add-output-hooks progn
     ((vtmsgs vtmsgs) (reason (eql :h)) sequencer)
-  (with-slots (class subclass chain-head) vtmsgs
+  (with-slots (class subclass chain-head chain-tail) vtmsgs
     (sequence-output (stream sequencer)
       ((subclass :vtable chain-head :slots)
        (format stream "  struct ~A ~A;~%"
                     (subclass :vtmsgs class :end)
                     (subclass :vtmsgs :end))
        ((subclass :vtmsgs class :start)
-        (format stream "struct ~A {~%" (vtmsgs-struct-tag subclass class)))
+        (format stream "/* Messages protocol from class ~A */~%~
+                        struct ~A {~%"
+                class
+                (vtmsgs-struct-tag subclass class)))
        ((subclass :vtmsgs class :end)
         (format stream "};~2%"))))))
 
     (add-output-hooks method reason sequencer)))
 
 (defmethod add-output-hooks progn
-    ((method effective-method) (reason (eql 'populate-vtmsgs)) sequencer)
-  (let* ((message (effective-method-message method))
+    ((entry method-entry) (reason (eql 'populate-vtmsgs)) sequencer)
+  (let* ((method (method-entry-effective-method entry))
+        (message (effective-method-message method))
         (class (effective-method-class method))
-        (class-type (find-class-type (sod-class-name class)))
-        (raw-type (sod-message-type message))
-        (type (c-type (* (fun (lisp (c-type-subtype raw-type))
-                              ("/*me*/" (* (lisp class-type)))
-                              . (commentify-argument-names
-                                 (c-function-arguments raw-type)))))))
+        (type (method-entry-function-type entry))
+        (commented-type (commentify-function-type type)))
     (sequence-output (stream sequencer)
       ((class :vtmsgs (sod-message-class message) :slots)
        (pprint-logical-block (stream nil :prefix "  " :suffix ";")
-        (pprint-c-type type stream (sod-message-name message)))
+        (pprint-c-type commented-type stream (sod-message-name message)))
        (terpri stream)))))
 
 (defmethod add-output-hooks progn
index 92489dd..cda6bcf 100644 (file)
@@ -1,60 +1,60 @@
 (set-dispatch-macro-character #\# #\{ 'c-fragment-reader)
 
-(progn
-  (clear-the-decks)
-
-  (define-sod-class "Animal" ("SodObject")
-    :nick 'nml
-    :link '|SodObject|
-    (slot "tickles" int)
-    (instance-initializer "nml" "tickles" :single #{ 0 })
-    (message "tickle" (fun void))
-    (method "nml" "tickle" (fun void) #{
-       me->tickles++;
-     }
-     :role :before)
-    (method "nml" "tickle" (fun void) #{ }))
-
-  (define-sod-class "Lion" ("Animal")
-    :nick 'lion
-    :link '|Animal|
-    (message "bite" (fun void))
-    (method "lion" "bite" (fun void) nil)
-    (method "nml" "tickle" (fun void) #{
-       me->_vt->lion.bite(me);
-       CALL_NEXT_METHOD;
-     }))
-
-  (define-sod-class "Goat" ("Animal")
-    :nick 'goat
-    (message "butt" (fun void))
-    (method "goat" "butt" (fun void) nil)
-    (method "nml" "tickle" (fun void) #{
-       me->_vt->goat.bite(me);
-       CALL_NEXT_METHOD;
-     }))
-
-  (define-sod-class "Serpent" ("Animal")
-    :nick 'serpent
-    (message "bite" (fun void))
-    (method "serpent" "bite" (fun void) nil)
-    (message "hiss" (fun void))
-    (method "serpent" "hiss" (fun void) nil)
-    (method "nml" "tickle" (fun void) #{
-       if (me->tickles < 3) me->_vt->hiss(me);
-       else me->_vt->bite(me);
-       CALL_NEXT_METHOD;
-     }))
-
-  (define-sod-class "Chimaera" ("Lion" "Goat" "Serpent")
-    :nick 'sir
-    :link '|Lion|)
-
-  (defparameter *chimaera* (find-sod-class "Chimaera"))
-  (defparameter *emeth* (find "tickle"
-                             (sod-class-effective-methods *chimaera*)
-                             :key (lambda (method)
-                                    (sod-message-name
-                                     (effective-method-message method)))
-                             :test #'string=)))
+(defparameter *chimaera-module*
+  (define-module ("chimaera.sod")
+
+    (define-sod-class "Animal" ("SodObject")
+      :nick 'nml
+      :link '|SodObject|
+      (slot "tickles" int)
+      (instance-initializer "nml" "tickles" :single #{ 0 })
+      (message "tickle" (fun void))
+      (method "nml" "tickle" (fun void) #{
+        me->tickles++;
+       }
+       :role :before)
+      (method "nml" "tickle" (fun void) #{ }))
+
+    (define-sod-class "Lion" ("Animal")
+      :nick 'lion
+      :link '|Animal|
+      (message "bite" (fun void))
+      (method "lion" "bite" (fun void) nil)
+      (method "nml" "tickle" (fun void) #{
+        me->_vt->lion.bite(me);
+        CALL_NEXT_METHOD;
+       }))
+
+    (define-sod-class "Goat" ("Animal")
+      :nick 'goat
+      (message "butt" (fun void))
+      (method "goat" "butt" (fun void) nil)
+      (method "nml" "tickle" (fun void) #{
+        me->_vt->goat.bite(me);
+        CALL_NEXT_METHOD;
+       }))
+
+    (define-sod-class "Serpent" ("Animal")
+      :nick 'serpent
+      (message "bite" (fun void))
+      (method "serpent" "bite" (fun void) nil)
+      (message "hiss" (fun void))
+      (method "serpent" "hiss" (fun void) nil)
+      (method "nml" "tickle" (fun void) #{
+        if (me->tickles < 3) me->_vt->hiss(me);
+        else me->_vt->bite(me);
+        CALL_NEXT_METHOD;
+       }))
+
+    (define-sod-class "Chimaera" ("Lion" "Goat" "Serpent")
+      :nick 'sir
+      :link '|Lion|)
+
+    (defparameter *chimaera* (find-sod-class "Chimaera"))
+    (defparameter *emeth* (find "tickle"
+                               (sod-class-effective-methods *chimaera*)
+                               :key (lambda (method)
+                                      (sod-message-name
+                                       (effective-method-message method)))
+                               :test #'string=))))
 
index 1583b11..2d1c4de 100644 (file)
--- a/lex.lisp
+++ b/lex.lisp
    "struct" "union" "enum"))
 
 (defclass sod-lexer (lexer)
-  ((keywords :initarg :keywords :initform *sod-keywords*
-            :type hash-table :reader lexer-keywords))
+  ()
   (:documentation
    "Lexical analyser for the SOD lanuage.
 
                                           (char= ch #\_))))
                          (return))))))
 
-           ;; Check to see whether we match any keywords.
-           (multiple-value-bind (keyword foundp) (gethash id keywords)
-             (return (values (if foundp keyword :id) id)))))
+           ;; Done.
+           (return (values :id id))))
 
         ;; Pick out numbers.  Currently only integers, but we support
         ;; multiple bases.
index 0fbb3f0..67033da 100644 (file)
@@ -42,7 +42,7 @@
    However, an :ELLIPSIS is replaced by an argument of type `va_list', named
    `sod__ap'."))
 
-(defgeneric direct-method-function-type (method)
+(defgeneric sod-method-function-type (method)
   (:documentation
    "Return the C function type for the direct method.
 
@@ -53,7 +53,7 @@
    prepends an appropriate `me' argument to the user-provided argument list.
    Fancy method classes may need to override this behaviour."))
 
-(defgeneric direct-method-next-method-type (method)
+(defgeneric sod-method-next-method-type (method)
   (:documentation
    "Return the C function type for the next-method trampoline.
 
    the right job.  Very fancy subclasses might need to do something
    different."))
 
-(defgeneric direct-method-function-name (method)
+(defgeneric sod-method-function-name (method)
   (:documentation
    "Return the C function name for the direct method."))
 
+(defgeneric method-entry-function-type (entry)
+  (:documentation
+   "Return the C function type for a method entry."))
+
 ;;;--------------------------------------------------------------------------
 ;;; Message classes.
 
                       ("me" (* (class (sod-method-class method))))
                       . (c-function-arguments type))))))
 
-(defmethod direct-method-function-name ((method basic-direct-method))
+(defmethod sod-method-function-name ((method basic-direct-method))
   (with-slots (class role message) method
     (format nil "~A__~@[~(~A~)_~]method_~A__~A" class role
            (sod-class-nickname (sod-message-class message))
 
   (let* ((message (sod-method-message direct-method))
         (class (sod-method-class direct-method))
-        (function (direct-method-function-name direct-method))
+        (function (sod-method-function-name direct-method))
         (arguments (cons (format nil "(~A *)&sod__obj.~A" class
                                  (sod-class-nickname
                                   (sod-class-chain-head class)))
     (codegen-pop-function codegen (temporary-function)
                          (c-type (fun (lisp return-type)
                                       ("me" (* (class super)))
-                                      . arguments))))))
+                                      . arguments)))))
 
 (defun invoke-delegation-chain (codegen target basic-tail chain kernel)
   "Invoke a chain of delegating methods.
   (setf (slot-value method 'functions)
        (compute-method-entry-functions method)))
 
-(defmethod make-method-entry
-    ((method basic-effective-method) (chain-head sod-class))
-  (make-instance 'method-entry :method method :chain-head chain-head))
+(defmethod method-entry-function-type ((entry method-entry))
+  (let* ((method (method-entry-effective-method entry))
+        (message (effective-method-message method))
+        (type (sod-message-type message)))
+    (c-type (fun (lisp (c-type-subtype type))
+                ("me" (* (class (method-entry-chain-tail entry))))
+                . (sod-message-argument-tail message)))))
+
+(defmethod make-method-entry ((method basic-effective-method)
+                             (chain-head sod-class) (chain-tail sod-class))
+  (make-instance 'method-entry
+                :method method
+                :chain-head chain-head
+                :chain-tail chain-tail))
 
 ;;;----- That's all, folks --------------------------------------------------
diff --git a/module-output.lisp b/module-output.lisp
new file mode 100644 (file)
index 0000000..3ec6aee
--- /dev/null
@@ -0,0 +1,126 @@
+;;; -*-lisp-*-
+;;;
+;;; Output handling for modules
+;;;
+;;; (c) 2009 Straylight/Edgeware
+;;;
+
+;;;----- Licensing notice ---------------------------------------------------
+;;;
+;;; This file is part of the Simple Object Definition system.
+;;;
+;;; SOD is free software; you can redistribute it and/or modify
+;;; it under the terms of the GNU General Public License as published by
+;;; the Free Software Foundation; either version 2 of the License, or
+;;; (at your option) any later version.
+;;;
+;;; SOD is distributed in the hope that it will be useful,
+;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;;; GNU General Public License for more details.
+;;;
+;;; You should have received a copy of the GNU General Public License
+;;; along with SOD; if not, write to the Free Software Foundation,
+;;; Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+
+(cl:in-package #:sod)
+
+;;;--------------------------------------------------------------------------
+;;; Utilities.
+
+(defun banner (title output &key (blank-line-p t))
+  (format output "~&/*----- ~A ~A*/~%"
+         title
+         (make-string (- 77 2 5 1 (length title) 1 2)
+                      :initial-element #\-))
+  (when blank-line-p
+    (terpri output)))
+
+(defun guard-name (filename)
+  "Return a sensible inclusion guard name for FILENAME."
+  (with-output-to-string (guard)
+    (let* ((pathname (make-pathname :name (pathname-name filename)
+                                   :type (pathname-type filename)))
+          (name (namestring pathname))
+          (uscore t))
+      (dotimes (i (length name))
+       (let ((ch (char name i)))
+         (cond ((alphanumericp ch)
+                (write-char (char-upcase ch) guard)
+                (setf uscore nil))
+               ((not uscore)
+                (write-char #\_ guard)
+                (setf uscore t))))))))
+
+;;;--------------------------------------------------------------------------
+;;; Driving output.
+
+(defun guess-output-file (module type)
+  (merge-pathnames (make-pathname :type type :case :common)
+                  (module-name module)))
+
+(defun output-module (module reason stream)
+  (let ((sequencer (make-instance 'sequencer)))
+    (add-output-hooks module reason sequencer)
+    (invoke-sequencer-items sequencer stream)))
+
+;;;--------------------------------------------------------------------------
+;;; Main output protocol implementation.
+
+(defmethod add-output-hooks progn ((module module) reason sequencer)
+  (dolist (item (module-items module))
+    (add-output-hooks item reason sequencer)))
+
+;;;--------------------------------------------------------------------------
+;;; Header output.
+
+(defmethod add-output-hooks progn
+    ((module module) (reason (eql :h)) sequencer)
+  (sequence-output (stream sequencer)
+    :constraint (:prologue
+                (:guard :start)
+                (:typedefs :start) :typedefs (:typedefs :end)
+                (:includes :start) :includes (:includes :end)
+                (:classes :start) (:classes :end)
+                (:guard :end)
+                :epilogue)
+
+    (:prologue
+     (format stream "~
+/* -*-c-*-
+ *
+ * Header file generated by SOD for ~A
+ */~2%"
+            (namestring (module-name module))))
+
+    ((:guard :start)
+     (format stream "~
+#ifndef ~A
+#define ~:*~A
+
+#ifdef __cplusplus
+  extern \"C\" {
+#endif~2%"
+            (or (get-property (module-pset module) :guard :id)
+                (guard-name (or (stream-pathname stream)
+                                (guess-output-file module "H"))))))
+    ((:guard :end)
+     (banner "That's all, folks" stream)
+     (format stream "~
+#ifdef __cplusplus
+  }
+#endif
+
+#endif~%"))
+
+    ((:typedefs :start)
+     (banner "Forward type declarations" stream))
+    ((:typedefs :end)
+     (terpri stream))
+
+    ((:includes :start)
+     (banner "External header files" stream))
+    ((:includes :end)
+     (terpri stream))))
+
+;;;----- That's all, folks --------------------------------------------------
index 36b2c85..5d05365 100644 (file)
 ;;;--------------------------------------------------------------------------
 ;;; Module importing.
 
+(defun build-module
+    (name body-func &key (truename (probe-file name)) location)
+  (let ((*module* (make-instance 'module
+                                :name (pathname name)
+                                :state (file-location location)))
+       (*type-map* (make-hash-table :test #'equal)))
+    (module-import *builtin-module*)
+    (when truename
+      (setf (gethash truename *module-map*) *module*))
+    (unwind-protect
+        (progn
+          (funcall body-func)
+          (finalize-module *module*))
+      (when (and truename (not (eq (module-state *module*) t)))
+       (remhash truename *module-map*)))))
+
+(defmacro define-module
+    ((name &key (truename nil truenamep) (location nil locationp))
+     &body body)
+  `(build-module ,name
+                (lambda () ,@body)
+                ,@(and truenamep `(:truename ,truename))
+                ,@(and locationp `(:location ,location))))
+
 (defun read-module (pathname &key (truename (truename pathname)) location)
   "Reads a module.
 
 
   ;; Make a new module.  Be careful to remove the module from the map if we
   ;; didn't succeed in constructing it.
-  (let ((*module* (make-instance 'module
-                                :name pathname
-                                :state (file-location location)))
-       (*type-map* (make-hash-table :test #'equal)))
-    (module-import *builtin-module*)
-    (setf (gethash truename *module-map*) *module*)
-    (unwind-protect
-        (with-open-file (f-stream pathname :direction :input)
-          (let* ((*module* (make-instance 'module :name pathname))
-                 (pai-stream (make-instance 'position-aware-input-stream
-                                            :stream f-stream
-                                            :file pathname))
-                 (lexer (make-instance 'sod-lexer :stream pai-stream)))
-            (with-default-error-location (lexer)
-              (next-char lexer)
-              (next-token lexer)
-              (parse-module lexer *module*)
-              (finalize-module *module*))))
-      (unless (eq (module-state *module*) t)
-       (remhash truename *module-map*)))))
+  (define-module (pathname :location location :truename truename)
+    (let ((*readtable* (copy-readtable)))
+      (with-open-file (f-stream pathname :direction :input)
+       (let* ((pai-stream (make-instance 'position-aware-input-stream
+                                         :stream f-stream
+                                         :file pathname))
+              (lexer (make-instance 'sod-lexer :stream pai-stream)))
+         (with-default-error-location (lexer)
+           (next-char lexer)
+           (next-token lexer)
+           (parse-module lexer *module*)))))))
 
 ;;;--------------------------------------------------------------------------
 ;;; Module parsing protocol.
index 05be7f8..b0df32b 100644 (file)
 ;;;--------------------------------------------------------------------------
 ;;; Utilities.
 
-(defun banner (title output &key (blank-line-p t))
-  (format output "~&~%/*----- ~A ~A*/~%"
-         title
-         (make-string (- 77 2 5 1 (length title) 1 2)
-                      :initial-element #\-))
-  (when blank-line-p
-    (terpri output)))
-
 ;;;--------------------------------------------------------------------------
 ;;; Header output.
 
 #endif~%"
                (namestring (module-name module))
                (or (getf (module-plist module) 'include-guard)
-                   (with-output-to-string (guard)
-                     (let ((name (namestring file))
-                           (uscore t))
-                       (dotimes (i (length name))
-                         (let ((ch (char name i)))
-                           (cond ((alphanumericp ch)
-                                  (write-char (char-upcase ch) guard)
-                                  (setf uscore nil))
-                                 ((not uscore)
-                                  (write-char #\_ guard)
-                                  (setf uscore t)))))))))
+                   ))
 
          ;; Forward declarations of all the structures and types.  Nothing
          ;; interesting gets said here; this is just so that the user code
index d273045..3613965 100644 (file)
 ;;; groups the other three kinds together and calls them all `type
 ;;; specifiers' (6.7.2).
 
+;; Let's not repeat ourselves.
+(macrolet ((define-declaration-specifiers (&rest defs)
+            (let ((mappings nil)
+                  (deftypes nil)
+                  (hashvar (gensym "HASH"))
+                  (keyvar (gensym "KEY"))
+                  (valvar (gensym "VAL")))
+              (dolist (def defs)
+                (destructuring-bind (kind &rest clauses) def
+                  (let ((maps (mapcar (lambda (clause)
+                                        (if (consp clause)
+                                            clause
+                                            (cons (string-downcase clause)
+                                                  clause)))
+                                      clauses)))
+                    (push `(deftype ,(symbolicate 'decl- kind) ()
+                             '(member ,@(mapcar #'cdr maps)))
+                          deftypes)
+                    (setf mappings (nconc (remove-if-not #'car maps)
+                                          mappings)))))
+              `(progn
+                 ,@(nreverse deftypes)
+                 (defparameter *declspec-map*
+                   (let ((,hashvar (make-hash-table :test #'equal)))
+                     (mapc (lambda (,keyvar ,valvar)
+                             (setf (gethash ,keyvar ,hashvar) ,valvar))
+                           ',(mapcar #'car mappings)
+                           ',(mapcar #'cdr mappings))
+                     ,hashvar))))))
+  (define-declaration-specifiers
+    (type :char :int :float :double :void)
+    (size :short :long (nil . :long-long))
+    (sign :signed :unsigned)
+    (qualifier :const :restrict :volatile)
+    (tagged :enum :struct :union)))
+
 (defstruct (declspec
             (:predicate declspecp))
   "Represents a declaration specifier being built."
   (qualifiers nil :type list)
-  (sign nil :type (member nil :signed :unsigned))
-  (size nil :type (member nil :short :long :long-long))
-  (type nil :type (or (member nil :int :char :float :double :void) c-type)))
+  (sign nil :type (or decl-sign null))
+  (size nil :type (or decl-size null))
+  (type nil :type (or decl-type c-type null)))
 
 (defun check-declspec (spec)
   "Check that the declaration specifiers in SPEC are a valid combination.
 
 (defun declaration-specifier-p (lexer)
   "Answer whether the current token might be a declaration specifier."
-  (case (token-type lexer)
-    ((:const :volatile :restrict
-      :signed :unsigned
-      :short :long
-      :void :char :int :float :double
-      :enum :struct :union)
-     t)
-    (:id
-     (gethash (token-value lexer) *type-map*))
-    (t
-     nil)))
+  (and (eq (token-type lexer) :id)
+       (let ((id (token-value lexer)))
+        (or (gethash id *declspec-map*)
+            (gethash id *type-map*)))))
 
 (defun parse-c-type (lexer)
   "Parse declaration specifiers from LEXER and return a C-TYPE."
 
   (let ((spec (make-declspec))
-       (found-any nil))
-    (loop
-      (let ((tok (token-type lexer)))
-       (labels ((update (func value)
-                  (let ((new (funcall func spec value)))
-                    (cond (new (setf spec new))
-                          (t (cerror*
-          "Invalid declaration specifier ~(~A~) after `~{~A~^ ~}' (ignored)"
-                              (format-token tok (token-value lexer))
-                              (declspec-keywords spec t))
-                             nil))))
-                (tagged (class)
-                  (let ((kind tok))
-                    (setf tok (next-token lexer))
-                    (if (eql tok :id)
-                        (when (update #'update-declspec-type
-                                      (make-instance
-                                       class
-                                       :tag (token-value lexer)))
-                          (setf found-any t))
-                        (cerror* "Expected ~(~A~) tag; found ~A"
-                                 kind (format-token lexer))))))
-         (case tok
-           ((:const :volatile :restrict)
-            (update #'update-declspec-qualifiers tok))
-           ((:signed :unsigned)
-            (when (update #'update-declspec-sign tok)
-              (setf found-any t)))
-           ((:short :long)
-            (when (update #'update-declspec-size tok)
-              (setf found-any t)))
-           ((:void :char :int :float :double)
-            (when (update #'update-declspec-type tok)
-              (setf found-any t)))
-           (:enum (tagged 'c-enum-type))
-           (:struct (tagged 'c-struct-type))
-           (:union (tagged 'c-union-type))
-           (:id
-            (let ((ty (gethash (token-value lexer) *type-map*)))
-              (when (or found-any (not ty))
-                (return))
-              (when (update #'update-declspec-type ty)
-                (setf found-any t))))
-           (t
-            (return))))
-       (setf tok (next-token lexer))))
-    (unless found-any
-      (cerror* "Missing type name (guessing at `int')"))
-    (declspec-c-type spec)))
+       (found-any nil)
+       tok)
+    (flet ((token (&optional (ty (next-token lexer)))
+            (setf tok
+                  (or (and (eq ty :id)
+                           (gethash (token-value lexer) *declspec-map*))
+                      ty)))
+          (update (func value)
+            (let ((new (funcall func spec value)))
+              (cond (new (setf spec new))
+                    (t (cerror* "Invalid declaration specifier ~(~A~) ~
+                                 following `~{~A~^ ~}' (ignored)"
+                                (format-token tok (token-value lexer))
+                                (declspec-keywords spec t))
+                       nil)))))
+      (token (token-type lexer))
+      (loop
+       (typecase tok
+         (decl-qualifier (update #'update-declspec-qualifiers tok))
+         (decl-sign (when (update #'update-declspec-sign tok)
+                      (setf found-any t)))
+         (decl-size (when (update #'update-declspec-size tok)
+                      (setf found-any t)))
+         (decl-type (when (update #'update-declspec-type tok)
+                      (setf found-any t)))
+         (decl-tagged (let ((class (ecase tok
+                                     (:enum 'c-enum-type)
+                                     (:struct 'c-struct-type)
+                                     (:union 'c-union-type))))
+                        (let ((tag (require-token lexer :id)))
+                          (when tag
+                            (update #'update-declspec-type
+                                    (make-instance class :tag tag))))))
+         ((eql :id) (let ((ty (gethash (token-value lexer) *type-map*)))
+                      (when (or found-any (not ty))
+                        (return))
+                      (when (update #'update-declspec-type ty)
+                        (setf found-any t))))
+         (t (return)))
+       (token))
+      (unless found-any
+       (cerror* "Missing type name (guessing at `int')"))
+      (declspec-c-type spec))))
 
 ;;;--------------------------------------------------------------------------
 ;;; Parsing declarators.
 (with-input-from-string (in "
 //  int stat(struct stat *st)
 //  void foo(void)
-//  int vsnprintf(size_t n, char *buf, va_list ap)
+  int vsnprintf(size_t n, char *buf, va_list ap)
 //  size_t size_t;
 //  int (*signal(int sig, int (*handler)(int s)))(int t)
 ")
   (let* ((stream (make-instance 'position-aware-input-stream
                                :file "<string>"
                                :stream in))
-        (lex (make-instance 'sod-lexer :stream stream
-                            :keywords *sod-keywords*)))
+        (lex (make-instance 'sod-lexer :stream stream)))
     (next-char lex)
     (next-token lex)
     (let ((ty (parse-c-type lex)))
diff --git a/sod.c b/sod.c
index ad20974..24a6429 100644 (file)
--- a/sod.c
+++ b/sod.c
@@ -26,7 +26,7 @@
 
 /*----- Header files ------------------------------------------------------*/
 
-#include <sod.h>
+#include "sod.h"
 
 /*----- Main code ---------------------------------------------------------*/
 
@@ -60,7 +60,7 @@ static const struct sod_chain *find_chain(const SodClass *sub,
    * and we're done.  Otherwise it isn't, and we lose.  We also lose if no
    * matching chain is found.
    */
-  for (chain = sub->cls.chains, lim = chain + sub->cls.n_chains;
+  for (chain = sub->cls.chains, limit = chain + sub->cls.n_chains;
        chain < limit; chain++) {
     if (chain->classes[0] != head)
       continue;
diff --git a/sod.h b/sod.h
index 9fa972d..cb56244 100644 (file)
--- a/sod.h
+++ b/sod.h
@@ -36,7 +36,7 @@
 #include <stdarg.h>
 #include <stddef.h>
 
-#include <sod-base.h>
+#include "sod-base.h"
 
 /*----- Data structures ---------------------------------------------------*/