[Top][All Lists]

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

fspec2c 1.0

From: Thien-Thi Nguyen
Subject: fspec2c 1.0
Date: Tue, 04 Nov 2003 03:11:01 +0100

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.


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
;; 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 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)
              (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)
                    (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))
             (format op "struct ~A {" (or (spec #:struct-name)
             (for-each (lambda (x)
                         (for-each (lambda (xx)
                                     (format op " ~A" xx))
                                   (cdr x))
                         (format op ";"))
             (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))
      (cond ((spec #:post-boilerplate)
             => (lambda (x)
                  (display "%%\n" op)
                  (display (symbol->string x) op))))
      (or (eq? op (current-output-port))
          (close-port op)))

(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

reply via email to

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