単純な字句アナライザーを手作業で書くには、ANTLRもドラゴンブックも必要ありません。完全な言語(Javaなど)のための語彙アナライザでさえ、手作業で書くのはあまり複雑ではありません。 ANTLRやいくつかのレックス・バリアントのような産業用ツールを考慮する必要があるかもしれませんが、字句解析の仕組みを学ぶためには、手作業で書くことは有益なことになります。私はあなたがまだ初心者だと言ったので、これが当てはまると仮定しています。
ここでは、Javaで書かれたシンプルな字句アナライザをSchemeライクな言語のサブセットとして使用しています。私はコードが単に字句のストリーム(この場合はList<Token>
)に文字のストリーム(この場合はString
)を分割するだけでレクサーを見たことがなくても、比較的簡単に理解できると思いますハード。ご質問がある場合、私はより深く説明しようとすることができます。
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/
正規表現の実装に関するいくつかの記事(自動化された字句解析は、通常、正規表現を使用しています)
http://swtch.com/~rsc/regexp/
私は役立つことを望みます。がんばろう。
本当にありがとうございます。それは私をたくさん助けました。私はコンピュータサイエンスの学生としてこれらのことを学ぶ必要があるかどうか尋ねたいと思います。それは私の専攻との関連性は何ですか? – KLoverated
レキシカル分析は、解析する前に、コンパイラまたはインタプリタが行う最初のステップです。コンパイラ(とインタプリタ)は非常に便利で、一日中はマシンコードを書く必要があります。私は、CS学生がコンパイラを勉強すべきか否かについてコメントしません。私は彼らが彼ら自身の面白さが面白いと思っています。あなたが興味をそそるプログラマーなら、彼らがどのように機能するのか疑問に思うかもしれません。 CSにはたくさんの話題がありますが、理解の集大成は面白くないかもしれません。それも大丈夫です。つまり、一般的にコンパイラはCSと確かに関係しています。 – spacemanaki
あなたの考えを共有してくれてありがとう、ありがとう。コンパイル/コンパイルのプロセスを勉強することに興味があります。私はいつかそのデザインを夢見ていたからです。私が恐れるのは、私がそれをとてもよく理解できないかもしれないということです。私はまだ私は初心者だと言ったように。私はコンピューター・プログラミングについての知識がなくても、コンピューター・サイエンスを勉強し始めました。私はいつどこから始めるのだろうか。 – KLoverated