[解決済み】lexical Analyzerの作成
質問
私は今、Javaを使って、字句解析のプログラムを作っています。この問題に対する回答を探していますが、今まで何も見つけることができませんでした。以下は私の問題です。
入力
System.out.println ("Hello World");
希望する出力
Lexeme----------------------Token
System [Key_Word]
. [Object_Accessor]
out [Key_Word]
. [Object_Accessor]
println [Key_Word]
( [left_Parenthesis]
"Hello World" [String_Literal]
) [right_Parenthesis]
; [statement_separator]
まだまだ初心者なので、皆さんのお力をお借りできればと思います。ありがとうございます。
どのように解決するのですか?
ANTLRもDragon bookもなくても、簡単な字句解析器を手書きで書くことができます。Javaなど、より充実した言語の字句解析器でさえ、手で書くのはそれほど複雑ではありません。もちろん、産業用のタスクであれば、ANTLRやlexのような強力なツールを検討すべきですが、字句解析の仕組みを学ぶには、手作業で書くことが有効な練習になることが多いでしょう。あなたはまだ初心者とのことなので、このようなケースを想定しています。
この質問を見てから書いた、Schemeに似た言語のサブセットのための、Javaで書かれた簡単な字句解析器を紹介します。字句解析器を見たことがない人でも比較的理解しやすいコードだと思います。単に文字のストリーム(この場合は
String
)をトークン(この場合は
List<Token>
は、それほど難しいことではありません。もし質問があれば、もっと詳しく説明しますよ。
import java.util.List;
import java.util.ArrayList;
/*
* Lexical analyzer for Scheme-like minilanguage:
* (define (foo x) (bar (baz x)))
*/
public class Lexer {
public static enum Type {
// This Scheme-like language has three token types:
// open parens, close parens, and an "atom" type
LPAREN, RPAREN, ATOM;
}
public static class Token {
public final Type t;
public final String c; // contents mainly for atom tokens
// could have column and line number fields too, for reporting errors later
public Token(Type t, String c) {
this.t = t;
this.c = c;
}
public String toString() {
if(t == Type.ATOM) {
return "ATOM<" + c + ">";
}
return t.toString();
}
}
/*
* Given a String, and an index, get the atom starting at that index
*/
public static String getAtom(String s, int i) {
int j = i;
for( ; j < s.length(); ) {
if(Character.isLetter(s.charAt(j))) {
j++;
} else {
return s.substring(i, j);
}
}
return s.substring(i, j);
}
public static List<Token> lex(String input) {
List<Token> result = new ArrayList<Token>();
for(int i = 0; i < input.length(); ) {
switch(input.charAt(i)) {
case '(':
result.add(new Token(Type.LPAREN, "("));
i++;
break;
case ')':
result.add(new Token(Type.RPAREN, ")"));
i++;
break;
default:
if(Character.isWhitespace(input.charAt(i))) {
i++;
} else {
String atom = getAtom(input, i);
i += atom.length();
result.add(new Token(Type.ATOM, atom));
}
break;
}
}
return result;
}
public static void main(String[] args) {
if(args.length < 1) {
System.out.println("Usage: java Lexer \"((some Scheme) (code to) lex)\".");
return;
}
List<Token> tokens = lex(args[0]);
for(Token t : tokens) {
System.out.println(t);
}
}
}
使用例です。
~/code/scratch $ java Lexer ""
~/code/scratch $ java Lexer "("
LPAREN
~/code/scratch $ java Lexer "()"
LPAREN
RPAREN
~/code/scratch $ java Lexer "(foo)"
LPAREN
ATOM<foo>
RPAREN
~/code/scratch $ java Lexer "(foo bar)"
LPAREN
ATOM<foo>
ATOM<bar>
RPAREN
~/code/scratch $ java Lexer "(foo (bar))"
LPAREN
ATOM<foo>
LPAREN
ATOM<bar>
RPAREN
RPAREN
このような簡単なレキサーを1つか2つ書けば、この問題がどのように分解されるのか、かなりよくわかるようになるでしょう。そうなると、lexのような自動化ツールの使い方を探ってみるのも面白いかもしれません。正規表現ベースのマッチャーの理論はそれほど難しいものではありませんが、完全に理解するのには時間がかかります。正規表現を有限オートメーションに変換する理論(まずNFA、次にNFAからDFA)などに飛び込むよりも、手でレキサを書いた方がその勉強のモチベーションになり、問題を把握するのに役立つと思います。
個人的には、ドラゴンの本はとても丁寧で良いのですが、網羅性を目指しているため、必ずしもわかりやすいとは言えないかもしれません。ドラゴンの本を開く前に、他のコンパイラのテキストを試してみるのもいいかもしれません。以下に無料の本をいくつか紹介しますが、これらは入門書としてはかなり良い内容だと思います。
http://www.ethoberon.ethz.ch/WirthPubl/CBEAll.pdf
http://www.diku.dk/~torbenm/Basics/
正規表現の実装に関するいくつかの記事(自動字句解析には通常正規表現が使われます)
お役に立てれば幸いです。幸運を祈ります。
関連
-
[解決済み】"実引数リストと形式引数リストの長さが異なる"
-
[解決済み】javaで指定されたファイルが見つからない
-
[解決済み】Android java.lang.IllegalStateException: Android java.lang.IllegalStateException: Could not execute method of the activity
-
[解決済み】エラー「No enclosing instance of type Foo is accessible」の原因と修正方法について教えてください。
-
[解決済み] 解決済み】Javaが「型をインスタンス化できない」というエラーを返す [重複] [重複]
-
[解決済み】Hibernateの例外「failed to lazily initialize a collection of role」の解決方法
-
[解決済み】java.io.IOException: 壊れたパイプ
-
[解決済み】Eclipseで「JUnitテストが見つかりませんでした。
-
[解決済み】フォルダに書き込もうとすると「java.nio.file.AccessDeniedException」が発生する件
-
[解決済み] モックされたメソッドに渡された引数を返すようにする
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み】エラー「No enclosing instance of type Foo is accessible」の原因と修正方法について教えてください。
-
[解決済み】"|="の意味は何ですか?(パイプ等号演算子)
-
[解決済み】宣言されたパッケージが期待されるパッケージと一致しない ""
-
[解決済み] メソッドがスーパータイプのメソッドをオーバーライドまたは実装していない - Overrideの場合
-
[解決済み】Gradleがtools.jarを見つけ出さない
-
[解決済み】Eclipseで「公開型 <<classname>> は独自のファイルで定義する必要があります」エラー【重複あり
-
[解決済み】スレッド "main "での例外 java.util.NoSuchElementException
-
[解決済み】ソースルート外のJavaファイル intelliJ
-
[解決済み】intがnullであるかどうかを確認する方法
-
[解決済み] エラー - trustAnchors パラメータは空であってはなりません。