CUP/JLex
-
Upload
callum-rodriquez -
Category
Documents
-
view
40 -
download
4
description
Transcript of CUP/JLex
コンパイラ
字句解析器
構文解析器
コード生成器
rlt := left + 20(ソースプログラム)
rlt := left + 20(ソースプログラム)
ID ASSIGN ID ADD CONST(トークン列)
ID ASSIGN ID ADD CONST(トークン列)
ASSIGN
VAR
VAR
CONST
ADD
(中間表現)ld [%fp - 8], %o1ld [%fp - 12], %o2add %o1,%o2,%o1st %o1, [%fp - 4](アセンブリコード)
ld [%fp - 8], %o1ld [%fp - 12], %o2add %o1,%o2,%o1st %o1, [%fp - 4](アセンブリコード)
識別子
コンパイラコンパイラ• 目的言語の仕様記述からコンパイラを
自動生成する( 1960 年中頃から)
一括生成困難
構文解析部( Yacc ),字句解析部( Lex )の自動生成( 1970 年代はじめ)
CUP/Jlex : Yacc/Lex の Java 版
BNF ( Backus-Naur Form )• S1 と S2 を文, E を式として, “ if E then S1 else S2” は文である• 文のクラスを stmt ,式のクラスを expr
として, stmt → if expr then stmt else stmt
終端記号(太文字) 非終端記号(斜体)
生成規則
曖昧さ
E → E + E | E * E | ( E ) | - E | id
• id+id*id の構文解析
id + id * id
E E
E
E
E
id + id * id
E E
E
E
E
構文解析ルーチン生成系• Yacc ( Yet Another Compiler Compiler )• 処理系: CUP ( Constructor of Useful Parser )
> java java_cup.Main < minimal.cup > javac parser.java
java java_cup.Main
javac
java parser
CUP による文法記述 Minimal.cup
構文解析プログラム parser.java
parser.java parser.class
入力 出力
expr_list → expr_list expr_part | expr_partexpr_part → expr ;expr → NUMBER | expr PLUS expr | expr TIMES expr | ( expr )
Minimal.cup :
構文解析ルーチン生成系• 生成される構文解析器の動作
E → E + T | TT → T * F | FF → ( E ) | digit
E
+
digit
規則の右辺にマッチすれば ,左辺で置換え
digit - ···
入力
構文スタック
シフト
構文解析ルーチン生成系• 生成される構文解析器の動作
– 還元
E → E + T | TT → T * F | FF → ( E ) | digit
E
+
digit
digit - ···
入力
構文スタック
ポップ
F
プッシュ
構文解析ルーチン生成系• 生成される構文解析器の動作
– 還元
E → E + T | TT → T * F | FF → ( E ) | digit
E
+
F
digit - ···
入力
構文スタック
ポップ
T
プッシュ
構文解析ルーチン生成系• 生成される構文解析器の動作
– 還元
E → E + T | TT → T * F | FF → ( E ) | digit
E+
digit - ···
入力
構文スタック
ポップT
プッシュE
構文解析ルーチン生成系• 生成される構文解析器の動作
– シフト
E → E + T | TT → T * F | FF → ( E ) | digit
digit -
···
入力
構文スタック
プッシュ
E
-
expr_list → expr_list expr_part | expr_partexpr_part → expr ;expr → NUMBER | expr PLUS expr | expr TIMES expr | ( expr )
Minimal.cup :
宣言
翻訳規則
構文解析ルーチン生成系• 宣言部
– 先頭 : package や import の宣言を書く.– action code {: … :}; アクションクラス内にコピー.– parser code {: … :}; 構文解析クラス内にコピー.– init with {: … :}; 構文解析の最初に実行.– scan with {: … :}; トークンを取り出すときに
呼び出すべき字句解析のメソッド.– terminal classname name1, name2, ...;
使用する終端記号(トークン)の宣言. class は属性の型名(なくても良い).
– non terminal classname name1, name2, ...; 使用する非終端記号の宣言. class は属性の型名(なくても良い).
構文解析ルーチン生成系• 翻訳規則部
<左辺> → <選択肢1>|<選択肢2>| ··· |<選択肢n>
<左辺> ::= <選択肢1> { : 意味動作1 : } |<選択肢2> { : 意味動作2 : } · · · |<選択肢n> { : 意味動作n : } ;セミコロン
コロン 2 つと =
構文解析ルーチン生成系• 翻訳規則部の意味動作
– 意味動作は対応する生成規則の還元の際に実行– 右辺の属性は,終端記号あるいは非終端記号
の後に,コロンを付けて変数を指定する.例 expr:e1– 左辺の属性は, RESULT という変数で表現される.– 意味アクション内では,属性の変数名を記述する
だけで,参照可.例 {:e1.intValue()+e2.intValue() :}– 多くの場合,左辺の属性値を右辺の属性値を使って計
算する.
expr ::= expr:e1 PLUS expr:e2 {: RESULT = new Integer(e1.intValue() + e2.intValue()); :}
構文解析ルーチン生成系• トークンの意味値
– 字句解析ルーチンから java_cup.runtime.Symbol クラスのインスタンスとして受け渡す.
Class Symbol { int sym; /* トークン型 */ int left, right; /* トークンのソースファイルでの位置 */ Object value; /* 意味値 */ Symbol(int s, int l, int r, Object v) { sym=s, left=l; right=r; value=v; }}注:トークン型は, sym クラスの static 変数の値として表現されている.
構文解析ルーチン生成系• 曖昧な文法の利用法
– +,-,*,/を式の生成規則に記述したい.
E → E + T | E - E | E * E | E / E | ( E ) | - E | number
文法が曖昧 ··· 競合
構文解析ルーチン生成系• 競合の解決
– Yacc による暗黙の解決 還元-還元競合: 最初の方に書かれた規
則を 優先する. シフト-還元競合: シフトを優先する.– ユーザ指定によるシフト-還元競合の解決 終端記号に優先順位と結合性を与える.
precedence left PLUS, MINUS; precedence left TIMES, DIVIDE, MOD; precedence left UMINUS;
構文解析ルーチン生成系• ユーザ指定による競合の解決
Precedence left PLUS, MINUS; ··· PLUS と MINUS の優先順位が同じで左結
合.Precedence right POW; ··· POW は右結合.Precedence nonassoc EQ, LE, GT; ··· 結合性をも
たない .– トークンは後の方で宣言されるほど優先順位
が高い 優先順位が高い同じ行は
同じ優先順位
expr ::= expr PLUS expr | expr MINUS expr | expr TIMES expr | expr DIVIDE expr | MINUS expr %prec UMINUS ;
構文解析ルーチン生成系• ユーザ指定による競合の解決
– 生成規則の優先順位を強制的に変更する .<生成規則> %prec <終端記号>
他の入力よりも生成規則の順位が高い
還元が優先
precedence left PLUS, MINUS;precedence left TIMES, DIVIDE;precedence left UMINUS;
字句解析ルーチン生成系• Lex (LEXical analysis program generator)
• 処理系 ··· JLex
> java java_cup.Main < minimal.cup> java JLex.Main minimal.lex> mv minimal.lex.java Yylex.java> javac –d . *.java
java Jlex.MainLex による仕様記述minimal.lex
minimal.lex.java
Yylex クラスの定義を含む
実行: > java Example.parser
字句解析ルーチン生成系• ユーザコード
– package や import 宣言を記述.• Jlex 修飾子
– %{ と %} でくくった部分は,字句解析クラス内にコピー.– %init{ と %init} でくくった部分は,字句解析クラスの
コンストラクタにコピー.– %eofval{ と %eofval} でくくった部分は,ファイルの終わ
りに達したときに返す値を指定.– %line を指定すると, yyline 変数で,行番号を参照可.– %char を指定すると, yychar 変数で,文字数を参照可.– %cup を指定すると, CUP 用のインタフェースを備える.– <マクロ名> <正規表現>
・・・正規表現のマクロ指定. { マクロ名 } で参照
字句解析ルーチン生成系• 正規表現の記述
. ··· 改行を除く任意の文字[ ] ··· [ と ] で囲まれた文字の内,どれか1つ. ^ で始まると,その文字以外. - は範囲を意味する.* ··· 0個以上の繰返し+ ··· 1個以上の繰返し? ··· あるか無いか.| ··· どちらか一方^ ··· パターン先頭の ^ は,入力行の先頭.$ ··· パターン最後の $ は,入力行の最後
字句解析ルーチン生成系• グループ化と予約文字のエスケープ
( ) ··· パターンをまとめる.\ ··· 次の文字をエスケープする.” ” ··· ” と”で囲まれた部分をエスケープす
る.• 曖昧さを除去する規則
– 最長の文字列を表現するパターンを選択– 2箇所にマッチする場合は,最初のパターン
例 if8
コード生成• 計算コード
– 操作なし: nop– レジスタ( reg ):
%g0(=0),%g1,%g2,%g3,%g4,%g5,%g6,%g7%i0,%i1,%i2,%i3,%i4,%i5,%i6(%fp),%i7%o0,%o1,%o2,%o3,%o4,%o5,%o6(%sp),%o7%l0,%l1,%l2,%l3,%l4,%l5,%l6,%l7
– メモリ参照( mem ) : [%fp-offset]– メモリからレジスタへのロード: ld mem,reg– レジスタからメモリへのストア: st reg,mem– reg1 から reg2 への転送: mov reg1,reg2– reg1 と reg2 の加算(結果 reg3 ): add reg1,reg2,reg3– reg1 と reg2 の減算(結果 reg3 ): sub reg1,reg2,reg3– reg の反転: neg reg
コード生成• 関数( func )の呼出し: call func,0
手前でセットされた, %o0 の値が第1引数,%o1 が第2引数, %o2 が第3引数・・・.返値は %o0 .
• reg1 と reg2 の乗算:mov reg1,%o0call .umul,0mov reg2,%o1
• reg1 と reg2 の除算: .div を乗算と同様に呼び出す.• ラベル( label ): label: • 無条件ジャンプ:
b labelnop
コード生成• reg1 と reg2 の関係演算: cmp reg1,reg2• 条件ジャンプ: 次の命令の後に nop .
– > : bg label– < : bl label– >= : bge label– <= : ble label– == : be label– != : bne label
コード生成• データセグメントへの文字列( string )割付:
.seg “data”label: .ascii “string\0” .seg “text” .align 4
• データセグメントデータ( label )の reg へのロード:sethi %hi(label),tmpregor tmpreg,%lo(label),reg
コード生成• ( スタック上での ) データ領域の用意:
sethi %hi(label),tmpregadd tmpreg,%lo(label),regsave %sp,reg,%sp ・・・label = -areasize
• データ領域の開放:retrestore
コード生成• 入出力 scanf(“%d”,&mem) , printf(“%d”,re
g) :– 文字列部分は前もって IO0/IO1 (出 / 入)とし
て定義.IO0: .ascii "%d\0"IO1: .ascii "%d\0" .seg "text" .align 4