だらだら続けます
文
文が多い
関数呼び出しが文><
statement : sub_call { $$ = gb_stmt_new_call (buffer, $1) } | object_list '=' expr { $$ = gb_stmt_new_assignment (buffer, $1, $3); } | dim_statement { $$ = NULL; } | static_statement { $$ = NULL; } | GB_REDIM { gb_parse_data_inside_dim (buffer); } opt_preserve var_name '(' subscripts ')' { gb_parse_data_dim_finish (buffer); $$ = gb_stmt_new_redim (buffer, $4, $6, $3); } | GB_ERASE var_name { $$ = gb_stmt_new_erase (buffer, $2); } | GB_SET object_list '=' opt_new object_list { $$ = gb_stmt_new_set (buffer, $2, $4, $5); } | GB_ON GB_ERROR on_error { $$ = $3; } | GB_EXIT nesting { $$ = gb_stmt_new_exit (buffer, $2); } | GB_DO opt_while_until eostmt statements GB_LOOP opt_while_until { $$ = gb_stmt_new_do_while (buffer, $2, $6, $4); } | GB_SELECT GB_CASE expr eostmt case_stmts GB_END GB_SELECT { $$ = gb_stmt_new_select (buffer, $3, $5); } | GB_WHILE expr eostmt statements GB_WEND { $$ = gb_stmt_new_do_while (buffer, $2, NULL, $4); } | GB_FOR NAME '=' expr GB_TO expr opt_step eostmt statements GB_NEXT opt_name /* TODO : add check for NAME == opt_name */ { $$ = gb_stmt_new_forloop (buffer, $2, $4, $6, $7, $9); } | GB_FOR GB_EACH NAME GB_IN object_list eostmt statements GB_NEXT opt_name /* TODO : add check for NAME == opt_name */ { $$ = gb_stmt_new_foreach (buffer, $3, $5, $7); } | GB_WITH object_list eostmt { gb_module_with_depth_inc (buffer, $2); } statements GB_END GB_WITH { $$ = gb_stmt_new_with (buffer, $2, $5); } | GB_IF expr GB_THEN if_body { $$ = gb_stmt_if_set_cond ((GBStatement *)$4, $2); } | GB_BEEP { $$ = NULL; } | GB_DATE '=' expr { $$ = NULL; } | GB_RANDOMIZE opt_expr { $$ = gb_stmt_new_randomize (buffer, $2); } | GB_LOAD expr { $$ = gb_stmt_new_load (buffer, $2); } | GB_UNLOAD expr { $$ = gb_stmt_new_unload (buffer, $2); } /* THIS LOOKS EXTREMELY BROKEN ! */ | object_refs '.' GB_LINE '(' expr ',' expr ')' '-' opt_line_step '(' expr ',' expr ')' ',' expr ',' expr { } | object_refs '.' GB_LINE '(' expr ',' expr ')' '-' opt_line_step '(' expr ',' expr ')' ',' expr { } | object_refs '.' GB_SCALE '(' expr ',' expr ')' '-' '(' expr ',' expr ')' { } /* File handling related statements */ | GB_OPEN expr GB_FOR open_mode GB_AS expr opt_open_len { $$ = gb_stmt_new_open (buffer, $2, $4, $6, $7); } | GB_OPEN expr GB_FOR open_mode GB_AS '#' expr opt_open_len { $$ = gb_stmt_new_open (buffer, $2, $4, $7, $8); } | GB_INPUT '#' expr ',' expr_csv { $$ = gb_stmt_new_input (buffer, $3, $5); } | GB_LINE GB_INPUT '#' expr ',' expr { $$ = gb_stmt_new_line_input (buffer, $4, $6); } | GB_CLOSE expr_csv { $$ = gb_stmt_new_close (buffer, $2); } | GB_CLOSE handles { $$ = gb_stmt_new_close (buffer, $2); } | GB_GET '#' expr ',' opt_expr ',' expr { $$ = gb_stmt_new_get (buffer, $3, $5, $7); } | GB_PUT '#' expr ',' opt_expr ',' expr { $$ = gb_stmt_new_put (buffer, $3, $5, $7); } | GB_SEEK '#' expr ',' expr { $$ = gb_stmt_new_seek (buffer, $3, $5); } | GB_PRINT '#' expr ',' expr_csv { $$ = gb_stmt_new_print (buffer, $3, $5); } /* End of File handling related statements */ | GB_GOTO NAME { $$ = gb_stmt_new_goto (buffer, $2); } | GB_GOTO_LABEL { $$ = gb_stmt_new_label (buffer, $1); } ;
式
expr : value { $$ = gb_expr_new_value ($1); } | object_list { $$ = $1; } | '+' expr { $$ = gb_expr_new_unary (GB_EXPR_POSITIVE, $2);} | '-' expr { $$ = gb_expr_new_unary (GB_EXPR_NEGATIVE, $2);} | GB_NOT expr { $$ = gb_expr_new_unary (GB_EXPR_NOT, $2);} | '(' expr ')' { $$ = gb_expr_new_unary (GB_EXPR_PAREN, $2); } | expr '&' expr { $$ = gb_expr_new_binary ($1, GB_EXPR_CONCAT, $3); } | expr GB_AND expr { $$ = gb_expr_new_binary ($1, GB_EXPR_AND, $3); } | expr GB_OR expr { $$ = gb_expr_new_binary ($1, GB_EXPR_OR, $3); } | expr GB_XOR expr { $$ = gb_expr_new_binary ($1, GB_EXPR_XOR, $3); } | expr '>' expr { $$ = gb_expr_new_binary ($1, GB_EXPR_GT, $3); } | expr GB_GE expr { $$ = gb_expr_new_binary ($1, GB_EXPR_GE, $3); } | expr '=' expr { $$ = gb_expr_new_binary ($1, GB_EXPR_EQ, $3); } | expr GB_IS expr { $$ = gb_expr_new_binary ($1, GB_EXPR_EQ, $3); } | expr GB_NE expr { $$ = gb_expr_new_binary ($1, GB_EXPR_NE, $3); } | expr GB_LE expr { $$ = gb_expr_new_binary ($1, GB_EXPR_LE, $3); } | expr '<' expr { $$ = gb_expr_new_binary ($1, GB_EXPR_LT, $3); } | expr '-' expr { $$ = gb_expr_new_binary ($1, GB_EXPR_SUB, $3); } | expr '+' expr { $$ = gb_expr_new_binary ($1, GB_EXPR_ADD, $3); } | expr '*' expr { $$ = gb_expr_new_binary ($1, GB_EXPR_MULT, $3); } | expr '/' expr { $$ = gb_expr_new_binary ($1, GB_EXPR_DIV, $3); } | expr '''' expr { $$ = gb_expr_new_binary ($1, GB_EXPR_INT_DIV, $3); } | expr '^' expr { $$ = gb_expr_new_binary ($1, GB_EXPR_POW, $3); } | expr GB_EQV expr { $$ = gb_expr_new_binary ($1, GB_EXPR_EQV, $3); } | expr GB_IMP expr { $$ = gb_expr_new_binary ($1, GB_EXPR_IMP, $3); } ;
以下のような関数呼び出しは
func(a)
- method_array_ref
- object_ref
- object_refs
- object_list
- expr
という風にリデュースされるので、式の中に関数呼び出しを書ける。
method_array_ref : GB_OBJ_NAME_LPAR opt_parms ')' { $$ = gb_obj_ref_new ($1, TRUE, $2); } ; object_ref : prop_ref { $$ = $1; } | method_array_ref { $$ = $1; } ; object_refs : object_refs '.' object_ref { $$ = g_slist_prepend ($1, $3); } | object_refs '!' obj_name { $$ = g_slist_prepend ($1, gb_obj_ref_new (NULL, TRUE, g_slist_prepend (NULL, (gpointer) gb_expr_new_string ($3)))); } | object_ref { $$ = g_slist_prepend (NULL, $1); } | GB_SPACE_DOT object_ref { $$ = g_slist_prepend (NULL, $2); } ; object_list : object_refs { $$ = gb_expr_new_obj_list ($1); } ;
型を調べる
TypeName を使います
alert(TypeName(document.createElement("div")))
関数宣言してすぐ代入はダメ
dim_statement の定義が以下のようになっているので、
dim_statement : GB_DIM { gb_parse_data_inside_dim (buffer); } var_decls { gb_parse_data_dim_finish (buffer); } ; var_decls : var_decls ',' var_decl | var_decl ; var_decl : opt_events var_name opt_subscripts dim_type { gb_parse_data_add_var (buffer, gb_var_new ($2, $4.as_new, $3.is_array, $3.indices, $4.name)); }
DIm elm = document.createElement("div")
などは、文法エラー
代入は文(しかもキモい)
代入は文なので、以下のようには書けません。
と、思いきや書けます。
a = b = 1
- 最初のイコールは、代入文の一部として評価され、
- 次のイコールは比較式のイコールとして評価されます。
つまり、 b と 1 を比較した結果を a に代入するということになります。
オブジェクトの代入だけは特殊
以下のようにオブジェクトを代入文で代入するときは注意が必要です。
Dim elm elm = document.createElement("div")
これをすると elm に "[object]" という文字列が代入されます。
JavaScript 的に言うとオブジェクトは通常の代入時に valueOf が呼び出されてしまうのですね。
なので、オブジェクト型の値を代入する場合に限って Set が必要になります。
Dim elm Set elm = document.createElement("div")
これを Set 文(Set ステートメント)といいます。
http://msdn.microsoft.com/ja-jp/library/cc392465.aspx
コメント
' コメントはアポストロフィ
文の区切り
文の区切りは改行
alert(0) alert(1) alert(2)
または、コロン
alert(0): alert(1): alert(2)
返り値
' 1 を足して返す ' 関数と同じ名前の変数に代入する Function succ(a) succ = a + 1 End Function alert(succ(succ(0))) ' 2
' return のように関数の最後じゃなくてもいい Function succ(a) succ = a + 1 alert(succ) End Function alert(succ(succ(0))) ' 2
Sub と Function は同じ風に使われるが、 Sub には返り値の機能はない
関数呼び出しの () は省略 OK
関数名のシンボルが式の中で評価されると関数は引数なしで呼び出される
ここらへんは Perl と同じ
Function foo: alert(0): End Function foo ' foo() と foo は同じ Function bar(a): alert(a): End Function bar 1 ' bar(1) と同じ a = foo ' foo の返り値を a に代入
Eval と Execute の違い
Eval は式の評価 Execute は文の評価を行う。
しかも、 Eval は式(関数)で Execute は文(値は持たない)。
' Eval は式として評価するので a = 1 は比較式になる Eval("a = 1") ' Eval 自身も式なので値を持つ alert(Eval("1 = 1")) ' True ' Execute は式として評価するので a = 1 は代入文になる Execute "a = 1" ' 複数の文も一つの Execute で実行できる Execute "dim a: a = 1: alert(a)" ' Execute 自身も式なので文の途中には書けない ' alert(Execute("a = 1")) はエラー
Execute を使うと動的に関数を宣言できる
Execute "Function foo: alert(1): End Function"
関数を値として使う
GetRef を使う
Function foo: alert(1): End Function Dim bar Set bar = GetRef("foo") ' 関数名を文字列で指定する bar() ' これは () の省略ができない。省略しても実行されない。 alert(TypeName(bar))
JavaScript から見た VBScript の関数
<script language="vbscript" type="text/vbscript"> Function foo foo = 1 End Function </script> <script language="javascript" type="text/javascript"> alert(foo()); // 呼び出せる alert(typeof foo); // unknown alert(typeof window.foo); // unknown try { var bar = foo; // これはエラーになる } catch(e) { alert(e.message); } </script>
これでは不便すぎるので、 GetRef してやると普通の JavaScript の関数のように扱える
<script language="vbscript" type="text/vbscript"> Function foo_ foo_ = 1 End Function Dim foo Set foo = GetRef("foo_") </script> <script language="javascript" type="text/javascript"> alert(foo()) alert(typeof foo); // object alert(typeof window.foo); // object try { var bar = foo; // これがエラーにならない alert(bar()); alert(bar.apply); // だけど apply などの Function.prototype に依存するものは持っていない } catch(e) { alert(e.message); } </script>
VBScript から見た JavaScript の関数
<script language="javascript" type="text/javascript"> function foo() { return 1 } </script> <script language="vbscript" type="text/vbscript"> ' JavaScript の関数はちょうど GetRef された VBScript の関数と同じ扱いになる alert(foo) ' 呼び出されない alert(foo()) ' 呼び出される Dim bar Set bar = foo ' 代入可能 alert(bar) alert(bar()) </script>
クラス
なんか、めんどくなってきたので凄いところだけw
ゲッター(Get) セッター(Set/Let)
Class Foo Property Let foo(a): alert("Let " + TypeName(a)): End Property Property Set foo(a): alert("Set " + TypeName(a)): End Property Property Get foo: foo = 1: End Property End Class
Let は普通の代入文、 Set は Set 文
Dim f Set f = new Foo f.foo = "hoge" 'Let が呼ばれる Set f.foo = "hoge" ' Set が呼ばれる alert(f.foo) ' Get が呼ばれる
JavaScript からも使える
alert(f.foo); // Get が呼ばれる f.foo = "hoge"; // 文字列だと Let が呼ばれる f.foo = {}; // オブジェクトだと Set が呼ばれる
Public Default
オブジェクトを Callable にする
<script language="vbscript" type="text/vbscript"> Class Foo Public Default Function item(a, b, c) alert(a) alert(b) alert(c) item = "fuga" End Function End Class alert(1) Dim bar Set bar = New Foo alert(bar(1, 2, 3)) </script> <script language="javascript" type="text/javascript"> alert(bar(1, 2, 3));
Setter や Getter と、 Callable は JScript からは出来ないので重宝しそう。