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

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

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

Microsoft PowerPoint - Compiler03note.pptx

Microsoft PowerPoint - Compiler03.pptx

Microsoft PowerPoint - Compiler06note.pptx

Microsoft PowerPoint - Compiler06.pptx

Microsoft Word - Javacc.docx

Microsoft PowerPoint - Compiler10note.pptx

基礎プログラミング2015

Microsoft PowerPoint - Compiler05.pptx

Java講座

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

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

PowerPoint プレゼンテーション

Microsoft Word - CompA-Ex doc

Microsoft Word - java a.doc

Microsoft PowerPoint - Compiler01note.pptx

Microsoft PowerPoint - Compiler05note.pptx

JavaプログラミングⅠ

JavaプログラミングⅠ

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

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

Prog1_6th

情報処理Ⅰ


メソッドのまとめ

Microsoft Word - problem3.doc

JavaプログラミングⅠ

ポインタ変数

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

JavaプログラミングⅠ

ポインタ変数

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

Microsoft Word - problem5.doc

Microsoft PowerPoint - ruby_instruction.ppt

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

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

Prog1_3rd

Javaプログラムの実行手順

ファイル操作

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

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

デジタル表現論・第4回

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

プログラミングA

Microsoft PowerPoint ppt

ガイダンス

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

Microsoft PowerPoint - prog03.ppt

<4D F736F F D2091E F196E291E889F090E C4816A82CC838C E646F6378>

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

プログラムの基本構成

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

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

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

Prog1_15th

ポインタ変数

Microsoft PowerPoint - prog03.ppt

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

スライド 1

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

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

Method(C 言語では関数と呼ぶ ) メソッドを使うと 処理を纏めて管理することができる 処理 ( メソッド ) の再実行 ( 再利用 ) が簡単にできる y 元々はC 言語の関数であり 入力値に対する値を 定義するもの 数学では F(x) = 2x + 1 など F(x)=2x+1 入力値 (

Prog1_2nd

基本情報STEP UP演習Java対策

プログラミング入門1

文字列操作と正規表現

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

gengo1-6

<4D F736F F D20438CBE8CEA8D758DC F0939A82C282AB2E646F63>

sinfI2005_VBA.doc

2006年10月5日(木)実施

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

Microsoft PowerPoint - C_Programming(3).pptx

Microsoft PowerPoint - OOP.pptx

第12回 モナドパーサ

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

PowerPoint プレゼンテーション

デジタル表現論・第6回

マークアップ言語

JavaプログラミングⅠ

教材ドットコムオリジナル教材 0から始めるiアフ リ リファレンス i アプリ簡易リファレンス ver i アプリ Java 独自のメソッド (1)iアプリの命令を使えるようにする import com.nttdocomo.ui.*; (2) 乱数を使う import java.u

K227 Java 2

Prog1_12th

JavaプログラミングⅠ

情報実習Ⅱ

GEC-Java

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

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

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

Microsoft PowerPoint - 03BNFScanner-print.ppt

メソッドのまとめ

Microsoft PowerPoint - kougi6.ppt

Prog1_10th

問題1 以下に示すプログラムは、次の処理をするプログラムである

プログラミングA

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

情報処理演習 B8クラス

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

プログラミングA

Transcription:

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

FileScanner (BufferdReaderクラス版) # ファイル探査部 - sourcefile : BufferedReader # 入力ファイルの参照 - 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 # 読み取り位置を返す 文字の読み込み FileScanner.java (BufferedReader クラス版 ) import java.nio.file.*; import java.io.*; /** * 入力ファイルから文字列を読み出し 字句解析器に1 文字ずつ渡すクラス */ class FileScanner { private BufferedReader sourcefile; // 入力ファイルの参照 private String line; // 行バッファ private int linenumber; // 行カウンタ private int columnnumber; // 列カウンタ private char currentcharacter; // 読み取り文字 private char nextcharacter; // 次の読み取り文字 文字の読み込み ( 情報システムプロジェクト 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 の値で分岐 */ ( 改行 ) ( 空白 )output ( 1 ) ; 予約語 if 左括弧 ( 変数 ans 不等号 >= 整数 123 右括弧 ) 予約語 output : トークンの種類 ) { [ ] ( 情報システムプロジェクトIの場合 ) トークン 記号 区切り記号 ;, ( 演比較演算子 ==!= < > (<=) (>=) 子算術演算子 + - * / % 算論理演算子! && 代入演算子 = += -= *= /= ++ -- 変数名 定数 整数文字 ( 文字列 ) 予約語 main int if while for inputint inputchar outputint outputchar break continue (for) (else) (do) Token クラス Token # トークン定義部 - symbol : Symbol # トークンの種類 - intvalue : int # トークンの値 - strvalue : String # トークンの Token (symbol : Symbol) # コンストラクタ Token (symbol : Symbol, intvalue : int) # コンストラクタ Token (symbol : Symbol, strvalue : String) # コンストラクタ checksymbol (symbol : Symbol) : boolean # トークンの種類を比較 getsymbol () : Symbol # トークンの種類を返す getintvalue () : int # トークンの値を返す getstrvalue () : String # トークンのを返す 2

Token クラス class Token { Symbol symbol; /* トークンの種類 */ int intvalue; /* 整数値または文字コード */ String strvalue; /* 変数名または文字列 */ トークン symbol intvalue strvalue main MAIN == EQUAL 123 INTEGER 123 a CHARACTER 97 ( a の文字コード ) time NAME time Token クラスのインスタンス Token token; main のトークン token = new Token (Symbol.MAIN); + のトークン token = new Token (Symbol.ADD); 以降は Symbol. は省略 トークンへの分轄 if (ans >= 123 ) /* ans の値で分岐 */ ( 改行 ) ( 空白 )output ( 1 ) ; Token (IF) Token (NAME) Token (GREATEQ) Token (INTEGER) Token (RPAREN) Token (OUTPUT) Token (CHARACTER) Token (RPAREN) Token (SEMICOLON) 次のトークンを得る Token nexttoken() メソッドを作成 値を持つトークン 値を持つトークン 整数 ( 整数値 ) 文字 ( 文字コード ) 変数名 ( 文字列 ) 整数 1 12 256 Token (INTEGER) しかし整数は値を区別する必要がある Token (INTEGER, 1) 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 = // ++ のト - クン生成 else if ( + を切り出した場合 ) token = // + のトークン生成 else if ( if を切り出した場合 ) token = // if のトークン生成 else if ( 整数を切り出した場合 ) token = // 整数のトークン生成 else if ( を切り出した場合 ) token = // のトークン生成 : /* 以下各トークンに対する処理を else if で並べる */ else syntaxerror(); /* どのトークンとも一致しなかった場合はエラー */ 3

空白の読み飛ばし 空白, コメントは字句解析時に読み飛ばす 空白 : ( スペース ) n ( 改行 ) t ( タブ記号 ) コメント ( 拡張課題 ) : /* */ // n if (ans >= 123 ) /* ans の値で分岐 */ ( 改行 ) ( 空白 )output ( 1 ) ; if(ans>=123)output( 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 (ZERO); : 単語への分割英語の場合 School of Science and Engineering Kindai University 単語間に空白があるので区切るのは簡単日本語の場合きんきだいがくりこうがくぶきんき : だいがく : りこうがくぶ近畿大学理工学部きんきだ : いがくり : こうが : くぶ近畿だイガ栗黄河九分 区切り方を正しく決定するのは困難計算機言語の場合は? 単語への分割計算機言語の場合区切り記号で単語を判別できる main () { int i, j, k; : main( 区切り記号 ( が来たので main で区切ると判別 単語への分割どう区切る? +++---=== + + + - - - = = = ++ + -- - == = + ++ - -- = == ++ + -- -= == 文字列 ++ は INC? それとも ADD ADD? 記号トークン名 = ASSIGN == EQUAL + ADD - SUB += ASSIGNADD -= ASSIGNSUB ++ INC -- DEC 最長一致で判断 4

最長一致 (longest matching) 最長一致 複数の字句の可能性がある そのうち最長の字句であると認識きょうとふきょうとしきょうとふ : きょうとし京都府 : 京都市きょうと : ふきょう : とし京都 : 不況 : 都市きょう : とふ : きょうとし今日 : 塗布 : 京都市 最長の きょうとふ と認識 最長一致 とうきょうとっきょきょかきょくきょかきょくちょう とうきょうと : っきょきょかきょく~ 東京都 : っきょきょかきょく~ とうきょう : とっきょきょかきょく~ 東京 : 特許 : 許可局 : 許可局長 自然言語は最長一致では解決できない場合もある 計算機言語は基本的に最長一致で OK 最長一致 +++---=== 左から順に一致をチェック ++ + -- -= == 記号トークン名 = ASSIGN == EQUAL + ADD - SUB += ASSIGNADD -= ASSIGNSUB ++ INC -- DEC 最長一致 a <= b +++ + ++ -++ a < = b a <= b + + + ++ + ++ + + ++ 空白で区切られている -+ + - ++ -+ というトークンは無い 123 1 2 3 123 main12 main 12 main12 ( 変数名 ) 字句解析オートマトン ( 一部 ) ; 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 矢印を辿れる限り先へ進む 5

トークンの識別 if (ans>=123) output ( 1 ); Token (IF) Token (NAME, ans ) Token (GREATEQ) Token (INTEGER, 123) Token (RPAREN) Token (OUTPUT) Token (CHARACTER, 1 ) Token (RPAREN) Token (SEMICOLON) 変数名が ans で終わるとどうやって判定する? もしかしたら変数名 answer の一部かも? トークンの識別 A Z a z _ youare20yearsold = 変数名 youare20yearsold と識別 英数字が来る間ループ A Z a z _ 0 9 英数字以外 最後に読んだ = は? = は次のトークン ( の一部 ) 次のトークンの識別のため再度読む必要あり 先読みを行う 先読み (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 で区切る ( ( は単独でトークン Token (IF) ans> 英数字以外が来た ans で区切る Token (NAME, ans ) 6

トークンの識別 if (ans>=123) output ( 1 ); Token (IF) Token (NAME, ans ) Token (GREATEQ) Token (INTEGER, 123) Token (RPAREN) Token (OUTPUT) Token (CHARACTER, 1 ) Token (RPAREN) Token (SEMICOLON) if は if( まで読んで判定 ( は ( 単独で判定可能 ans は ans> まで読んで判定 先読み ( 情報システムプロジェクト I の場合 ) FileScanner.java /** * 現在読んでいる文字の次の文字を返す * @return 次の文字 ( 行末なら n, ファイル末なら 0 ) */ char lookahead () { if ( 次がファイル末か?) return 0 ; else if ( 次が行末か?) return n ; else return 次の文字 ; 記号解析部分のプログラム char currentchar; // 現在位置の文字 char nextchar(); // 次の文字を読み込み1 文字進める char lookahead(); // 次の位置の文字の先読み 例 +, ++ の解析 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); 7

数値への変換 2 桁以上の整数値への変換 値を 10 倍して次の数値を足す を繰り返す 数値への変換, 数字の判定 (16 進数 ) int i; char c; boolean b; 数値への変換文字 c 整数 12 例 : 123 i = Character.digit (c, 16); 16 進数 1 10 12 120 123 *= 10; +=2; *= 10; +=3; 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); 整数解析部分のプログラム if (currentchar { 0 9 ) { int value = /* 文字 currentchar を数値に変換 */ while (lookahead() { 0 9 ) { /* 次が数字の間ループ */ currentchar = /* 次の数字を読む */ value *= /* 数値を 1 桁ずらす */ value += /* currentchar を数値に変換して加える */ token = /* 整数のトークン生成 */ しかしこれでは 007 を整数 7 と判別してしまう 0 は別処理に 整数解析部分のプログラム if (currntchar == 0 ) { /* 先頭が 0 の場合は別処理 */ token = /* 整数のトークン生成 */ else if (currentchar { 1 9 ) { /* 0 以外の場合の処理 */ int value = /* 文字 currentchar を数値に変換 */ while (lookahead() { 0 9 { /* 次が数字の間ループ */ currentchar = /* 次の数字を読む */ value *= /* 数値を 1 桁ずらす */ value += /* currentchar を数値に変換して加える */ token = /* 整数のトークン生成 */ 整数解析部分のプログラム ( 値を文字列として記憶する場合 ) if (currntchar == 0 ) { /* 先頭が 0 の場合は別処理 */ token = /* 整数のトークン生成 */ else if (currentchar { 1 9 ) { String st = + currentchar; /* 文字列として記憶 */ while (lookahead() { 0 9 { /* 次が数字の間ループ */ currentchar = /* 次の数字を読む */ st += /* currentchar を文字列に追加 */ int value = /* 文字列 st を整数に変換 */ token = /* 整数のトークン生成 */ 文字の解析 文字 : ( シングルクォート )*( 任意の文字 ) ( シングルクォート ) a Token (CHARACTER, 97( a の文字コード ) ) 任意の文字 * * 文字コードへの変換 (Java の場合 ) int value; char ch = a ; value = (int) ch; 以外 字句解析エラー 8

文字解析部分のプログラム char currentchar; char nextchar(); char lookahead(); // 現在位置の文字 // 次の文字を読み込み 1 文字進める // 次の位置の文字の先読み if (currentchar == ) { /* 1 文字目がシングルクォート */ currentchar = /* 2 文字目を読む */ value = /* currentchar を数値に変換 */ currentchar = /* 3 文字目を読む */ if (currentchar!= ) { /* 3 文字目がシングルクォート以外 */ syntaxerror(); /* 字句解析エラー */ token = /* 文字のトークン生成 */ 特殊文字 Javaの特殊文字 記号 意味 n で1 文字 n 改行 t タブ r 行頭復帰 f 改ページ b バックスペース ( バックスラッシュ ) ( シングルクオート ) ( ダブルクオート ) uhhhh 文字コードhhhh(16 進数 ) の文字 ( 特殊文字を含む ) 文字の解析 以外 n t * * K19 言語のマイクロ構文では特殊文字は不要 ( 特殊文字は発展課題 ) : シングルクォート : ダブルクォート : バックスラッシュ 字句解析エラー 以外 字句解析エラー 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 = /* 文字のトークン生成 */ 特殊文字の処理 変数名, 予約語 変数名, 予約語 : 英字の並び英字 {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 ); 9

変数名解析部分のプログラム 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 = /* 変数名のトークン生成 */ 変数名解析部分のプログラム 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 = /* 変数名のトークン生成 */ 予約語はどうする? 変数名と予約語の解析 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 = /* 変数名のトークン生成 */ 字句解析時のエラー処理 トークンとして切り出せなかった 字句解析エラー 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(); /* どのトークンとも一致しなかった場合はエラー */ エラー検出時はエラーメッセージを表示して停止 10

字句解析時のエラー処理 エラー検出時はエラーメッセージを表示して停止 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 */ エラー箇所がユーザに分かり易いエラーメッセージを作成する 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(); /* どのトークンとも一致しなければエラー */ コメント コメントの処理 戦略 1 : 空白と同様に処理 戦略 2 : 再帰で次のトークンを読む 以下では @... @ をコメントとする if (ans >= 123 ) @ コメント @ output @ コメント @ ( a ); コメント : 空白と同様に処理 while (currentchar == currentchar == @ ) { if (currentchar == ) // 空白の場合 currentchar = nextchar(); // 空白を読み飛ばす else { // @ の場合 currentchar = nextchar(); // 1つめの @ を読み飛ばす while (currentchar!= @ ) currntchar = nextchar(); // @ 以外を読み飛ばす currntchar = nextchar(); // 2つめの @ を読み飛ばす コメント : 再帰で次のトークンを読む if (currentchar == @ ) { currentchar = nextchar(); // 1つめの @ を読み飛ばす while (currentchar!= @ ) currntchar = nextchar(); // @ 以外を読み飛ばす currntchar = nextchar(); // 2つめの @ を読み飛ばす token = nexttoken(); // 再帰で次のトークンを読む /*... */ や //... ( 改行 ) にする方法は各自で考えること 11

nexttoken() 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 (MAIN) m a i n ( ) { n t i n t i nextcharacter currentcharacter nexttoken() 先読みを用いない字句解析 先読み文字が 1 文字の場合 先読み無しでも字句解析可能 currentchar = nextchar(); /* 読み進める */ /* 現在の文字で判定 */ nextchar(); token = new Token (INC); else token = newtoken (ADD); 先読みを用いない字句解析 先読みあり Token nexttoken() { Token token; 先読み無し Token nexttoken() { Token token; nexttoken() ( 先読み無しの場合 ) m a i n ( ) { n t i n t i nextcharacter currentcharacter nexttoken() Token (MAIN) /* 1 文字目は未読 */ currentchar = nextchar(); // 1 文字目 if (lookahead() == + ) { nextchar(); // 2 文字目 token = new Token (INC); else token = newtoken (ADD); /* 1 文字目は既読 */ currentchar = nextchar(); // 2 文字目 nextchar(); // 3 文字目 token = new Token (INC); else token = newtoken (ADD); 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 nexttoken () { Token token = null; do { currentchar = nextchar(); 先読みあり /* 1 文字目を読み込む */ Token nexttoken () { Token token = null; while (currentchar == ) currentchar = nextchar(); 先読み無し /* 空白を読み飛ばす */ while (currentchar == ); /* 空白を読み飛ばす */ if (lookahead() == + ) { /* 先読み文字で判定 */ nextchar(); /* 読み進める (2 文字目 ) */ token = new Token (INC); else token = newtoken (ADD); currentchar = nextchar(); /* 読み進める (2 文字目 ) */ /* 現在の文字で判定 */ nextchar(); /* 読み進める (3 文字目 ) */ token = new Token (INC); else token = newtoken (ADD); 12

行単位での字句解析 文字単位ではなく行単位で解析する 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 文字を削る */ 行単位での字句解析の利点 2 文字以上先読み可能 文字列操作用のメソッドを利用可能 13