[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

c2x that handles multiple SCM__I

From: Thien-Thi Nguyen
Subject: c2x that handles multiple SCM__I
Date: Thu, 30 Oct 2003 21:19:32 +0100

first a little background: c2x (and the version of guile-snarf upon
which the older c2x was modeled) uses the C preprocessor to extract and
format certain parts of macros (e.g., `SCM_DEFINE' and `SCM_SYMBOL')
defined in libguile/snarf.h[1].  on occaision you may wish to compose a
macro that uses the same underlying macros but tuned for your particular
needs, for example (from guile-sdl work-in-progress):

#define SCM_DEFINE_CONST(schemename,csymvalue) \
SCM_SYMBOL (scm_ ## csymvalue, schemename) \
; \
 scm_variable_set (scm_ ## csymvalue, SCM_MAKINUM (csymvalue))\

this composition combines a pre-existing high-level macro SCM_SYMBOL
with a semicolon with a new SCM_SNARF_INIT macro.  if you examine
SCM_SYMBOL you see it is made of a SCM_SNARF_HERE and SCM_SNARF_INIT as
well, so it would be reasonable to consider SCM_DEFINE_CONST as the more
fundamental sequence: SCM_SNARF_HERE, SCM_SNARF_INIT, semicolon,
SCM_SNARF_INIT.  no problem, right?

well unfortunately, the C preprocessor is free to discard non-string
newlines, which means the SCM_DEFINE_CONST expansion which c2x sees is
on one line, which means in our example the SCM__I token that the
SCM_SNARF_INIT macro inserts for the benefit of c2x, occurs more than
once.  the result is that current c2x does not handle these so-called
"chained" SCM_SNARF_INIT expansions.

all this is to explain the rationale for the fixed c2x (to appear in
guile, below, which handles chained SCM_SNARF_INIT forms, as
long as they are properly separated by a semicolon.



exec ${GUILE-guile} -e '(scripts c2x)' -s $0 "$@" # -*- scheme -*-
;;; c2x --- Extract initialization code from .c files

;;      Copyright (C) 2003 Free Software Foundation, Inc.
;; This program 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, or
;; (at your option) any later version.
;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; General Public License for more details.
;; You should have received a copy of the GNU General Public License
;; along with this software; see the file COPYING.  If not, write to
;; the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
;; Boston, MA 02111-1307 USA
;; As a special exception, the Free Software Foundation gives permission
;; for additional uses of the text contained in its release of GUILE.
;; The exception is that, if you link the GUILE library with other files
;; to produce an executable, this does not by itself cause the
;; resulting executable to be covered by the GNU General Public License.
;; Your use of that executable is in no way restricted on account of
;; linking the GUILE library code into it.
;; This exception does not however invalidate any other reasons why
;; the executable file might be covered by the GNU General Public License.
;; This exception applies only to the code released by the
;; Free Software Foundation under the name GUILE.  If you copy
;; code from other Free Software Foundation releases into a copy of
;; GUILE, as the General Public License permits, the exception does
;; not apply to the code that you add in this way.  To avoid misleading
;; anyone as to the status of such modified files, you must delete
;; this exception notice from them.
;; If you write modifications of your own for GUILE, it is your choice
;; whether to permit this exception to apply to your modifications.
;; If you do not wish that, delete this exception notice.

;;; Author: Thien-Thi Nguyen <address@hidden>

;;; Commentary:

;; Usage: c2x [-o OUTFILE] [CPP-ARGS ...]
;; Process CPP-ARGS using the C pre-processor and some other programs.
;; Write output to a file named OUTFILE or to the standard output when no
;; OUTFILE has been specified or when OUTFILE is "-".  CPP-ARGS should
;; include an input filename.
;; If there are errors during processing, delete OUTFILE and exit with
;; non-zero status.
;; During snarfing, the pre-processor macro SCM_MAGIC_SNARFER is defined.
;; Also, c2x passes "-I GUILE-INCLUDE-DIR" to the pre-processor, where
;; GUILE-INCLUDE-DIR is the directory Guile's header files are installed.
;; (You can display this value with the command "guile-tools guile-config
;; info includedir".)
;; If env var CPP is set, use its value instead of the C pre-processor
;; determined at Guile configure-time.  (You can display this value with
;; the command "guile-tools guile-config acsubst CPP".)

;;; Code:

(define-module (scripts c2x)
  #:autoload (scripts PROGRAM) (HVQC-MAIN)
  #:autoload (scripts guile-config-data) (guile-config-data)
  #:autoload (ice-9 regex) (match:substring match:suffix)
  #:autoload (ice-9 rdelim) (read-line write-line)
  #:autoload (ice-9 popen) (open-input-pipe)
  ;; not yet
  ;; #:export (c2x)

(define (jaminc)
  (format #f "-I ~A " (assq-ref %guile-build-info 'includedir)))
;;(define (jaminc) "")                    ; mask-zonk on install

(define (snarf-cmd args)
  (format #f "~A -DSCM_MAGIC_SNARFER ~A~A"
          (or (getenv "CPP")
              (assq-ref guile-config-data 'CPP))
          (apply string-append
                 (map (lambda (s)
                        (format #f "~S " s))

(define init-rx (make-regexp "^ *SCM__I"))
(define more-rx (make-regexp "; *SCM__I"))
(define doc-rx  (make-regexp " *SCM__D"))

(define (snarf! outp args good! bad!)
  (let* ((inp (open-input-pipe (snarf-cmd args)))
         (next (lambda () (read-line inp)))
         (acc (list 0)))                ;-( nothing is real ;-)
    (cond ((let loop ((line (next)) (tp acc))
             (cond ((eof-object? line)
                    (= 0 (status:exit-val (close-pipe inp))))
                   ((regexp-exec init-rx line)
                    => (lambda (m)
                         (let ((look (match:suffix m)))
                            ;; also handle chained (not at bol) SCM__I
                            ((and=> (regexp-exec more-rx look)
                                    (lambda (mm) (1+ (match:start mm 0))))
                             => (lambda (split)
                                  (set-cdr! tp (list (substring look 0 split)))
                                  (loop (substring look split)
                                        (cdr tp))))
                             (set-cdr! tp (list (match:suffix m)))
                             (loop (next) (cdr tp)))))))
                   (else (loop (next) tp))))
           (for-each (lambda (line)
                        (cond ((regexp-exec doc-rx line) => match:prefix)
                              (else line))
                     (cdr acc))         ;-( ignore nothing! ;-)

(define (c2x/main args)
  (let* ((count (length args))
         ;; Do arg processing "manually" (avoiding qop and even getopt-long)
         ;; since the majority of the args are destined to be passed to cpp.
         (has-minus-o? (and (> count 3) (string=? "-o" (cadr args))))
         (outfile (if has-minus-o?
                      (caddr args)
         (cpp-args (if has-minus-o?
                       (cdddr args)
                       (cdr args))))
    (snarf! (if (string=? "-" outfile)
                ;; Ensure something non-empty is in the output file before the
                ;; snarfing begins, since the C file typically does #include
                ;; "OUTFILE", and might not properly guard against circular
                ;; dependency.  (Non-emtpy because file existence alone is
                ;; insufficient for some old pre-processors.)
                (let ((outp (open-output-file outfile)))
                  (format outp "/* greetings from c2x! */\n")
                  (close-port outp)
                  (open-file outfile "a")))
            (lambda () #t)
            (lambda () (or (string=? "-" outfile)
                           (delete-file outfile))

(define (main args)
  (HVQC-MAIN args c2x/main
             '(usage . commentary)
             '(package . "Guile")))     ; see "manually" comment in c2x/main

;;; c2x ends here

reply via email to

[Prev in Thread] Current Thread [Next in Thread]