簡単な字句アナライザーを手動で作成するのに、ANTLR も Dragon book も必要ありません。より完全な言語 (Java など) の語彙アナライザーでさえ、手作業で書くのはそれほど複雑ではありません。産業用のタスクがある場合は、ANTLR や lex バリアントなどの産業用ツールを検討することをお勧めしますが、字句解析がどのように機能するかを学習するためには、手動で作成することが有用な演習になる可能性があります。あなたはまだ初心者だと言ったので、これが事実だと思います。
これは、この質問を見た後に私が書いた、Scheme のような言語のサブセット用の Java で書かれた単純な語彙アナライザーです。String
文字のストリーム (この場合は a ) をトークンのストリーム(この場合は a ) に分割する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) に変換する背後にある理論に飛び込むよりも、勉強する動機を与え、問題を理解するのに役立つと思います。一度にたくさんのことを吸収する必要があり、圧倒されがちです。
個人的には、Dragon book は優れていて非常に徹底していますが、完全なものを目指しており、必ずしもアクセス可能であるとは限らないため、最も理解しやすいとは言えないかもしれません。ドラゴンの本を開く前に、他のいくつかのコンパイラ テキストを試してみることをお勧めします。ここにいくつかの無料の本がありますが、これらは入門的な内容がかなり充実しています。
http://www.ethoberon.ethz.ch/WirthPubl/CBEAll.pdf
http://www.diku.dk/~torbenm/Basics/
正規表現の実装に関するいくつかの記事 (自動字句解析では通常、正規表現が使用されます)
http://swtch.com/~rsc/regexp/
それが役立つことを願っています。幸運を。