プログラミング言語の スコープ階層を反映した 構造化解析器 神谷 年洋† 石尾 隆* 井上 克郎* †科学技術振興機構 さきがけ *大阪大学 大学院情報科学研究科 2004/02/24 日本ソフトウェア科学会 第1回 ディペンダブ ルソフトウェア ワークショップ 1 背景:ソースコードを処理する CASEツール ◆ ソースコードを処理する様々なCASEツール ■ ■ コンパイラ、lint リバースエンジニアリングツール ◆ 「ソースコードからドキュメントを作成する」 ■ 影響波及解析、スライス ◆ ソースコードを処理するための手法 ■ 2004/02/24 字句解析、プリプロセッシング、構文解析、意味解析 日本ソフトウェア科学会 第1回 ディペンダブ ルソフトウェア ワークショップ 2 コンパイラ・ コンパイラの利用 ソースファイル (文字の並び) 字句解析 ソースコード処理ツール トークンの並び 構文解析 コンパイラ・コンパイラ 字句規則 (正規表現) 字句解析規則 (BNF) AST等 … 意味解析 2004/02/24 出力 日本ソフトウェア科学会 第1回 ディペンダブ ルソフトウェア ワークショップ 3 問題点 ◆ コンパイラ・コンパイラを使ってもなお、 複雑なプログラミングを要求される ■ 構文エラーからの回復処理の記述 ◆構文解析器の内部処理に関する知識が必要 ■ OOPLのスコープおよびアクセス制御 ◆前方参照の解消 ■ 曖昧な構文の処理 ◆(型)式 ◆型<型, 2004/02/24 …> 日本ソフトウェア科学会 第1回 ディペンダブ ルソフトウェア ワークショップ 4 スコープおよびアクセス制御 パッケージ クラス 不可視 または アクセス不可 メソッド 自動変数 他のメソッド インスタンス変数 他のクラス 2004/02/24 公開されている場合 可視 かつ アクセス可能 公開されている場合 公開されている場合 日本ソフトウェア科学会 第1回 ディペンダブ ルソフトウェア ワークショップ 5 アプローチ ◆ 漸進的解析器 ■ ■ OOPLのスコープとアクセス制御の階層性=解 析器のクラス階層 ソースコードの外側から内側へと解析を進める ◆パッケージ 2004/02/24 → クラス → メソッド 日本ソフトウェア科学会 第1回 ディペンダブ ルソフトウェア ワークショップ 6 漸進的解析器の構成 •ソースコード中でクラスを定義して •クラスのインターフェイス(公開メソッ いる部分すべて見つけだす。 ドのシグネチャや公開インスタンス変 •parseInterface()を呼び出して、そ 数の型)を調べてPackageParser に返 れらをInterfaceParser に渡す。 す。 •PackageParser はその情報を interfaces に追加していく。 実行順序 PackageParser #interfaces -code ClassParser +parse(partialSrc):code #parserInterface(partialSrc) :interface #parseClass(partialSrc):code InterfaceParser #parseInterface (partialSrc):interface 2004/02/24 #instanceVars #methods #parseClass(partialSrc):code #parseMethod(partialSrc):code MethodParser #parameters #parseMethod(partialSrc):code 日本ソフトウェア科学会 第1回 ディペンダブ ルソフトウェア ワークショップ 7 漸進的解析器の利点 ■ 構文エラーの処理=構造化例外処理 ◆パッケージ ■ ← クラス ← メソッド 前方参照の問題が生じない/識別子が変数、メ ソッド、型のいずれかであるかを利用した文法 を使うことができる ◆メソッドを解析する前に、インスタンス変数が判明 している ■ 繰り返し開発・回帰テストへの対応 ◆パッケージの解析器から順に開発していく 2004/02/24 日本ソフトウェア科学会 第1回 ディペンダブ ルソフトウェア ワークショップ 8 class C extends Object { Object value; C() { super(); this.value = new Pair(new A(), new B()).setfst(new B()); } } 例題: Featherweight Java ◆ FWJ[7]の漸進的解析器を 開発する ■ ■ ■ 階層的なスコープを持ち 強く型付けされた 非常に単純な構文規則 (Javaのサブセット)を持つ class Pair extends Object { Object fst; Object snd; Pair(Object fst, Object snd) { super(); this.fst = fst; this.snd = snd; } Pair setfst(Object newfst) { return new Pair(newfst, this.snd); } } class A extends Object { A() { super(); } } [7] Igarashi, A., Pierce, B., and Wadler, P.: Featherweight Java: A Minimal Core Calculus for Java and GJ, ACM Trans. Programming class B extends Object { Languages and Systems, 23(3), pp. 396-450 B() { super(); } 2004/02/24 日本ソフトウェア科学会 第1回 ディペンダブ (2001). } ルソフトウェア ワークショップ 9 構文規則 Input() : // 開始シンボル ( CL() )* <EOF> CL() : // クラス定義 <CLASS> <ID> <EXTENDS> <ID> <LB> ( LOOKAHEAD(2) <ID> <ID> <SEMICOLON> )* K() ( M() )* <RB> 字句規則 K() : // コンストラクタ SKIP : { <ID> <LP> ( ParamL() )? <RP> " " | "\t" | "\n" | "\r" | "\f" <LB> } <SUPER> <LP> ( ArgL() )? <RP> TOKEN : { <SEMICOLON> < LP: "(" > | < RP: ")" > ( <THIS> <DOT> <ID> <EQUAL> e() | < LB: "{" > | < RB: "}" > <SEMICOLON> )* | < COMMA: ","> | < SEMICOLON: ";" > <RB> | < DOT: "." > | < EQUAL: "=" > ParamL() : // パラメータの並び | < CLASS: "class" > <ID> <ID> ( <COMMA> <ID> <ID> )* | < EXTENDS: "extends" > ArgL() : // 実引数の並び | < NEW: "new" > | < RETURN: "return" > e() ( LOOKAHEAD(2) <COMMA> e() )* | < SUPER: "super" > | < THIS: "this" > M() : // メソッド定義 | < ID: ( <LETTER> )+ > <ID> <ID> <LP> ( ParamL() )? <RP> | < #LETTER: ["\u0041"-"\u005a", "\u005f", <LB> <RETURN> e() <SEMICOLON> <RB> "\u0061"-"\u007a" ] > e() : // 式 10 日本ソフトウェア科学会 第1回 ディペンダブ } 2004/02/24 ルソフトウェア ワークショップ ・・・ 通常の解析器 Input() : ClassParser <LB> ( LOOKAHEAD(2) V() )* K() ( M() )* <RB> V() : <TYPEID> <ID> <SEMICOLON> K() : <TYPEID> <LP> ( ParamL() )? <RP> BlockLike() ParamL() : <TYPEID> <ID> PackageParser ( <COMMA> <TYPEID> <ID> )* Input() : M() : ( CL() ) * <EOF> ( <TYPEID> | <VOID> ) <ID> CL() : <LP> ( ParamL() )? <RP> <CLASS> <ID> <EXTENDS> <ID> BlockLike() BlockLike() BlockLike() : BlockLike() : <LB> <LB> ( <ID> | <TYPEID> | <LP> | <RP> ( <ID> | <LP> | <RP> | <SUPER> | <SUPER> | <THIS> | <THIS> | <DOT> | <EQUAL> | <DOT> | <EQUAL> | <SEMICOLON> | <COMMA> | <SEMICOLON> | <COMMA> | <RETURN> | <NEW> | BlockLike() )* 第1回 ディペンダブ 2004/02/24 11 日本ソフトウェア科学会 | <RETURN> | <NEW> | BlockLike() )* ルソフトウェア ワークショップ <RB> <RB> 漸進的解析器 構文エラーを含む入力例 2004/02/24 1: class A extends Object { 2: C() { super(); } 3: } 4: class Pair extends Object { 5: Object fst; 6: Object snd; 7: Pair(Object fst, Object snd) { 8: super(); 9: this.fst = fst; 10: this.snd = snd; 11: } 12: Pair Pair(Object newfst) { 13: return new Pair(newfst, this.snd); 14: 日本ソフトウェア科学会 } 第1回 ディペンダブ ルソフトウェア ワークショップ 15: } 12 課題 ◆ 技術的な問題 ■ JavaCCは構文解析器をクラス階層内に作り込 むことを想定していない ◆ 本質的に曖昧な名前への対応 ■ クラス、メソッド、フィールドが同じ名前の場 合 ◆ BNFで与えられた構文全体から、 PackageParser, InterfaceParser等のための 部分規則を自動的に作り出す方法 2004/02/24 日本ソフトウェア科学会 第1回 ディペンダブ ルソフトウェア ワークショップ 13 まとめ ◆ 「漸進的解析器」を提案した ■ ■ ■ ■ スコープやアクセス制御=クラス階層 構文エラーからの回復を構造化例外によって処 理する 識別子が型であるか無いかで異なった構文であ ると見なす構文規則を利用できる 返し型開発、テスト駆動型開発とも親和性があ る ◆ 例題を通じて、その開発の詳細を説明した 2004/02/24 日本ソフトウェア科学会 第1回 ディペンダブ ルソフトウェア ワークショップ 14 終わり 2004/02/24 日本ソフトウェア科学会 第1回 ディペンダブ ルソフトウェア ワークショップ 15 QA「関連技術」 [Q] 構文解析というのは古典的な領域ですの で,提案されている着想がなぜいままでな されていなかったかについて,若干のコメ ントがあればと思います. ◆ よくわかりません。 ◆ ただし、近年、従来の字句解析・意味解 析・意味解析という境界を崩そうとする試 みが徐々に登場しています。 2004/02/24 日本ソフトウェア科学会 第1回 ディペンダブ ルソフトウェア ワークショップ 16 QA 「曖昧な名前」 [Q] 型名と識別子の区別についてですが,例えば,以下のCプ ログラムは正しいですが,どう思います? struct sss { short mmm; }; typedef int mmm; mmm foo(struct sss s){ return s.mmm; } 型名となってもフィールド名としても使えないといけないです. ◆ ◆ このような、同じ名前の型とフィールドを区別するために は、字句解析にヒューリスティックを導入するしかありま せん。 ただし、これについてはプログラミング言語の変化を待っ た方が良いとも思います。 2004/02/24 日本ソフトウェア科学会 第1回 ディペンダブ ルソフトウェア ワークショップ 17 QA「エラー回復処理」 [Q] クラス内部は後にして,クラス宣言を取り出す部分です が,括弧の対応をとるというのは,そこを間違ったプログ ラムに対して困りませんか?「<CLASS>」まで skip する のと比較してどうでしょう? ◆ ◆ 外側の括弧の対応が崩れているソースコードでは、その場 でエラー回復しても大量のエラーメッセージが再生産され るだけなので、そのような場合は考慮していません。 構造化例外処理の方が、プログラミング言語の機能を直接 使っているという点でシンプルな手法であると思います。 2004/02/24 日本ソフトウェア科学会 第1回 ディペンダブ ルソフトウェア ワークショップ 18 QA「クラス階層」 [Q] 後から足す parser はオーバライドで足すとのことですが,それだと 後から足す部分が複数あったときに,どのクラスを使ったらよいのか 困りませんか? (中略) おそらく関係のないClassParser と,MethodParasr をクラス拡張で関 係付けるのは間違っていて,何もしない MethodParasr の代わりにそ れを拡張してある程度解析するようにしたStdMethodParser を使いた いなどのときには new StdClassParser (new MethodParser, new VariableParser) ではなく new StdClassParser (new StdMethodParser, new StdVariableParser) のようにする,ということにしたほうがよいと思います. ◆ はい、そう思います。現実の利用に堪えるツールを開発することを想 定すれば、何かと制約の多い継承(導出)をがんばって使うよりは、 インターフェイスによる分離と委譲を使った方が良いでしょう。 2004/02/24 日本ソフトウェア科学会 第1回 ディペンダブ ルソフトウェア ワークショップ 19 コンパイラ・コンパイラ ベース言語 ANTLR 字句解析 構文解析 意味解析 LALR(1) Java, C#, C++ LL(k) Boost Spirit C++ LL(k) JavaCC Java LALR(1) Lex+Yacc C LALR(1) SableCC 2004/02/24 Java 日本ソフトウェア科学会 第1回 ディペンダブ ルソフトウェア ワークショップ 20
© Copyright 2024 ExpyDoc