fspec2c 1.0

Thien-Thi Nguyen <[email protected]>
Newsgroups gmane.lisp.guile.user,gmane.lisp.guile.sources
Message-ID <[email protected]>
this may make it into the guile 1.4.x scripts collection if i can
generalize it enough.  "flag"-specific because enum values tend to be
linear so simpler methods are indicated for reverse-mapping them.  at
least, this is true for /usr/include/SDL/*.h enums and flags.  who knows
for other header domains?  what a mess, the terminology of programmers!

if any gperf hackers are reading this: thanks for writing gperf.
it was worth installing g++ to compile 3.0.1, for "--output-file".

i will post a sample FSPEC file next.

thi


______________________________________________________________________________
#!/bin/sh
exec ${GUILE-guile} -e "(guile-sdl scripts fspec2c)" -s $0 "$@" # -*-scheme-*-
!#
;;; fspec2c --- translate flag spec to C code

;;	Copyright (C) 2003 Thien-Thi Nguyen
;;
;; 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
;; 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 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

;;; Commentary:

;; Usage: fspec2c [OPTIONS] FSPEC
;;
;; Write C fragment to stdout derived from running gperf (GNU perfect hash
;; function generator) on the flags mined from the header as specified in
;; FSPEC.  OPTIONS are zero or more of:
;;
;;  -o, --output FILE    -- write to FILE instead of stdout
;;  -I, --include DIR    -- look in DIR instead of /usr/include
;;  -n, --no-cgen        -- write generated gperf input instead
;;                          of actually sending it to gperf
;;
;; The FSPEC file contents is a Scheme list with alternating keyword and data
;; elements.  Currently, these keywords are recognized:
;;
;;  #:infile RELPATH     -- which header to scan (string)
;;  #:regexp REGEXP      -- regexp w/ at least one subexpression (string)
;;  #:key-match-num NUM  -- which subexpression is the key
;;  #:struct SPEC        -- struct-member specifiers (list, see below)
;;  #:struct-name NAME   -- for "struct NAME { ... }" (string)
;;  #:gperf-options OPT  -- additional options for gperf (string)
;;  #:pre-boilerplate S  -- gperf "%{ ... %}" declarations (symbol, see below)
;;  #:post-boilerplate S -- direct C inclusion (symbol, see below)
;;
;; SPEC is a list of struct-member specifiers, each a list of the form:
;;
;;   (MATCH C-TYPE-COMPONENT-1 [C-TYPE-COMPONENT-2 ...] C-VAR-NAME)
;;
;; MATCH can be a number to specify a subexpression of REGEXP to use for
;; static-data initialization, or #f to indicate no initialization.  Per info
;; node "(gperf)User-supplied Struct", the first element of SPEC must be:
;;
;;   (1 char * name)
;;
;; This restriction may be lifted in the future, as fspec2c is enhanced to
;; interoperate better with those features of gperf that allow customization
;; of this struct element.
;;
;; The #:pre-boilerplate and #:post-boilerplate data elements are symbols
;; rather than strings, in order to minimize quoting headaches.  Such symbols
;; have the syntax: #{ TEXT }# where TEXT can include anything (including
;; spaces, newlines, and quote characters) except the closing curly-brace-hash
;; token.  Boilerplate text is passed straight-through by both fspec2c and
;; gperf; errors in the code will only be flagged during compilation.

;;; Code:

(define-module (guile-sdl scripts fspec2c)
  #:use-module (scripts PROGRAM)
  #:use-module (ice-9 rdelim)
  #:use-module (ice-9 regex)
  #:autoload (ice-9 popen) (open-output-pipe))

(define (fspec2c/qop qop)
  (let* ((info (read (open-input-file
                      (let ((args (qop '())))
                        (or (and (pair? args) (car args))
                            (error "no input specified"))))))
         (spec (lambda (kw) (and=> (memq kw info) cadr)))
         (gperf-input '()))
    (let* ((p (open-input-file (in-vicinity
                                (or (qop 'include) "/usr/include")
                                (spec #:infile))))
           (rx (make-regexp (spec #:regexp))))
      (let loop ((line (read-line p)))
        (or (eof-object? line)
            (begin
              (cond ((regexp-exec rx line)
                     => (lambda (m)
                          (set! gperf-input (cons m gperf-input)))))
              (loop (read-line p)))))
      (close-port p))
    ;; feed gperf (unless --no-cgen)
    (let* ((kw-num (spec #:key-match-num))
           (struct (or (spec #:struct) '()))
           (op (if (qop 'no-cgen)
                   (or (qop 'output open-output-file)
                       (current-output-port))
                   (open-output-pipe
                    (format #f "gperf~A~A --output-file=~A"
                            (if (null? struct) "" " -t")
                            (cond ((spec #:gperf-options)
                                   => (lambda (o) (format #f " ~A" o)))
                                  (else ""))
                            (or (qop 'output) "-"))))))
      (cond ((spec #:pre-boilerplate)
             => (lambda (x)
                  (display "%{\n" op)
                  (display (symbol->string x) op)
                  (display "\n%}\n" op))))
      (cond ((null? struct))
            (else
             (format op "struct ~A {" (or (spec #:struct-name)
                                          "randomstructname"))
             (for-each (lambda (x)
                         (for-each (lambda (xx)
                                     (format op " ~A" xx))
                                   (cdr x))
                         (format op ";"))
                       struct)
             (format op " };\n%%\n")))
      (for-each (lambda (m)
                  (display (match:substring m kw-num) op)
                  (for-each (lambda (x)
                              (and=> (car x)
                                     (lambda (num)
                                       (format op ", ~A"
                                               (match:substring m num)))))
                            ;; 1st fixed; see "(gperf)User-supplied Struct"
                            (cdr struct))
                  (newline op))
                gperf-input)
      (cond ((spec #:post-boilerplate)
             => (lambda (x)
                  (display "%%\n" op)
                  (display (symbol->string x) op))))
      (or (eq? op (current-output-port))
          (close-port op)))
    #t))

(define (main args)
  (HVQC-MAIN args fspec2c/qop
             '(usage . commentary)
             '(package . "guile-sdl")
             '(version . "1.0")
             '(option-spec (output  (single-char #\o) (value #t))
                           (include (single-char #\I) (value #t))
                           (no-cgen (single-char #\n)))))

;;; fspec2c ends here


_______________________________________________
Guile-user mailing list
[email protected]
http://mail.gnu.org/mailman/listinfo/guile-user
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.