コマンド ライン引数の解析 - 2022.1 日本語

Vivado Design Suite ユーザー ガイド: Tcl スクリプト機能の使用 (UG894)

Document ID
UG894
Release Date
2022-06-08
Version
2022.1 日本語

外部パラメーターまたは引数を使用するプロシージャを記述すると、プロシージャの使用範囲が広がり、無駄なコードを記述する必要性を軽減できます。1 つのプロシージャで複数のコンテキストを処理できるようにすると、重複したコードを含む複数のプロシージャと同じ範囲のコンテキストを 1 つのプロシージャで網羅でき、使用および管理が簡単になります。

これは、プロシージャをインタラクティブに使用する場合に特に有益です。一部のコマンド ライン オプションをほかの Vivado コマンドと同じように指定できると、ユーザーにとって便利です。

Tcl では、これを args 変数を使用して簡単に適用できます。プロシージャの引数リスト内で使用される args キーワードは、任意の数の要素 (0 を含む) を示します。args 変数は、ほかの Tcl リストと同様に処理および解析可能な Tcl リストです。

コマンド ライン引数を解析する方法は複数あります。次に、その 1 つの例を示します。

01 proc lshift listVar {
02   upvar 1 $listVar L
03   set r [lindex $L 0]
04   set L [lreplace $L [set L 0] 0]
05   return $r
06 }
07 
08 
09 proc myproc { args } {
10 
11  #-------------------------------------------------------
12  # Process command line arguments
13  #-------------------------------------------------------
14  set error 0
15  set help 0
16  set verbose 0
17  set ports {}
18  # if {[llength $args] == 0} { incr help }; # Uncomment if necessary
19  while {[llength $args]} {
20   set flag [lshift args]
21   switch -exact -- $flag {
22    -p -
23    -ports {
24       set ports [lshift args]
25    }
26    -v -
27    -verbose {
28       set verbose 1
29    }
30    -h -
31    -help {
32       incr help
33    }
34    default {
35       if {[string match "-*" $flag]} {
36        puts " ERROR - option '$flag' is not a valid option."
37        incr error
38       } else {
39        puts "ERROR - option '$flag' is not a valid option."
40        incr error
41       }
42    }
43   }
44  }
45 
46  if {$help} {
47   set callerflag [lindex [info level [expr [info level] -1]] 0]
48   # <-- HELP
49   puts [format {
50  Usage: %s
51        [-ports|-p <listOfPorts>]
52        [-verbose|-v]
53        [-help|-h]
54 
55  Description: xxxxxxxxxxxxxxxxxxx.
56         xxxxxxxxxxxxxxxxxxx.
57 
58  Example:
59    %s -port xxxxxxxxxxxxxxx
60 
61 } $callerflag $callerflag ]
62   # HELP -->
63   return -code ok {}
64  }
65 
66  # Check validity of arguments. Increment $error to generate an error
67 
68  if {$error} {
69   return -code error {Oops, something is not correct}
70  }
71 
72  # Do something
73 
74  return -code ok {}
75 }

説明:

  1. 行 1 ~ 6: リストの最初の要素を削除するプロシージャ lshift を定義します。
  2. 行 9: 複数の要素を指定可能な 1 つの引数 myproc を使用する args を定義します。このコード例では、myproc は、-ports < string >-verbose-help の 3 つのコマンド ライン オプションをサポートします。
  3. 行 19 ~ 44: すべてのコマンド ライン引数をループします。すべての引数が処理されると、args 変数は空になります。
  4. 行 20: 処理が必要なコマンド ライン引数を flag 変数に保存します。lshift プロシージャを使用して、args 変数から引数を取得および削除します。
  5. 行 21 ~ 43: flag 変数の内容を、有効なすべての引数に対してチェックします。switch 文には -exact オプションが使用されており、flag の内容が完全なオプション名に対してチェックされます。たとえば、ポートを定義するには、-p または -ports を指定する必要があります。

    -p/-ports オプションではコマンド ライン引数が指定され、lshift args (行 24) により読み出され、削除されます。

    -v/-verbose オプションはブール値で、args からの引数は必要ありません (行 28)。

    行 31 ~33: -h/-help オプションをチェックします。

    行 36 ~38:「-」で開始するすべてのコマンド ライン引数をチェックします。このプロシージャ例では、サポートされません。

    行 39 ~40:「-」で開始しないすべてのコマンド ライン引数をチェックします。このプロシージャ例では、サポートされません。

  6. 行 46 ~64:-h/-help が指定されている場合に、組み込まれているヘルプ情報を表示します。プロシージャにヘルプ情報を組み込む必要がない場合は、これらの行と行 30 ~ 33 は削除できます。
  7. 行 68 ~70:エラーが発生していないかをチェックします。通常、引数が有効であるかをチェックする追加コードは、行 68 より前に記述する必要があります。指定されたコマンド ライン オプションが互換していないなど、エラーが発生している場合は、error 変数がインクリメントされ、行 69 が実行されます。
  8. 行 73 以降: コードを追加します。

上記のコードはコマンド ライン引数を解析し、サポートされているオプションと完全に一致しているかを調べていますが (行 21)、コマンド ライン引数が完全に一致しているかを調べるよりも、条件式に一致しているかを調べる方が有益な場合もあります。これには、行 21 で -glob オプションの代わりに -exact オプションを使用します。次に例を示します。

21 switch -glob -- $flag {
22    -p* -
23    -ports {
24       set ports [lshift args]
25    }
26    -v* -
27    -verbose {
28       set verbose 1
29    }
30    -h* -
31    -help {
32       incr help
33    }
34    default {
35       if {[string match "-*" $flag]} {
36        puts " ERROR - option '$flag' is not a valid option."
37        incr error
38       } else {
39        puts "ERROR - option '$flag' is not a valid option."
40        incr error
41       }
42    }
43 }

行 22、26、および 30 では、ワイルドカードとしてアスタリスク (*) が使用されています。この場合、-pfoo など、-p で開始するすべての文字列が、ポートを定義する有効なコマンド ライン オプションとなります。

上記のプロシージャ例 myproc はインタラクティブ コマンドとして機能しますが、引数の解析のためランタイム オーバーヘッドがあります。何回も呼び出される下位プロシージャでは、ランタイム オーバーヘッドが問題となることがあります。プロシージャにコマンド ライン引数を追加するのに別の方法を使用して、ランタイム オーバーヘッドを削減できます。これには、Tcl 配列にコマンド ライン引数のリストを割り当てます。ただし、各コマンド ライン オプションに 1 つの引数しか使用できません。次に例を示します。

01 proc myproc2 { args } {
02  # Default values
03  set defaults [list -p 123 -v 0]
04  # First, assign default values
05  array set options $defaults
06  # Then, override with user choice
07  array set options $args
08 
09  set ports $options(-p)
10  set verbose $options(-v)
11  set error 0
12  
13  # Check validity of arguments. Increment $error to generate an error
14 
15  if {$error} {
16   return -code error {Oops, something is not correct}
17  }
18  
19  # Do something
20 
21  return -code ok {}
22 }

説明

  1. 行 1: 複数の要素を指定可能な 1 つの引数 myproc2 を使用する args を定義します。args は後ほど Tcl 配列を設定するのに使用されるので、引数の数は偶数にする必要があります。
  2. 行 3: さまざまなオプションのデフォルト値を指定します。各オプションには、1 つの引数のみ指定できます。
  3. リストのフォーマットは、次のとおりです。
    expanse="page">  <option1> <valueForOption1> <option2> <valueForOption2> … <optionN> <valueForOptionN> 
  4. 行 5: Tcl 配列 options をデフォルト値で初期化します。
  5. 行 7: args 変数の値でデフォルト値を置き換えます。
  6. 行 9 ~ 10: 各オプションの値を $options(<option>) で読み出します。次のコードを使用して、オプションが存在するかをチェックすることも可能です。
    if [info exists options(<option>)] { … }
    注記: フラグとして機能する値のないコマンド ライン オプションは、0 または 1 などの値を渡すことにより簡単にインプリメントできます。上記のプロシージャ例では、フラグ -v は「myproc2 -v 1」を使用してオンにできます。