FF502 FVXの構文
 
 ◆ 概要 ◆

FieldViewの拡張スクリプト言語FVXの構文について説明します。

 ◆ 詳細 ◆
                     

ベース言語

FVXはスクリプト言語「Lua」をベースとした言語です。多くのLuaスクリプトがFVXで使用可能です。
以下のWebページにLua言語のマニュアルなど有益な情報が多数紹介されていますので、是非アクセスしてみてください。
 <English> http://www.lua.org/
 <Japanese> http://staff.aist.go.jp/yutaka.ueno/lua/docsjp.html

チャンク

FVXにおいて自己完結型プログラムであるコードのセグメントを「チャンク」と呼びます。 チャンクは独立したプログラム、または、 メインプログラムの一部として実行することができます。 チャンク最小で1行から最大でハードウェア環境によって決まる上限の行数で構成されます。

字句規約

・変数名は任意の文字またはアンダースコア ‘_’記号で始めることができます
・変数名は数字で始めてはいけません
・FVXは大文字と小文字を区別します: (例)変数 'temp'は 'Temp'と同じではありません
・コメントは「--」(半角マイナス2つ)で始まり、その行の終わりまでコメントアウトされます
・変数を明示的に宣言する必要はありません
・明示的にローカルと宣言されない限り、変数はグローバルとみなされます
・次の単語は予約されており、変数として使用することはできません

and break do else elseif
elseif for function if in
local nil not or repeat
return then until while  

変数の型

FVXの変数自体には型がありません。変数の型は割り当てられた値に依存します。変数の値は以下の異なる5つの型のいずれか1つを持ちます。

nil型
プログラムで宣言された値が割り当てられていない変数は自動的にnil型となります。

number型
倍精度浮動小数点数です。

string型
文字列変数です。シングルまたはダブルクォーテーションで囲んで表記されます。文字列には、C言語で使用されるようなエスケープ文字を使用することもできます。

function型
FVXの関数はfunction型の変数として表されます。つまり引数として他の関数に渡すことができ、関数の結果として返すこともできます。

table型
table型の変数は連想配列を表します。 連想配列とは数値だけでなく他のデータ型(nilを除く)もキーにできる配列です。それらの値は、FVXのすべての型(nil、number、string、function、table)で構成されます。

Tableの作成例

テーブルは { } で表されるコンストラクタ式によって作成されます。以下にテーブルの作成と使用の例を示します。

--空テーブルの作成
iso_surface = {}

--数値インデックスによる文字列を値に持つテーブルの作成
surface_types = {"wall", "inlet", "outlet"}

--文字列インデックスによるテーブルの作成
-- 文字列変数 "country" の作成
country = "UK"
-- テーブルの作成
capital = {}
capital[country] = "london"--インデックスとして "country" を使用
print (capital["UK"])-- prints "london"

テーブル変数はテーブルのみを参照します。つまり別のテーブル変数がこの変数に割り当てられると、両方が同じテーブルを参照することになります。コピーが作成されるわけではありません。

-- このテーブル変数の参照を別のテーブル変数に割り当てます
surface_types = {}
my_surface_types = {}
my_surface_types = surface_types
-- 2番目のインデックスの値を変更
my_surface_types[2] = "manifold"
print (surface_types[2])-- prints "manifold"

テーブル内の値にアクセスする別の方法があります。これは、table.index という形式です。注:この構文は数値インデックスには使用できません。 以下に例を示します。

print (surface_types[3])-- prints "outlet"
print (surface_types.3)-- wrong syntax
print (capital["UK"])-- prints "london"
print (capital.UK)-- prints "london"

前述のように、テーブルのインデックスは、すべてのタイプを組み合わせて組み合わせることができます。以下に例を示します。

test = {}
test[1] = 10
test[2] = 25
test["temp"] = 30
test.demo_func = function () print "Hello, World" end
print (test[1])-- prints "10"
print (test[2])-- prints "25"
print (test["temp"])-- prints "30"
test.demo_func()-- prints "Hello, World"

コンストラクタを使用して異なるタイプのインデックスを持つテーブルを作成する場合、数値インデックスを使用する値は、セミコロンを使用して他のタイプのインデックスを使用する値から分離する必要があります。以下に例を示します。

test = {"wall","surface","inlet";length=10,width=8,height=3}
print(test[2])-- prints "surface"
print(test.width)-- prints "8"

変数のスコープ

前述のように、FVXのすべての変数のスコープは自動的にグローバルになります。唯一の例外は明示的にlocalとして宣言されている場合です。ローカル変数のスコープはそれが宣言されているブロックに限定されます。この場合の「ブロック」は、制御構造やコード内の関数の本体になります。ローカルスコープの変数の方がパフォーマンスが向上します。コードのセグメント内にブロックを作成する必要がある場合は、do文でブロックを開始しend文でブロックを終了することでブロックを作成できます。

型変換

FVXではnumber型からstring型の変数は自動変換されます。numberからstringへの変換が精度低下を引き起こすことはありません。 しかしstringをnumberに変換する場合は精度低下が発生することがあり、印刷時に数値の外観が望ましくないことがあります。プレゼンテーション目的ではformat関数を使用する必要があります。

演算子

FVXは標準的な算術演算子、関係演算子、論理演算子、文字列連結演算子を利用できます。これらの演算子と演算子の優先順位について以下で説明します。

算術演算子
加算(+)、減算(-)、乗算(*)、除算(/)、べき乗(^)を使用できます。算術演算はnumber型の変数について実行されます。算術式中で数値を持つstring変数は、算術演算が実行される前に自動的にnumber型に変換されます。

関係演算子
より大きい(>)、より小さい(<)、より大きいか等しい(>=)、より小さいまたは等しい(<=)、等しい(==)、等しくない(~=)を使用できます。 これらの演算子はnumber型またはstring型の2個の変数に適用され、number型では大小比較、string型ではアルファベット順の比較を行います。 その結果がfalseの場合はnil型の値を、trueの場合はnil以外の型の値を返します。ただし、 string型変数の比較はFieldViewを実行しているマシンのロケールセットに依存します。例えば、ヨーロッパのLatin-1ロケールでは、 “acai” < “acorde” となります。他の変数型の場合は等しい(==)、等しくない(~=)のみの比較することができます。table型とfunction型の変数については参照によって比較されます。つまり変数が全く同じテーブルまたは関数を指している場合にのみ、2つの変数は等しいとみなされます。

論理演算子
and、or、notを使用できます。これらの演算子はnil型変数をfalseとみなし、それ以外の型の変数をtrueとみなします。演算子andは、最初の引数がnil型であればnilを返し、それ以外の場合は2番目の引数が返されます。演算子orは、最初の引数がnil型でなければ最初の引数を返し、それ以外の場合は2番目の引数が返されます。以下は論理演算子の使用例です:

x = y or z

ここで、yがnil以外の型の値を持つ場合、xにはyの値が代入されます。yの値がnilの場合、xにzの値が代入されます。

文字列連結演算子
2つの文字列を演算子「..」 (2つの連続するドット)を用いて連結することができます。連結演算のオペランドの1つがnumber型の値である場合、連結演算の前に自動的にstring型に変換されます。出力は新しいstringになるので、演算操作によりオペランドは変化しません。
例:

a = "Hello,"
b = " World"
c = a..b
print (c)-- prints "Hello, World"

演算子の優先順位
FVXの演算子を上から下に優先順位の高い順に以下のようになります:

^ (exponentiation)
not - (単項演算子)
*   /
+   -
..
<   >   <=   >=   ~=   == and   or

各行内では、右から左のべき乗演算を除いて優先順位は左から右となります。 混乱を避けるため式を入れ子にする時は括弧を使用する方がよいでしょう。 「等しくない」について、他のプログラミング言語で使用される「!=」とは異なり、FVXでは「~=」が使用されることにご注意ください。

代入文

代入文では変数の値を設定します。以下の例では変数xに値1を設定します。

x = 1

FVXでは、1つの代入文で複数の変数に値を代入することも可能です。以下の例では、xには値a、yには値bが割り当てられます。

x, y = a, b

左辺の変数の個数が右辺の値の個数より大きい場合、余分な変数には値nilが割り当てられます。以下の例では、pとqにはそれぞれ値1と2が割り当てられ、rとsの両方に値nilが割り当てられます。

p, q, r, s = 1, 2

右辺の変数の個数が左変の変数の個数より多い場合、余分な値は無視されます。以下の例ではm、n、oにはそれぞれ10、11、12が割り当てられ、値13は無視されます。

m, n, o = 10, 11, 12, 13

制御文

FVXには4種類の制御文if、while、repeat、forがあります。これら制御文では、nil値をfalse、それ以外の値をtrueとみなします。 FVXの条件式においては、ゼロとゼロ以外の値はtrueと評価され、nil値のみがfalseと評価されることにご注意ください。

if文
if文は最初に条件式をテストし、trueの場合はthenセクション、falseの場合elseセクションを実行します。if文はキーワードendで終了します。

例:

if x > 0 then
  y = 1
else
  y = 2
end

この例では、条件式x>0がテストされ、結果としてnil以外の値が返されるとthenセクションが実行され、nilの場合はelseセクションが実行されます。最初のifの後でelseifを使用してより多くの条件式をテストすることできます。

例:

if x > 20 then
  y = 1
elseif x > 10 then
  y = 2
elseif x > 0 then
  y = 3
else
  y = 4
end

while文
while文は最初に条件式をテストし、条件が満たされた場合はループ処理を繰り返し実行します。条件を満たさない場合、その時点でループを終了します。while文はキーワードendで終了します。

例:

a = 1
b = 10
while a<b do
  c = a^2
  a = a + 1
end

repeat文
repeat文はwhile文に似ていますが、条件式のテストをループ処理の終わりに行うという点が異なります。したがってプログラムはループ処理を少なくとも1回実行します。until文を使用して条件式をテストします。

例:

local x = 1
repeat
  print (x)
  x = x + 1
until x>10

for文
for文はカウンタを使用して設定された回数だけループを処理します。カウンタのインクリメントはオプションで、指定しない場合は1に設定されます。for文はキーワードendで終了します。ループカウンタは、ループの最初の反復で初期値に設定され、ループ処理後にインクリメントされます。ループカウンタが最大値を超えるとループの実行が停止します。

例:

x = 0
for i = 1, 10, 2 do
  x = x + 1
end

上のループの最後では、インクリメントが2のために変数xの値は5になります。インクリメントを負の整数に設定することも可能です。

注意:カウンタを表す変数は自動的にローカル宣言されます。 したがって、ループ終了後にこの変数の値を取り出すことはできません。上の例ではループの終了後のiの値はnilになります。カウンタの値を保持する必要がある場合は、別の変数に割り当てる必要があります。

例:

y = 1
for j = 1, 20 do
 if j>10 then
  x = j
  break
 end
end

上の例では、ループは11回の繰り返しを経て終了します。 またカウンタjの値は変数xに保存されます。

forループで数値インデックスを持つテーブルを参照することもできます。デフォルトでは数値インデックスは1から始まります。以下の例では、関数getn()を使用してテーブルtの要素数を取得しています。

例:

t = { "l", "m", "n", "o" }
for i = 1, getn(t) do
 print (t[i])
end

カウンタを使用する代わりに、指定したテーブル中のインデックス値のペアを参照することができます。 各インデックス値のペアが取得される順序はランダムです。このループ処理の回数はテーブル内のインデックスの数に等しくなります。

t = {a = 9,b = 6,c = 15,d = 27,tmp = 12}
for x, y in t do
 print (x, y)
end

関数

他のプログラミング言語の関数と同様に、FVXの関数はプログラムされた一連のタスクを実行し値を返すことができます。入力引数を使用することもできます。 関数内でローカル宣言された変数は、関数内に限定されたスコープを持ちます。つまり、関数のreturn時にこれらの変数とその値は破棄されます。

例:

function xyz (a, b, c)
  d = a + b + c
  return d
end

-- call the function
sum = xyz(3,2,3) -– the value stored in "sum" is 8

制御文と同様に、関数定義はend文で終了します。FVXプログラムで関数にアクセスできるようにするには、呼び出す前に関数定義をプログラムに導入する必要があります。上の例がa=1、b=2、c=3で呼び出されると、関数は値6を返します。xyzはfunction型の変数で、関数の直接参照を行っています。これを他の型の変数と同様の方法で取り扱うことができます。例えば、別の関数に引数として渡すことができます。またFVXテーブルのフィールドにすることもできます。

他の値と同様に、関数はテーブルの一部とすることができます。関数はテーブルに格納する際に定義することもできます。この場合、関数は名前を必要としません。

例:

--define the function
t.func = function(x)
  return 5*x
end

--call the function
x = t.func(4) -- the value stored into variable "x" is 20.

テーブルには、関数とその関数が操作するデータを含めることができます。この場合、テーブルはオブジェクト指向プログラミングの意味で「オブジェクト」と見なすことができます。

例:

--create a table
ambient = {
soundspeed = 330, -- [m/s]
temperature = 273, -- [deg. K]
density = 1.0, -- [kg/cm3]
gamma = 1.4, -- [-]
pressure = 0.795, -- [pascal]
R = 0.008314 -– [(kg*m2)/(s2*kg-mol*pascal)]
}

--define function to calculate ambient speed of sound
ambient.soundcalc = function(ambient)
ambient.soundspeed = sqrt(ambient.gamma*ambient.R*ambient.temperature)
end -–end definition of function "soundcalc"

--define function to calculate ambient pressure
ambient.pressurecalc = function(ambient)
ambient.pressure = ambient.density*ambient.R*ambient.temperature
end -– end definition of function "pressurecalc"

上の例では、周囲の大気物性値を持つテーブルには、圧力と音速があり、これらの値はテーブル中で定義された関数で更新されます。この意味で、テーブルはその値を維持するために外部関数を必要としない自己完結型オブジェクトと言えます。ただし、関数は表中の他の値を認識していないため、テーブルambientを引数として渡す必要があることに注意してください。 FVXにはコロン記法があり、テーブルの一部である関数にテーブルを渡す操作をより簡単に行えます。コロン記法では、selfと呼ばれる隠された最初の引数が使用されます。selfは関数を保持するテーブルです。前の例をコロン記法を使用して書き直すと以下のようになります。ここで、selfはテーブルambientを指しています。

例:

--define function to calculate ambient speed of sound
function ambient:soundcalc()
  self.soundspeed = sqrt(self.gamma* self.R*self.temperature)
end
--define function to calculate ambient pressure
function ambient:pressurecalc()
  self.pressure = self.density * self.R * self.temperature
end

引数の数が変化する関数を記述することも可能です。特別な引数‘...’は、関数定義の最後の引数として使用されるとき、引数の数が可変であることを示します。その関数中では、FVXは渡されるすべての引数を含むテーブルargを作成します。以下の例でこの機能を示します。

例:

function sum(…)
local arg_count=1
local total=0
while arg_count<=arg.n do
total = total + arg[arg_count]
arg_count = arg_count + 1
end
return total
end

--call function
print( sum(1,2,3) ) –- returns 6
print( sum(0,3,8,6) )-– returns 17

return文は、関数を終了するか、関数の結果を返すために使用されます。すべての関数は、デフォルトで暗黙のreturn文を持っているので必須ではありません。省略した場合は関数から値は返されません。構文上、return文はend文またはelse文の直前すなわちブロックまたはチャンクの最後に記述します。場合によってはブロックの途中でreturn文を使用する必要がある場合もあります。 このような場合、明示的なdoブロックでラップすることでreturn文を使用できます。

例:

function test(x)   return–-incorrect syntax

  if x>2 then
  return–-incorrect syntax

  x = x + 1
end

  --"return" is the last statement in this block
do return end–-correct syntax


… --remainder of the function

end

エラー

プログラムの実行中にエラーが発生すると、エラーの情報がポップアップウィンドウに表示されます。ポップアップウィンドウを閉じるとFVXデバッガが起動します。これによりデバッガコマンドを使用した修正のためにFVX環境にアクセスできます。デバッグを終了しない限り、プログラムの実行を継続することはできません。ただし、quitコマンドを入力することでFieldViewのGUIに制御を戻すことができます。

・この資料の内容は予告なしに変更されることがあります。
・いかなる場合でも、この資料の内容およびその運用の結果に関しては一切の責任を負いません。
・この資料の一部または全部を無断で使用、作成することはできません。
All rights reserved by Vinas Co., Ltd.
sales@vinas.com