Microsoft PowerPoint - Compiler04note.ppt [互換モード]

Similar documents
Microsoft PowerPoint - Compiler04note.ppt [互換モード]

Microsoft PowerPoint - Compiler04note.ppt [互換モード]

Microsoft PowerPoint - Compiler03.pptx

Microsoft PowerPoint - Compiler03note.pptx

Microsoft PowerPoint - Compiler06note.pptx

Microsoft PowerPoint - Compiler06.pptx

Microsoft Word - Javacc.docx

Microsoft PowerPoint - Compiler10note.pptx

Microsoft PowerPoint - Compiler05.pptx

基礎プログラミング2015

Java講座

PowerPoint プレゼンテーション

Microsoft PowerPoint - Compiler05note.pptx

Microsoft PowerPoint - CproNt02.ppt [互換モード]

Microsoft PowerPoint - Compiler01note.pptx

Java プログラミング Ⅰ 7 回目 switch 文と論理演算子 今日の講義講義で学ぶ内容 switch 文 論理演算子 条件演算子 条件判断文 3 switch 文 switch 文 式が case のラベルと一致する場所から直後の break; まで処理しますどれにも一致致しない場合 def

情報工学実験 C コンパイラ第 2 回説明資料 (2017 年度 ) 担当 : 笹倉 佐藤

Prog1_6th

Microsoft Word - CompA-Ex doc

Microsoft Word - problem5.doc

JavaプログラミングⅠ

JavaプログラミングⅠ

Microsoft PowerPoint - Compiler15note.ppt [互換モード]

ポインタ変数

Microsoft Word - problem3.doc

ポインタ変数

JavaプログラミングⅠ

文法と言語 ー文脈自由文法とLR構文解析2ー

Microsoft PowerPoint ppt

情報処理Ⅰ

Microsoft PowerPoint - ruby_instruction.ppt


Taro-ファイル処理(公開版).jtd

Java プログラミング Ⅰ 7 回目 switch 文と論理演算子 条件判断文 3 switch 文 switch 文式が case の値と一致した場合 そこから直後の break; までを処理し どれにも一致しない場合 default; から直後の break; までを処理する 但し 式や値 1

Microsoft PowerPoint - 計算機言語 第7回.ppt

Java プログラミング Ⅰ 3 回目変数 変数 変 数 一時的に値を記憶させておく機能型 ( データ型 ) と識別子をもつ 2 型 ( データ型 ) 変数の種類型に応じて記憶できる値の種類や範囲が決まる 型 値の種類 値の範囲 boolean 真偽値 true / false char 2バイト文

Microsoft PowerPoint - 03BNFScanner.ppt [互換モード]

Microsoft Word - java a.doc

Javaプログラムの実行手順

ファイル操作

Java Scriptプログラミング入門 3.6~ 茨城大学工学部情報工学科 08T4018Y 小幡智裕

break 文 switch ブロック内の実行中の処理を強制的に終了し ブロックから抜けます switch(i) 強制終了 ソースコード例ソースファイル名 :Sample7_1.java // 入力値の判定 import java.io.*; class Sample7_1 public stati

char int float double の変数型はそれぞれ 文字あるいは小さな整数 整数 実数 より精度の高い ( 数値のより大きい より小さい ) 実数 を扱う時に用いる 備考 : 基本型の説明に示した 浮動小数点 とは数値を指数表現で表す方法である 例えば は指数表現で 3 書く

ポインタ変数

ガイダンス

18/12/06 情報工学実験 C コンパイラ (2018 年度 ) 担当 : 笹倉 佐藤 その 3 yacc の構造 定義部 %% 定義部の終了 規則部 %% 規則部の終了 ユーザ定義サブルーチン部 :C のプログラムを書く 形は lex と同じ 1

Microsoft PowerPoint - prog03.ppt

Prog1_3rd

JavaプログラミングⅠ

ソフトウェア基礎 Ⅰ Report#2 提出日 : 2009 年 8 月 11 日 所属 : 工学部情報工学科 学籍番号 : K 氏名 : 當銘孔太

2006年10月5日(木)実施

Microsoft PowerPoint - prog03.ppt

System.out.println("char : " + (int)character.min_value + "~" + (int)character.max_value); System.out.println("float : " + Float.MIN_VALUE + "~" + Flo

Microsoft PowerPoint - 03BNFScanner-print.ppt

Microsoft PowerPoint - OOP.pptx

Java プログラミング Ⅰ 3 回目変 数 今日の講義講義で学ぶ内容 変数とは 変数の使い方 キーボード入力の仕方 変 数 変 数 一時的に値を記憶させておく機能 変数は 型 ( データ型 ) と識別子をもちます 2 型 ( データ型 ) 変数に記憶する値の種類変数の型は 記憶できる値の種類と範囲

gengo1-6

デジタル表現論・第4回

問 次の Fortran プログラムの説明及びプログラムを読んで、設問に答えよ。

情報技術 Java の特徴 Java は現在 事務処理計算用プログラミング言語として開発された COBOL に取って代わり C 言語や C++ と並んで 現在最も使われているプログラミング言語の一つである Java は Write Once, Run Anywhere( プログラムを一度作成したらど

オブジェクト指向プログラミング・同演習 5月21日演習課題

情報工学実験 C コンパイラ第 2 回説明資料 (2018 年度 ) 担当 : 笹倉 佐藤

情報実習Ⅱ

Microsoft PowerPoint ppt

Prog1_12th

Microsoft PowerPoint - C_Programming(3).pptx

第12回 モナドパーサ

文字列 2 前回の授業ではコンピュータ内部での文字の取り扱い 文字型の変数 文字型変数への代入方法などを学習した 今回は 前回に引き続き 文字処理を学習する 内容は 標準入出力 ( キーボード ディスプレイ ) での文字処理 文字のファイル処理 文字を取り扱うライブラリ関数である 標準入出力 Lin

情報処理演習 B8クラス

* ライブラリ関数 islower(),toupper() を使ったプログラム 1 /* 2 Program : trupper.c 3 Student-ID : K 4 Author : TOUME, Kouta 5 Comments : Used Library function i

基本情報STEP UP演習Java対策

<4D F736F F D20438CBE8CEA8D758DC F0939A82C282AB2E646F63>

メソッドのまとめ

(1) プログラムの開始場所はいつでも main( ) メソッドから始まる 順番に実行され add( a,b) が実行される これは メソッドを呼び出す ともいう (2)add( ) メソッドに実行が移る この際 add( ) メソッド呼び出し時の a と b の値がそれぞれ add( ) メソッド

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

3,, となって欲しいのだが 実際の出力結果を確認すると両方の配列とも 10, 2, 3,, となってしまっている この結果は代入後の配列 a と b は同じものになっていることを示している つまり 代入演算子 = によるの代入は全要素のコピーではなく 先をコピーする ため 代入後の a と b は

文字列操作と正規表現

PowerPoint プレゼンテーション

プログラムの基本構成

スライド 1

画像ファイルを扱う これまでに学んだ条件分岐, 繰り返し, 配列, ファイル入出力を使って, 画像を扱うプログラムにチャレンジしてみよう

sinfI2005_VBA.doc

RX ファミリ用 C/C++ コンパイラ V.1.00 Release 02 ご使用上のお願い RX ファミリ用 C/C++ コンパイラの使用上の注意事項 4 件を連絡します #pragma option 使用時の 1 または 2 バイトの整数型の関数戻り値に関する注意事項 (RXC#012) 共用

Microsoft PowerPoint - 第3回目.ppt [互換モード]

メソッドのまとめ

コマンドラインから受け取った文字列の大文字と小文字を変換するプログラムを作成せよ 入力は 1 バイトの表示文字とし アルファベット文字以外は変換しない 1. #include <stdio.h> 2. #include <ctype.h> /*troupper,islower,isupper,tol

.NETプログラマー早期育成ドリル ~VB編 付録 文法早見表~

プログラミングA

JavaプログラミングⅠ

プログラミングA

<4D F736F F D2091E F196E291E889F090E C4816A82CC838C E646F6378>

Prog1_2nd

第10回 モジュール

PowerPoint プレゼンテーション

Microsoft Word - no103.docx

compiler-text.dvi

4 分岐処理と繰返し処理 ( 教科書 P.32) プログラムの基本的処理は三つある. (1) 順次処理 : 上から下に順番に処理する ぶんきそろ (2) 分岐処理 : 条件が揃えば, 処理する はんぷく (3) 反復処理 : 条件が揃うまで処理を繰り返す 全てのプログラムは (1) から (3) の

プログラミングA

Javaセキュアコーディングセミナー2013東京第1回 演習の解説

Javaによるアルゴリズムとデータ構造

Transcription:

コンパイラ 第 4 回字句解析 字句解析プログラムの作成 http://www.info.kindai.ac.jp/compiler 38 号館 4 階 N-411 内線 5459 takasi-i@info.kindai.ac.jp コンパイラの構造 字句解析系 構文解析系 制約検査系 中間コード生成系 最適化系 目的コード生成系 処理の流れ情報システムプロジェクト I の場合 write (ab); 字句解析系 write ( 変数名 ) ; 構文解析系 マイクロ構文の文法に従い解析 マクロ構文の文法に従い解析 <write_statement> ::= write ( <exp> ) ; コード生成系 VSM アセンブラの文法に従い生成 プログラムの構造 ( 字句解析系 ) FileScanner.java ファイル探査部 LexicalAnalyzer.java 字句解析部 char char nextchar(); Token nexttoken(); //1 文字読み込む // トークンを切り出す k 言語原始プログラム Token.java トークン定義部 Kc.java Token 構文解析部 Symbol.java トークン名列挙部 1. PUSH ab 2. OUTPUT FileScanner # ファイル探査部 - sourcefile : Scanner # 入力ファイルのスキャナ - line : String # 行バッファ - linenumber : int # 行カウンタ - columnnumber : int # 列カウンタ - currentcharacter : char # 読み取り文字 - nextcharacter : char # 次の読み取り文字 FileScanner (sourcefilename : String) # コンストラクタ closefile () : void # 入力ファイルを閉じる readnextline () : void # ファイルから 1 行読み込む nextchar () : char # 1 文字切り出す lookahead () : char # 次の読み取り文字を返す getline () : String # 読み取り行を返す scanat () : String # 読み取り位置を返す 文字の読み込み ( 情報システムプロジェクト I の場合 ) FileScanner.java /** * 入力ファイルから文字列を読み出し 字句解析器に1 文字ずつ渡すクラス */ class FileScanner { private Scanner sourcefile; // 入力ファイルのスキャナ private String line; // 行バッファ private int linenumber; // 行カウンタ private int columnnumber; // 列カウンタ private char currentcharacter; // 読み取り文字 private char nextcharacter; // 次の読み取り文字 1

文字の読み込み ( 情報システムプロジェクト I の場合 ) FileScanner.java /** * 現在読んでいる文字の次の文字を返し 1 文字読み進める * @return 次の文字 ( 行末なら n, ファイル末なら 0 ) */ char nextchar () { currentcharacter = nextcharacter; 走査位置を1 文字進める ; if ( 走査位置がファイル末か?) nextcharacter = 0 ; else if ( 走査位置が行末か?) nextcharacter = n ; else nextcharacter = 走査位置の文字 ; return currentcharacter; 字句解析系 (lexical analyzer, scanner) 字句解析系 空白 コメントを読み飛ばす 単語 (token) に区切る マイクロ構文エラーを検出 if (ans >= 123 ) /* ans の値で分岐 */ ( 改行 ) ( 空白 )print ( 1 ) ; 予約語 if 左括弧 ( 変数 ans 不等号 >= 整数 123 右括弧 ) 予約語 print : トークンの種類 ( 情報システムプロジェクトIの場合 ) トークン記号 区切り記号 ;, ( ) { [ ] 演算論理演算子! && 比較演算子 ==!= < > (<=) (>=) 算術演算子子算術演算子 + - * / % 代入演算子 = += -= *= /= ++ -- 変数名 定数 整数文字文字列 main int if while for inputint inputchar 予約語 outputint outputchar break (else) (do) (continue) Token クラス Token # トークン定義部 - symbol : Symbol # トークンの種類 - value : int # トークンの値 -name : String # トークンの Token (symbol : Symbol) # コンストラクタ Token (symbol : Symbol, value : int) # コンストラクタ Token (symbol : Symbol, name : String) # コンストラクタ checksymbol (symbol : Symbol) : boolean # トークンの種類を比較 getsymbol () : Symbol # トークンの種類を返す getvalue () : int # トークンの値を返す getname () : String # トークンのを返す Token クラス class Token { Symbol symbol; /* トークンの種類 */ int value; /* 整数値または文字コード */ String name; /* 変数名 */ トークン symbol value name main MAIN == EQUAL 123 INTEGER 123 a CHARACTER 97 ( a の文字コード ) time NAME time トークンへの分轄 if (ans >= 123 ) /* ans の値で分岐 */ ( 改行 ) ( 空白 )print ( 1 ) ; Token (IF) Token (LPAREN) Token (NAME) Token (GREATEQ) Token (INTEGER) Token (RPAREN) Token (PRINT) Token (LPAREN) Token (CHARACTER) Token (RPAREN) Token (SEMICOLON) 次のトークンを得る Token nexttoken() メソッドを作成 2

値を持つトークン 値を持つトークン 整数 ( 整数値 ) 文字 ( 文字コード ) 変数名 ( 文字列 ) 整数 0 12 256 Token (INTEGER) しかし整数は値を区別する必要がある Token (INTEGER, 0) Token (INTEGER, 12) Token (INTEGER, 256) 文字 a 変数名 time Token (CHARACTER, a ) Token (NAME, time ) LexicalAnalyzer クラス LexicalAnalyzer # 字句解析部 - sourcefilescanner : FileScanner # 入力ファイルの参照 LexicalAnalyzer (sourcefilename : String) # コンストラクタ closefile () : void # 入力ファイルを閉じる nexttoken () : Token # トークンを切り出す analyzeat () : String # 読み取り位置を返す - syntaxerror () : void # エラー検出時の処理 nexttoken() Token nexttoken () { Token token; 空白を読み飛ばす ; トークンを切り出す ; if ( ++ を切り出した場合 ) token = new Token (INC); else if ( + を切り出した場合 ) token = new Token (ADD); else if ( if を切り出した場合 ) token = new Token (IF); else if ( 整数を切り出した場合 ) token = new Token (INTEGER, value); else if ( を切り出した場合 ) token = new Token (NAME, name); : /* 以下各トークンに対する処理を else if で並べる */ else syntaxerror(); /* どのトークンとも一致しなかった場合はエラー */ 空白の読み飛ばし 空白, コメントは字句解析時に読み飛ばす 空白 : ( スペース ) n ( 改行 ) t ( タブ記号 ) コメント ( 拡張課題 ) : /* */ // n if (ans >= 123 ) /* ans の値で分岐 */ ( 改行 ) ( 空白 )print ( 1 ) ; if(ans>=123)print( 1 ); 空白の読み飛ばし char currentchar; // 現在位置の文字 do { currentchar = nextchar(); // 次の文字を読み込む while (currentchar == ); // 空白文字の間ループ n, t も同様に読み飛ばすコメントも読み飛ばすが処理が少し難しい ( コメントは発展課題 ) LexicalAnalyzer.java Token nexttoken() { String word = ; /* 文字列を単語に切り分ける */ while ( 単語が続く間 ) { String word += nextchar(); 単語が続く間 の判定はどのように行う? if (word が main ) token = new Token (MAIN); else if (word が if ) token = new Token (IF); else if (word が + ) token = new Token (ADD); else if (word が ++ ) token = new Token (INC); else if (word が 0 ) token = new Token (INTEGER); : 3

単語への分割英語の場合 School of Science and Engineering Kindai University 単語間に空白があるので区切るのは簡単 日本語の場合 きんきだいがくりこうがくぶ きんき : だいがく : りこうがくぶきんきだ : いがくり : こうが : くぶ 区切り方を正しく決定するのは困難計算機言語の場合は? 近畿大学理工学部近畿だイガ栗黄河九分 単語への分割計算機言語の場合区切り記号で単語を判別できる main () { m ain ( int i, j, k; : 区切り記号 ( が来たので main で区切ると判別 単語への分割どう区切る? +++---=== + + + - - - = = = ++ + -- - == = + ++ - -- = == ++ + -- -= == 文字列 ++ は INC? それとも ADD ADD? 記号トークン名 = ASSIGN == EQUAL + ADD - SUB += ASSIGNADD -= ASSIGNSUB ++ INC -- DEC 最長一致で判断 最長一致 (longest matching) 最長一致 複数の字句の可能性がある そのうち最長の字句であると認識きょうとふきょうとしきょうとふ : きょうとし京都府 : 京都市きょうと : ふきょう : とし京都 : 不況 : 都市きょう : とふ : きょうとし今日 : 塗布 : 京都市 最長の きょうとふ と認識 最長一致 とうきょうとっきょきょかきょくきょかきょくちょう とうきょうと : っきょきょかきょく~ 東京都 : っきょきょかきょく~ とうきょう : とっきょきょかきょく~ 東京 : 特許 : 許可局 : 許可局長 自然言語は最長一致では解決できない場合もある 計算機言語は基本的に最長一致で OK 最長一致 +++---=== 左から順に一致をチェック ++ + -- -= == 記号トークン名 = ASSIGN == EQUAL + ADD - SUB += ASSIGNADD -= ASSIGNSUB ++ INC -- DEC 4

最長一致 a <= b +++ +++ -++ a < = b a <= b + + + ++ + ++ + + ++ 空白で区切られている -+ + - ++ -+ というトークンは無い 123 1 2 3 123 main12 main 12 main12 ( 変数名 ) 最長一致 a+++b の構文木 <term> <factor> <exp> + <term> <factor> <unsigned> <unsigned> <name> a ++ (a++) + b <name> b 空白 a+ ++b の構文木 <exp> <term> + <term> <factor> <factor> <unsigned> <unsigned> <name> ++ <name> a b a + (++b) 字句解析オートマトン ( 一部 ) ; A Z a z _ ; = += + + ++ + = = = == 0 1 9 A Z a z _ 0 9 整数 整数 0 9 矢印を辿れる限り先へ進む 字句解析オートマトン ( 一部 ) ; A Z a z _ ; = += + + ++ + = = = == += の場合 0 1 9 A Z a z _ 0 9 整数 整数 0 9 矢印を辿れる限り先へ進む トークンの識別 if (ans>=123) print ( 1 ); Token (IF) Token (PRINT) Token (LPAREN) Token (LPAREN) Token (NAME, ans ) Token (CHARACTER, 1 ) Token (GREATEQ) Token (RPAREN) Token (INTEGER, 123) Token (SEMICOLON) Token (RPAREN) 変数名が ans で終わるとどうやって判定する? もしかしたら変数名 answer の一部かも? トークンの識別 A Z a z _ youare20yearsold = 変数名 youare20yearsold と識別 英数字が来る間ループ A Z a z _ 0 9 英数字以外 最後に読んだ = は? = は次のトークン ( の一部 ) 次のトークンの識別のため再度読む必要あり 先読みを行う 5

先読み (lookahead) 先読み トークンが終了するか否かを何文字か先の文字を読んで判定 多くの言語では1 文字先読みで判定できる = = = = 以外 == = 確定 これは先読み無しで == 確定 次の文字が = か先読みする 先読み Java, C, Pascal 等多くの言語 1 文字先読みすればトークンを識別可能 FORTRAN 無限に先読みが必要な可能性がある FORTRAN90 の場合 (FORTRAN では空白は無視される ) DO I=1, 20 コンマ DO I=1. 20 ピリオド DO( 予約語 ) I( 変数名 ) = 1, 20 DOI( 変数名 ) = 1.20,. まで読まないと DO と DOI を識別できない トークンの識別 = < <= < 先読み : = 以外 < 確定数字整数数字 英字 先読み : 数字以外整数確定 英数字 先読み : 英数字以外確定 if( トークンの識別 if(ans>=123 )print ( 1 ); 英数字以外が来た if で区切る ( ( は単独でトークン ans> 英数字以外が来た ans で区切る Token (IF) Token (LPAREN) Token (NAME, ans ) トークンの識別 if(ans>=123 )print ( 1 ); Token (IF) Token (PRINT) Token (LPAREN) Token (LPAREN) Token (NAME, ans ) Token (CHARACTER, 1 ) Token (GREATEQ) Token (RPAREN) Token (INTEGER, 123) Token (SEMICOLON) Token (RPAREN) if は if( まで読んで判定 ( は ( 単独で判定可能 ans は ans> まで読んで判定 先読み ( 情報システムプロジェクト I の場合 ) FileScanner.java /** * 現在読んでいる文字の次の文字を返す * @return 次の文字 ( 行末なら n, ファイル末なら 0 ) */ char lookahead () { if ( 次がファイル末か?) return 0 ; else if ( 次が行末か?) return n ; else return 次の文字 ; 6

記号解析部分のプログラム char currentchar; char nextchar(); char lookahead(); // 現在位置の文字 // 次の文字を読み込み 1 文字進める // 次の位置の文字の先読み 例 +, ++ の解析 if (currentchar == + ) +) { if (lookahead() == + ) { /* 1 文字先読みする */ nextchar(); /* 2 文字目の + を読む */ token = new Token (INC); /* ++ と判定 */ else { token = new Token (ADD) /* + と判定 */ 記号解析部分のプログラム char currentchar; // 現在位置の文字 char nextchar(); // 次の文字を読み込み1 文字進める char lookahead(); // 次の位置の文字の先読み例 -, -= の解析 if (currentchar == ){ -) if (lookahead() == = ) { /* 1 文字先読みする */ nextchar(); /* 2 文字目の = を読む */ token = new Token (ASSIGNSUB); /* -= と判定 */ else { token = new Token (SUB) /* - と判定 */ 整数の解析 整数 : 数字の並び 123 Token (INTEGER, 123) 0 0 1..9 数字 {0 9 整数 ループ部分は while 文で判定 0..9 0 は単独で整数 (007 は整数 0 整数 0 整数 7 と識別 ) 数値への変換, 数字の判定 int i; char c; boolean b; 数値への変換文字 1 整数 1 i = Character.digit (c, 10); i = c - 0 ; 数字か? 文字コード 0 の値を引く 10 進数 b = Character.isDigit (c); b = ( 0 <= c && c <= 9 ); b = (Character.digit (c, 10)!= -1); 数値への変換 2 桁以上の整数値への変換 値を10 倍して次の数値を足す を繰り返す例 : 123 1 10 12 120 123 *= 10; +=2; *= 10; +=3; 数値への変換, 数字の判定 (16 進数 ) int i; char c; boolean b; 数値への変換文字 c 整数 12 i = Character.digit (c, 16); 16 進数 i = c - 0 ; (c {0 9 のとき ) i = c a + 10; (c {A F のとき ) 数字か? b = ( 0 <= c && c <= 9 A <= c && c <= F ); b = (Character.digit (c, 16)!= -1); 7

整数解析部分のプログラム if (currentchar { 0 9 ) { int value = /* 文字 currentchar を数値に変換 */ while (lookahead() { 0 9 ) { /* 次が数字の間ループ */ currentchar = /* 次の数字を読む */ value *= /* 数値を 1 桁ずらす */ value += /* currentchar を数値に変換して加える */ token = new Token (INTEGER, value) /* 整数と判定 */ しかしこれでは 007 を整数 7 と判別してしまう 0 は別処理に 整数解析部分のプログラム if (currntchar == 0 ) { /* 先頭が0の場合は別処理 */ token = new Token (INTEGER, 0); /* 整数 0と判定 */ else if (currentchar { 1 9 ) { /* 0 以外の場合の処理 */ int value = /* 文字 currentcharを数値に変換 */ while (lookahead() { 0 9 9 {/* 次が数字の間ループ */ currentchar = /* 次の数字を読む */ value *= /* 数値を1 桁ずらす */ value += /* currentcharを数値に変換して加える */ token = new Token (INTEGER, value) /* 整数と判定 */ 整数解析部分のプログラム ( 値を文字列として記憶する場合 ) if (currntchar == 0 ) { /* 先頭が0の場合は別処理 */ token = new Token (INTEGER, 0); /* 整数 0と判定 */ else if (currentchar { 1 9 ) { String st = + currentchar; /* 文字列として記憶 */ while (lookahead() { 0 9 9 {/* 次が数字の間ループ */ currentchar = /* 次の数字を読む */ st += /* currentcharを文字列に追加 */ int value = /* 文字列 st を整数に変換 */ token = new Token (INTEGER, value) /* 整数と判定 */ 文字の解析 文字 : ( シングルクォート )*( 任意の文字 ) ( シングルクォート ) a Token (CHARACTER, 97( a の文字コード ) ) 任意の文字 文字コードへの変換 (Java の場合 ) int value; char ch = a ; value = (int) ch; * * 以外 構文解析エラー 文字解析部分のプログラム char currentchar; // 現在位置の文字 char nextchar(); // 次の文字を読み込み1 文字進める char lookahead(); // 次の位置の文字の先読み if (currentchar == ) { /* 1 文字目がシングルクォート */ currentchar = /* 2 文字目を読む */ value = /* currentcharを数値に変換 */ currentchar = /* 3 文字目を読む */ if (currentchar!= ) { /* 3 文字目がシングルクォート以外 */ syntaxerror(); /* 字句解析エラー */ token = new Token (CHARACTER, value); 特殊文字 Javaの特殊文字 記号 意味 n で1 文字 n 改行 t タブ r 行頭復帰 f 改ページ b バックスペース ( バックスラッシュ ) ( シングルクオート ) ( ダブルクオート ) uhhhh 文字コードhhhh(16 進数 ) の文字 8

( 特殊文字を含む ) 文字の解析 以外 n t * 以外 * K16 言語のマイクロ構文では特殊文字は不要 ( 特殊文字は発展課題 ) : シングルクォート : ダブルクォート : バックスラッシュ 構文解析エラー構文解析エラー if (currentchar == ) { /* 1 文字目がシングルクォート */ currntchar = nextchar(); /* 2 文字目を読む */ if (nextchar == ) { /* 2 文字目がバックスラッシュ */ currentchar = nextchar(); /* 3 文字目を読む */ if (currntchar == n ) value = (int) n ; else if (currentchar = t ) value = (int) t ; : else{ 特殊文字の処理 if (currentchar == ) syntaxerror(); /* 2 文字目が はエラー */ else value = (int) currentchar; /* 2 文字目の文字コードを記憶 */ currentchar = nextchar(); /* 3 文字目を読む */ if (currentchar!= ) syntaxerror(); token = new Token (CHARACTER, value); 変数名, 予約語 変数名, 予約語 : 英字の並び英字 {a z, A Z, _ 英数字 {a z, A Z, _, 0 9 英字 英数字 変数名も予約語も文法上の制約は同じ 英字の判定 char c; boolean b; 英小文字か? b = Character.isLowerCase (c); b = ( a <= c && c <= z ); 英大文字か? b = Character.isUpperCase (c); b = ( A <= c && c <= Z ); 変数名解析部分のプログラム char currentchar; char nextchar(); char lookahead(); // 現在位置の文字 // 次の文字を読み込み 1 文字進める // 次の位置の文字の先読み String name = ; if (currentchar {a z, A Z, _){ /* 1 文字目が英字 */ String name += /* currentcharを結合する */ while (lookahead() {a z, A Z, _, 0 9) { currentchar = /* 次の文字を読み込む */ name += /* currentcharを結合する */ token = new Token (NAME, name); /* 変数名と判定 */ 変数名解析部分のプログラム char currentchar; char nextchar(); char lookahead(); // 現在位置の文字 // 次の文字を読み込み 1 文字進める // 次の位置の文字の先読み ( 大文字のみの場合 ) String name = ; if (Character.isUpperCase (currentchar)) {/* 1 文字目が英字 */ String name += currentchar; /* 文字を記憶 */ while (Character.isUpperCase (lookahead()) { currentchar = nextchar(); /* 次の文字を読み込む */ name += currentchar; /* 文字を記憶 */ token = new Token (NAME, name); /* 変数名と判定 */ 予約語はどうする? 9

変数名と予約語の解析 m a i f n それ以外の英数字 IF i t INT n MAIN 変数名と予約語の解析 英字 英数字 1. ひとまず全て候補として単語に切る 2. 予約語と一致する単語は予約語とする 3. 予約語と一致しなかった単語は変数名とする 英数字 これでできなくはないが状態数が膨大になり非常に面倒 I if IF in inc int inter 変数名, 予約語解析部のプログラム String name = ; if (currentchar {a z, A Z, _) { String name += /* currentcharを結合する */ while (lookahead() {a z, A Z, _, 0 9) { currentchar = /* 次の文字を読み込む */ ここまで共通 name += /* currentchar を結合する */ /* 候補として最後まで name に取り込む */ if (name が main と一致 ) token = new Token (MAIN); /* 予約語 main と判定 */ else if (name が if と一致 ) token = new Token (IF); /* 予約語 if と判定 */ else token = new Token (NAME, name); /* 変数名と判定 */ 字句解析時のエラー処理 トークンとして切り出せなかった 字句解析エラー if ( 0 を切り出した場合 ) token = new Token (INTEGER,0); else if ( ++ を切り出した場合 ) token = new Token (INC); else if ( + を切り出した場合 ) token = new Token (ADD); else if ( if を切り出した場合 ) token = new Token (IF); : /* 以下各トークンに対する処理を else if で並べる */ else syntaxerror(); /* どのトークンとも一致しなかった場合はエラー */ エラー検出時はエラーメッセージを表示して停止 字句解析時のエラー処理 エラー検出時はエラーメッセージを表示して停止 private void syntaxerror () { String err_mes = analyzeat() + でエラー検出 ; /* analuzeat() を用いてエラーメッセージ作成 */ System.out.println (err_mes); /* エラーメッセージ表示 */ closefile (); /* 入力ファイルを閉じる */ System.exit (0); /* プロクラム停止 */ ファイル末到達時の処理 ファイル末到達時は Token (EOF) を返す ファイル末を示す文字 if (currntchar == 0 ) { /* ファイル末の場合 */ token = new Token (EOF); /* 特殊なトークン EOF */ エラー箇所がユーザに分かり易いエラーメッセージを作成する 10

Token nexttoken () { Token token = null; /* ダミーの初期値 */ do { currentchar = nextchar(); /* 1 文字目を読み込む */ while (currentchar == ); /* 空白以外を読み込むまで */ if (lookahead() == + ) { nextchar(); token = new Token (INC); else token = newtoken (ADD); else if : /* 以下各トークンに対する処理を else if で並べる */ else syntaxerror(); /* どのトークンとも一致しなければエラー */ nexttoken() m a i n ( ) { n t i n t i nextcharacter currentcharacter nexttoken() Token (MAIN) m a i n ( ) { n t i n t i nextcharacter currentcharacter m a i n ( ) { n t i n t i nextcharacter currentcharacter nexttoken() Token (LPAREN) 先読みを用いない字句解析 先読み文字が 1 文字の場合 先読み無しでも字句解析可能 currentchar = nextchar(); /* 読み進める */ /* 現在の文字で判定 */ nextchar(); token = new Token (INC); else token = newtoken (ADD); 先読みを用いない字句解析 先読みあり Token nexttoken() { Token token; /* 1 文字目は未読 */ currentchar = nextchar(); // 1 文字目 if (lookahead() == + ) { nextchar(); // 2 文字目 token = new Token (INC); else token = newtoken (ADD); 先読み無し Token nexttoken() { Token token; /* 1 文字目は既読 */ currentchar = nextchar(); // 2 文字目 nextchar(); // 3 文字目 token = new Token (INC); else token = newtoken (ADD); nexttoken() ( 先読み無しの場合 ) m a i n ( ) { n t i n t i nextcharacter currentcharacter nexttoken() Token (MAIN) m a i n ( ) { n t i n t i nextcharacter currentcharacter m a i n ( ) { n t i n t i nextcharacter currentcharacter nexttoken() Token (LPAREN) Token nexttoken () { 先読みあり Token token = null; do { currentchar = nextchar(); /* 1 文字目を読み込む */ while (currentchar == ); /* 空白を読み飛ばす */ if (lookahead() == + ) { /* 先読み文字で判定 */ nextchar(); /* 読み進める (2 文字目 ) */ token = new Token (INC); else token = newtoken (ADD); 11

Token nexttoken () { 先読み無し Token token = null; while (currentchar == ) /* 空白を読み飛ばす */ currentchar = nextchar(); currentchar = nextchar(); /* 読み進める (2 文字目 ) */ /* 現在の文字で判定 */ nextchar(); /* 読み進める (3 文字目 ) */ token = new Token (INC); else token = newtoken (ADD); 行単位での字句解析 文字単位ではなく行単位で解析する String line; // 現在解析中の行 String nextline(); // 入力ファイルから次の行を読み込む if (line.charat (0) == ( ) { /* 先頭の文字で判定 */ token = new Token (LPREN); line = line.substring (1); /* line の先頭の 1 文字を削る */ 記号解析部分のプログラム String line; 例 +, ++ の解析 // 現在解析中の行 if (line.charat (0) == + && line.charat (1) == + ) { /* 1 文字目と2 文字目の論理積で判定 */ token = new Token (INC); /* ++ と判定 */ line = line.substring (2); /* line の先頭の2 文字を削る */ else if (line.charat (0) == + ) { token = new Token (ADD); /* + と判定 */ line = line.substring (1); /* line の先頭の1 文字を削る */ 変数名解析部分のプログラム String line; 例変数名の解析 ( 手法 1) // 現在解析中の行 if (line.charat (0) {a z, A Z, _) { /* 1 文字目が英字 */ int i =1; while (line.charat (i) {a z, A Z, _, 0 9) ++i; /* 連続する英数字の文字数をカウントする */ name = line.substring (0, i); /* line の先頭から i 文字目までが変数名 */ line = line.substring (i); /* line を name の文字数文削る */ token = new Token (NAME, name); /* 変数名と判定 */ 変数名解析部分のプログラム String line; 例変数名の解析 ( 手法 2) // 現在解析中の行 if (line.charat (0) {a z, A Z,,_) { /* 1 文字目が英字 */ String[] subline = line.split ( [^a-za-z_0-9] ); /* line を英数字以外で分割 */ String name = subline[0]; /* 分割した先頭部分が */ line = line.substring (name.length()); /* line を name の文字数文削る */ token = new Token (NAME, name); /* 変数名と判定 */ Token nexttoken () { Token token = null; 行単位での字句解析 while (line.charat (0) == n ) line = readnextline(); /* 行末なら次の行を読み込む */ if (line.charat (0) == + && line.charat (1) == + ) { token = new Token (INC); /* ++ と判定 */ line = line.subset (2); /* 先頭の2 文字を削る */ else if (line.charat (0) == + ) { token = new Token (ADD); /* + と判定 */ line = line.subset (1); /* 先頭の1 文字を削る */ 12

行単位での字句解析の利点 2 文字以上先読み可能 文字列操作用のメソッドを利用可能 13