なんか、中途半端になってしまった。。。読まないほうがいいです。
個人的なメモ
だらだら書く
動機
pthread の確認するときに dtrace が凄く便利だったので
でも、全然使いこなせてない。(特に D 言語の文法が分からない)
dtrace のトレースの方法を書く言語を D 言語というが、一般的な D 言語とは違うもの。
dtrace の文法も含めて細かくかかれてる資料
これにつきる
http://docs.sun.com/app/docs/doc/817-6223?l=ja
さすが sun 。
この資料には日本語のはない。(6/17 現在)
文法定義ファイルも見つけた
http://www.opensource.apple.com/darwinsource/Current/dtrace-48/libdtrace/dt_grammar.y
Hello, world!
以下を hello.d で保存
BEGIN { trace("Hello, world!"); exit(0); }
実行
$ sudo dtrace -s hello.d dtrace: script 'hello.d' matched 1 probe CPU ID FUNCTION:NAME 1 1 :BEGIN Hello, world!
文法
これ を見ながら
プログラム全体
d_program: d_expression DT_TOK_EOF { return (dt_node_root($1)); } | d_program DT_TOK_EOF { return (dt_node_root($1)); } | d_type DT_TOK_EOF { return (dt_node_root($1)); } ; d_program: DT_CTX_DPROG { $$ = dt_node_program(NULL); } | DT_CTX_DPROG translation_unit { $$ = dt_node_program($2); } ;
D 言語をファイルに書いた場合、最初のトークンは DT_CTX_DPROG になる(実際に書いてある訳じゃないが、 Lexer がそういうトークンを返してくる)のでプログラム全体の文法は translation_unit を見ればいい。
translation_unit: external_declaration | translation_unit external_declaration { $$ = LINK($1, $2); } ; external_declaration: inline_definition | translator_definition | provider_definition | probe_definition | declaration ;
translation_unit (つまり、プログラム全体)は以下のいずれかの繰り返しということになる。
- inline_definition
- translator_definition
- provider_definition
- probe_definition
- declaration
inline_definition, translator_definition, provider_definition については使ったことがないので、無視する。
あ、でも translator_definition は便利そうなので後で解説するかも(余力があれば)
probe_definition
probe_definition: probe_specifiers { /* * If the input stream is a file, do not permit a probe * specification without / <pred> / or { <act> } after * it. This can only occur if the next token is EOF or * an ambiguous predicate was slurped up as a comment. * We cannot perform this check if input() is a string * because dtrace(1M) [-fmnP] also use the compiler and * things like dtrace -n BEGIN have to be accepted. */ if (yypcb->pcb_fileptr != NULL) { dnerror($1, D_SYNTAX, "expected predicate and/" "or actions following probe description\n"); } $$ = dt_node_clause($1, NULL, NULL); } | probe_specifiers '{' statement_list '}' { $$ = dt_node_clause($1, NULL, $3); } | probe_specifiers DT_TOK_DIV expression DT_TOK_EPRED { dnerror($3, D_SYNTAX, "expected actions { } following " "probe description and predicate\n"); } | probe_specifiers DT_TOK_DIV expression DT_TOK_EPRED '{' statement_list '}' { $$ = dt_node_clause($1, $3, $6); } ; probe_specifiers: probe_specifier_list { yybegin(YYS_EXPR); $$ = $1; } ; probe_specifier_list: probe_specifier | probe_specifier_list DT_TOK_COMMA probe_specifier { $$ = LINK($1, $3); } ; probe_specifier: DT_TOK_PSPEC { $$ = dt_node_pdesc_by_name($1); } | DT_TOK_INT { $$ = dt_node_pdesc_by_id($1); } ;
ちょっと長いが probe_definition は以下のようなものだということが分かる
<(DT_TOK_PSPEC または DT_TOK_INT) がコンマ区切りで続いたもの> [ DT_TOK_DIV <式(expression)> DT_TOK_EPRED ] { <複数の文(statement_list)> }
Lexer を見ると DT_TOK_PSPEC は hoge:hoge:hoge:hoge や hoge や hoge*::hoge のような文字、 DT_TOK_INT は 1234 のような数字 DT_TOK_DIV および DT_TOK_EPRED はスラッシュだと分かる
つまり、最初の Hello world の例は DT_TOK_DIV から DT_TOK_EPRED を省略したこの形だ
BEGIN {
trace("Hello, world!");
}
式(expression)
expression は
expression: assignment_expression | expression DT_TOK_COMMA assignment_expression { $$ = OP2(DT_TOK_COMMA, $1, $3); } ; : hogehoge_expression がずーっと続く。演算子の優先順位は C 言語と全く同じ :
なるほど、あるコンテキストでは d 言語は式だけの場合があるということか。
ちょっと気になったところは
配列アクセスの添字も関数呼出しの引数のように、複数指定できる。
/* 配列アクセスの添字 */ array_parameters: /* empty */ { $$ = NULL; } | constant_expression { $$ = $1; } | parameter_type_list { $$ = $1; } /* ←注目! */ ; /* 関数呼出しの引数 */ function_parameters: /* empty */ { $$ = NULL; } | parameter_type_list { $$ = $1; } /* ←注目! */ ;
つまり、 dtrace では多次元配列を
array[index_1, index_2]
というようにアクセスするってことか。
複数の文(statement_list)
statement_list: statement { $$ = $1; } | statement_list ';' statement { $$ = LINK($1, $3); } ; statement: /* empty */ { $$ = NULL; } | expression { $$ = dt_node_statement($1); } ;
うお。めっちゃシンプル!
え? D 言語って式文しかないの?? if 文 for 文 while 文は??
マジでないみたいだ
まあ、考えることは少なくなった、文は式文でしかない。
セミコロンとカンマの違いはほとんどない(値を持つかどうかぐらい)。
あ。変数宣言という文もない!
変数宣言は probe_definition の外に書く。
プログラム全体のところで述べた declaration が変数宣言を含む。
宣言(declaration)
declaration: declaration_specifiers ';' { $$ = dt_node_decl(); dt_decl_free(dt_decl_pop()); yybegin(YYS_CLAUSE); } | declaration_specifiers init_declarator_list ';' { $$ = $2; dt_decl_free(dt_decl_pop()); yybegin(YYS_CLAUSE); } ; declaration_specifiers: d_storage_class_specifier | d_storage_class_specifier declaration_specifiers | type_specifier | type_specifier declaration_specifiers | type_qualifier | type_qualifier declaration_specifiers ; d_storage_class_specifier: storage_class_specifier | DT_KEY_SELF { dt_decl_class(DT_DC_SELF); } | DT_KEY_THIS { dt_decl_class(DT_DC_THIS); } ; storage_class_specifier: DT_KEY_AUTO { dt_decl_class(DT_DC_AUTO); } | DT_KEY_REGISTER { dt_decl_class(DT_DC_REGISTER); } | DT_KEY_STATIC { dt_decl_class(DT_DC_STATIC); } | DT_KEY_EXTERN { dt_decl_class(DT_DC_EXTERN); } | DT_KEY_TYPEDEF { dt_decl_class(DT_DC_TYPEDEF); } ; type_specifier: DT_KEY_VOID { $$ = dt_decl_spec(CTF_K_INTEGER, DUP("void")); } | DT_KEY_CHAR { $$ = dt_decl_spec(CTF_K_INTEGER, DUP("char")); } | DT_KEY_SHORT { $$ = dt_decl_attr(DT_DA_SHORT); } | DT_KEY_INT { $$ = dt_decl_spec(CTF_K_INTEGER, DUP("int")); } | DT_KEY_LONG { $$ = dt_decl_attr(DT_DA_LONG); } | DT_KEY_FLOAT { $$ = dt_decl_spec(CTF_K_FLOAT, DUP("float")); } | DT_KEY_DOUBLE { $$ = dt_decl_spec(CTF_K_FLOAT, DUP("double")); } | DT_KEY_SIGNED { $$ = dt_decl_attr(DT_DA_SIGNED); } | DT_KEY_UNSIGNED { $$ = dt_decl_attr(DT_DA_UNSIGNED); } | DT_KEY_STRING { $$ = dt_decl_spec(CTF_K_TYPEDEF, DUP("string")); } | DT_TOK_TNAME { $$ = dt_decl_spec(CTF_K_TYPEDEF, $1); } | struct_or_union_specifier | enum_specifier ; type_qualifier: DT_KEY_CONST { $$ = dt_decl_attr(DT_DA_CONST); } | DT_KEY_RESTRICT { $$ = dt_decl_attr(DT_DA_RESTRICT); } | DT_KEY_VOLATILE { $$ = dt_decl_attr(DT_DA_VOLATILE); } ; struct_or_union_specifier: struct_or_union_definition struct_declaration_list '}' { $$ = dt_scope_pop(); } | struct_or_union DT_TOK_IDENT { $$ = dt_decl_spec($1, $2); } | struct_or_union DT_TOK_TNAME { $$ = dt_decl_spec($1, $2); } ; struct_or_union_definition: struct_or_union '{' { dt_decl_sou($1, NULL); } | struct_or_union DT_TOK_IDENT '{' { dt_decl_sou($1, $2); } | struct_or_union DT_TOK_TNAME '{' { dt_decl_sou($1, $2); } ; init_declarator_list: init_declarator | init_declarator_list DT_TOK_COMMA init_declarator { $$ = LINK($1, $3); } ; init_declarator: declarator { $$ = dt_node_decl(); dt_decl_reset(); } ; declarator: direct_declarator | pointer direct_declarator ; direct_declarator: DT_TOK_IDENT { $$ = dt_decl_ident($1); } | lparen declarator DT_TOK_RPAR { $$ = $2; } | direct_declarator array { dt_decl_array($2); } | direct_declarator function { dt_decl_func($1, $2); } ; lparen: DT_TOK_LPAR { dt_decl_top()->dd_attr |= DT_DA_PAREN; } ;
つまり
( 記憶クラス or 型 or const volatile など) の繰り返し
か
( 記憶クラス or 型 or const volatile など) の繰り返し 識別子; ( 記憶クラス or 型 or const volatile など) の繰り返し *識別子; ( 記憶クラス or 型 or const volatile など) の繰り返し 識別子(パラメータリスト); ( 記憶クラス or 型 or const volatile など) の繰り返し 識別子[パラメータリスト]; : などなど :
みたいな変数宣言と型宣言の組み合わせなのか。
型宣言は分かるけど変数宣言もグローバル領域にしかできないのか。
文法以外のいろいろ
- C 言語のポインタは数値としてしか扱えない。
- copyin でメモリの内容をコピーする
- copyin(arg0, 3) ← C 言語のポインタ arg0 から 3 バイトコピーした領域の(D 言語の)ポインタを返す。
- 解放とか考えなくてもいい
- 0 終端な文字列は copyinstr(p) で
- struct hoge { int fuga; } など同じ型を宣言して copyin と sizeof でコピーすればいい