• 検索結果がありません。

B演習(言語処理系演習)第一回

N/A
N/A
Protected

Academic year: 2021

シェア "B演習(言語処理系演習)第一回"

Copied!
28
0
0

読み込み中.... (全文を見る)

全文

(1)

B演習(言語処理系演習)第3回

字句解析

(2)

今日の予定

字句解析インタフェース

• 今週の課題

字句の定義

字句解析器の仕組み(概要)

• 下請け部品 char_buf, char_stream, int_stack

まめ知識: デバッガ

(3)

字句解析器とは

字句解析器 (tokenizer) ‘d’ ‘e’ ‘f’ ‘ ’ ‘f’ ‘i’ ‘b’ ‘(’ ‘n’ ‘)’ ‘:’ def identifier (fib) ( Identifier (n) )

(4)

今週の課題

字句解析器の作成とそのテスト

• テストプログラム: ファイルから字句を読み出して, 読み出された字句をその順に表示 • 表示の仕方 • TOK_KW_FOR • TOK_LITERAL_INT (35) • TOK_ID (x) • etc. • テストデータとその正解があるのでそれを用いて 比較

(5)

インタフェース

tokenizer_t t = mk_tokenizer(char * filename);  void tok_next(tokenizer_t t);

• 次の1字句を読み込んで現在の字句に設定

 token_kind_t tok_cur_token_kind(tokenizer_t t);

 int tok_cur_token_int_val(tokenizer_t t);  double tok_cur_token_float_val(tokenizer_t t);  char * tok_cur_token_str_val(tokenizer_t t);

(6)

インタフェース(2)

正しくエラーメッセージを表示するためのイン

タフェース

char * tok_cur_token_string(tokenizer_t t);

• 現在構築中の字句の文字列表現 

char * tok_cur_line_string(tokenizer_t t);

• 現在の行の文字列表現(現在の字句まで) 

そのほか2, 3 (資料参照)

(7)

字句解析器のテストプログラム

int tokenizer_test(char * filename) {

tokenizer_t t =

mk_tokenizer

(filename);

while (

tok_cur_token_kind

(t) != TOK_EOF) {

print_cur_token(t);

tok_next

(t);

}

return 0;

}

(8)

 void print_cur_token(tokenizer_t t) {

char * C_name = tok_cur_token_kind_string(t); switch(tok_cur_token_kind(t)) {

case TOK_ID:

case TOK_LITERAL_INT:

case TOK_LITERAL_FLOAT: case TOK_LITERAL_STRING:

printf("%s (%s)¥n", C_name, tok_cur_token_string(t)); break; default: printf("%s¥n", C_name); break; } }

(9)

int main(int argc, char ** argv) {

if (argc != 2) {

fprintf(stderr,

"usage : %s filename¥n", argv[0]);

exit(1);

} else {

tokenizer_test(argv[1]);

exit(0);

}

}

(10)

字句の種類

 テキスト,HP参照

or, and, is, not, in, =, ==, !=, >, >=, <, <=, +, -,

*, /, %, ~, <<, >>, ^, &, |,

None,

break, continue, pass, return, del, print,

global, if, elif, else, for, while, def,

(, ), {, }, [, ], ., ,, :,

 integer, floatnumber, stringliteral,  identifier

(11)

少し複雑な字句

 integer • 0 | (1|…|9)(0|…|9)*  floatnumber • (0|…|9)+.(0|…|9)* | .(0|…|9)+  string literal (エスケープ文字の扱い) • ”(x | ¥y)*”  identifier • (a|_)(a|d|_)*  テキストおよびmini-Pythonの文法を参照

(12)

注意の必要な字句

end_of_file : 入力終端に達すると生成される

newline : 改行に対して生成される(無視しない)

字下げ:

• indent : 字下げを1レベル深くする字句 • dedent : 字下げを1レベル浅くする字句 

コメント

(13)

字下げ/改行字句生成の例

def fib(n):

if n < 2: return 1 else:

return fib(n-1) + fib(n-2) def another_fun(…)         改行 字下げ(indent) 逆字下げ(dedent)

(14)

コメント

基本: #から改行手前までを無視

行が空白とコメントのみの場合,改行も無視

例:

• x = y + z # calc x

• id(x), =, id(y), +, id(z), newline

• # calc x first x = y

# then p p = q

(15)

字句の種類のCプログラムでの定義

typedef enum { TOK_OR, /* or */ TOK_AND, /* and */ …, …, TOK_ID, TOK_NEWLINE, TOK_INDENT, TOK_DEDENT, TOK_EOF } token_kind_t;

(16)

字句のCプログラム内での定義

typedef struct token

{

token_kind_t k;

union {

char * s_val; /* id, 文字列リテラル */ double f_val; /* 浮動小数点数リテラル */ int i_val; /* 整数リテラル */

} v;

(17)

字句解析器の基本的な仕組み

「現在の文字」に基づく場合わけ

• tok_next(tokenizer_t t) { …

switch (現在の文字) {

case ’%’ : t->tok.k = …; break;

case ’0’..’9’ : t->tok.k = …; break; }

… }

(18)

いくつかややこしいところ

各種literalとidentifier (正規表現)

コメントの読み飛ばし

indent/dedent字句の生成

現在構築中の行,字句の保持(エラーメッ

セージ用)

(19)

いきなりだとどうしていいか悩んでしまう人は,

• newline/indent/dedent 字句を後回しにする • エラーメッセージ表示(そのための状態管理)を後 回しにする 

tok_nextの主要部分(次の文字で場合わけを

しながら,字句の切れ目まで読んでいく.読ん

だtokenをtokにセットする)に集中

(20)

有用な下請け部品

 char_stream_t • 文字を読み出すための下請け部品 • ファイル名,行番号,列番号,現在行(現在の文字まで)を 維持  char_buf_t • 文字をためるバッファ(append)

• cur_line, cur_token_string, string literalの読み込み用

 int_stack_t

• 整数のスタック

• indent/dedent用

(21)

デバッグの心構え

いけないこと

• 平常心を失うこと(「なぜ動かないんだっっ!!」) • バグが消えてほしいと思うこと • プログラムをむやみにいじること(うまく動けばラッ キー,という考え方) 

よい心構え

• 目の前の(バグ入り)プログラムの動作を理解・観 察・追跡する

(22)

実践的心構え

極力小さな入力でバグを再現する

• どんな入力なら動いて,どんな入力は動かない か? 

(できるだけ小さな入力で),どこまでまともに

動作し,どこから狂いだすかを追跡する

• printfで変数の値を表示 • デバッガ

(23)

「デバッガ」の使い方よりも大切な

「デバッグ」の方法

平常心

• プログラムを直そうとやっきにならない 

大切な心構え

• 目の前にあるプログラムの挙動の調査 • どこで「本来の挙動」を逸脱したかの調査 本来の挙動 実際の挙動 プログラム開始時点 異常観測地点

(24)

デバッガ

プログラムを実行

実行途中で停止

• 関数先頭,行番号 • ステップ(1行ずつ)実行 

停止した状態で,変数,その他の「状態を観

察」

• 変数の値 • 関数呼び出しの履歴(なぜ今ここにいるか)

(25)

起動方法

gcc –g …

(shell)% gdb プログラム名

(emacs) M-x gdb

(26)

まめ知識: gdbの良く使うコマンド

 r コマンドライン引数…  p  bt  b 関数名  b ファイル名:行番号 (Emacs: C-x SPACE)  c  n  s  disp  <RET>で最後のコマンドの繰り返し

(27)

メモリ割り当てについて

よく分からない人はmalloc (C++ではnew)が

基本と思っておく

• 関数呼び出し後も生き延びてほしい(使われる)領 域は必ずmallocで割り当てる tokenizer_t mk_tokenizer() { tokenizer t[1]; t->… = …; … return t; } tokenizer_t mk_tokenizer() { tokenizer_t t = (tokenizer_t)malloc(sizeof(tokenizer)); if (t == 0) { … exit(1); } t-> … = …; … return t; }

(28)

M-x info

Cut & paste (コピペ)

• C-SPACE … C-w

• C-y

M-x query-replace

M-x replace-string

キーボードマクロ

参照

関連したドキュメント

卒論の 使用言語 選考要件. 志望者への

国際地域理解入門B 国際学入門 日本経済基礎 Japanese Economy 基礎演習A 基礎演習B 国際移民論 研究演習Ⅰ 研究演習Ⅱ 卒業論文

授業は行っていません。このため、井口担当の 3 年生の研究演習は、2022 年度春学期に 2 コマ行います。また、井口担当の 4 年生の研究演習は、 2023 年秋学期に 2

使用言語 日本語 選考要件. 登録届を提出するまでに個別面談を受けてください。留学中で直接面談 できない場合は Skype か

卒論の 使用言語 選考要件

(6) 管理者研修:夏に、 「中長期計画策定」の演習/年度末の 3 月は、 「管理者の役割につ