コマンドライン引数を解析する


Tags: R5RS, R6RS, プログラム, SRFI, SLIB, Gauche, stub

例として imake(1) コマンドの引数を解析する場合を考える。

SRFI 37

SRFI 37 では解析時の状態を手続きの引数で持ち回る形式を取る。多値と手続きを用い副作用なく記述できるという利点がある反面、やや冗長になりやすい傾向がある。

(import (rnrs) (srfi :37))

(let-values
    (([cpp-options
       template-name
       input-file-name
       c-file-name
       makefile-name
       execute?
       verbose?]
      (args-fold (cdr (command-line))
                 (list
                  (option '(#\D) #t #f
                          (lambda (opt name arg cpp-opts tfn ifn cfn mfn e? v?)
                            (values (cons* arg (string #\- name) cpp-opts)
                                    tfn ifn cfn mfn e? v?)))
                  (option '(#\I) #t #f
                          (lambda (opt name arg cpp-opts tfn ifn cfn mfn e? v?)
                            (values (cons* arg (string #\- name) cpp-opts)
                                    tfn ifn cfn mfn e? v?)))
                  (option '(#\U) #t #f
                          (lambda (opt name arg cpp-opts tfn ifn cfn mfn e? v?)
                            (values (cons* arg (string #\- name) cpp-opts)
                                    tfn ifn cfn mfn e? v?)))
                  (option '(#\T) #t #f
                          (lambda (opt name arg cpp-opts tfn ifn cfn mfn e? v?)
                            (values cpp-opts arg ifn cfn mfn e? v?)))
                  (option '(#\f) #t #f
                          (lambda (opt name arg cpp-opts tfn ifn cfn mfn e? v?)
                            (values cpp-opts tfn arg cfn mfn e? v?)))
                  (option '(#\C) #t #f
                          (lambda (opt name arg cpp-opts tfn ifn cfn mfn e? v?)
                            (values cpp-opts tfn ifn arg mfn e? v?)))
                  (option '(#\s) #t #f
                          (lambda (opt name arg cpp-opts tfn ifn cfn mfn e? v?)
                            (values cpp-opts tfn ifn cfn arg e? v?)))
                  (option '(#\e) #f #f
                          (lambda (opt name arg cpp-opts tfn ifn cfn mfn e? v?)
                            (values cpp-opts tfn ifn cfn mfn #t v?)))
                  (option '(#\v) #f #f
                          (lambda (opt name arg cpp-opts tfn ifn cfn mfn e? v?)
                            (values cpp-opts tfn ifn cfn mfn e? #t)))
                  )
                 (lambda (opt name arg . _)
                   (error 'parse-option "unrecognized option" name))
                 (lambda (arg . _)
                   (error 'parse-option "superfluous argument" arg))
                 '() "Imake.tmpl" "Imakefile" "Imakefile.c" "Makefile" #f #f)))
  (display "options to cpp: ")
  (display (reverse cpp-options))
  (display "\nthe name of master template file: ")
  (display template-name)
  (display "\nthe name of input file: ")
  (display input-file-name)
  (display "\nthe name of .c file: ")
  (display c-file-name)
  (display "\nthe name of makefile: ")
  (display makefile-name)
  (display "\nexecute: ")
  (display execute?)
  (display "\nverbose: ")
  (display verbose?)
  (newline))

(exit)

SLIB

Gauche

Gauche では gauche.parseopt モジュールにより、典型的なコマンドライン引数の解析を簡潔に記述できる。

(use gauche.parseopt)

(let ((cpp-options '()))
  (let-args *argv*
      ((#f "D=s" => (lambda (arg)
                      (push! cpp-options (format "-D~A" arg))))
       (#f "I=s" => (lambda (arg)
                      (push! cpp-options (format "-I~A" arg))))
       (#f "U=s" => (lambda (arg)
                      (push! cpp-options (format "-U~A" arg))))
       (template-name   "T=s" "Imake.tmpl")
       (input-file-name "f=s" "Imakefile")
       (c-file-name     "C=s" "Imakefile.c")
       (makefile-name   "s=s" "Makefile")
       (execute? "e")
       (verbose? "v")
       (else (opt . _) (error "Unknown option: " opt))
       . rest)
    (unless (null? rest)
      (error "superfluous arguments: "  rest))
    (format #t "options to cpp: ~A
the name of master template file: ~A
the name of input file: ~A
the name of .c file: ~A
the name of makefile: ~A
execute: ~A
verbose: ~A~%"
            (reverse cpp-options)
            template-name input-file-name c-file-name makefile-name
            execute? verbose?)))

(exit)