外部パラメーターまたは引数を使用するプロシージャを記述すると、プロシージャの使用範囲が広がり、無駄なコードを記述する必要性を軽減できます。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 ~ 6: リストの最初の要素を削除するプロシージャ
lshift
を定義します。 - 行 9: 複数の要素を指定可能な 1 つの引数
myproc
を使用するargs
を定義します。このコード例では、myproc
は、-ports <
string
>
、-verbose
、-help
の 3 つのコマンド ライン オプションをサポートします。 - 行 19 ~ 44: すべてのコマンド ライン引数をループします。すべての引数が処理されると、
args
変数は空になります。 - 行 20: 処理が必要なコマンド ライン引数を
flag
変数に保存します。lshift
プロシージャを使用して、args
変数から引数を取得および削除します。 - 行 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:「-」で開始しないすべてのコマンド ライン引数をチェックします。このプロシージャ例では、サポートされません。
- 行 46 ~64:
-h
/-help
が指定されている場合に、組み込まれているヘルプ情報を表示します。プロシージャにヘルプ情報を組み込む必要がない場合は、これらの行と行 30 ~ 33 は削除できます。 - 行 68 ~70:エラーが発生していないかをチェックします。通常、引数が有効であるかをチェックする追加コードは、行 68 より前に記述する必要があります。指定されたコマンド ライン オプションが互換していないなど、エラーが発生している場合は、
error
変数がインクリメントされ、行 69 が実行されます。 - 行 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 つの引数
myproc2
を使用するargs
を定義します。args
は後ほど Tcl 配列を設定するのに使用されるので、引数の数は偶数にする必要があります。 - 行 3: さまざまなオプションのデフォルト値を指定します。各オプションには、1 つの引数のみ指定できます。
- リストのフォーマットは、次のとおりです。
expanse="page"> <option1> <valueForOption1> <option2> <valueForOption2> … <optionN> <valueForOptionN>
- 行 5: Tcl 配列
options
をデフォルト値で初期化します。 - 行 7:
args
変数の値でデフォルト値を置き換えます。 - 行 9 ~ 10: 各オプションの値を
$options(<option>)
で読み出します。次のコードを使用して、オプションが存在するかをチェックすることも可能です。if [info exists options(<option>)] { … }
注記: フラグとして機能する値のないコマンド ライン オプションは、0 または 1 などの値を渡すことにより簡単にインプリメントできます。上記のプロシージャ例では、フラグ-v
は「myproc2 -v 1
」を使用してオンにできます。