第030回_条件付字句解析器6_NormalSectionLexer
»
今回は通常(NormalSection)の構文解析器 NormalSectionLexerについて検討します。
NormalSectionLexerの検討
NormalSectionは、WHITE_SPACE,WORD,SYMBOL,LITERAL,COMMENTをトークン化します。
■NormalSectionで扱う各トークンの定義のおさらい
■仕様
■NormalSectionで扱う各トークンの定義のおさらい
WHITE_SPACE ::= (#x20 | #x9 | #xD | #xA)+ |
WORD ::= (":" | [A−Z] | "_" | [a−z] | [#xC0−#xD6] | [#xD8−#xF6] |
| [#xF8−#x2FF] | [#x370−#x37D] | [#x37F−#x1FFF] |
| [#x200C−#x200D] | [#x2070−#x218F] | [#x2C00−#x2FEF] |
| [#x3001−#xD7FF] | [#xF900−#xFDCF] | [#xFDF0−#xFFFD] |
| [#x10000−#xEFFFF] | "−" | "." | [0−9] | #xB7 |
| [#x0300−#x036F] | [#x203F−#x2040] |
)+ |
LITERAL ::= '"' '"'以外の文字 '"' | "'" "'"以外の文字 "'" |
SYMBOL ::= '#FIXED' | '#IMPLIED' | '#PCDATA' | '#REQUIRED' | '%' |
| '&#' | '&#x' | '&' | '(' | ')' | ')?' | ')*' | ')+' | '*' | '+' | ',' | '/>' | ';' |
| '=' | '<'| '</' | '<?' | '<?xml' | '<![' | '<![CDATA[' | '<!ATTLIST' |
| '<!DOCTYPE' | '<!ENTITY' | '<!ELEMENT' | '<!NOTATION' | '>' |
| '?' | '?>' | '[' | ']' | ']]>' | '|' |
COMMENT ::= '<!−−' 連続した'−−'をもたない文字列 '−−>' |
各トークンについて1文字目で整理すると次のようになります。
記号 | UniCode | 処理 |
―――――――――――――――――――――――――――――――――――――― | ||
#x0009 | 初期化して、WhiteSpaceTokenizerへ移動する | |
'\n' | #x000A | 初期化して、WhiteSpaceTokenizerへ移動する |
'\r' | #x000D | 初期化して、WhiteSpaceTokenizerへ移動する |
#x0020 | 初期化して、WhiteSpaceTokenizerへ移動する | |
"\"" | #x0022 | 初期化して、DoubleQuoteTokenizerへ移動する |
"#" | #x0023 | 初期化して、SymbolListTokenizer(FIXED,IMPLIED,PCDATA,REQUIRED)へ移動する |
"%" | #x0025 | 初期化して、JustCreateSymbolTokenizerへ移動する |
"&" | #x0026 | 初期化して、SymbolListTokenizer2へ移動する |
"'" | #x0027 | 初期化して、QuoteTokenizerへ移動する |
"(" | #x0028 | 初期化して、JustCreateSymbolTokenizerへ移動する |
")" | #x0029 | 初期化して、SymbolListTokenizer2へ移動する |
"*+," | #x002A-#x002C | 初期化して、JustCreateSymbolTokenizerへ移動する |
"-." | #x002D-#x002E | 初期化して、WordTokenizerへ移動する |
"/" | #x002F | 初期化して、SymbolTokenizer(>)へ移動する |
"0-9:" | #x0030-#x003A | 初期化して、WordTokenizerへ移動する |
";" | #x003B | 初期化して、JustCreateSymbolTokenizerへ移動する |
"<" | #x003C | 初期化して、LeftAngleTokenizerへ移動する |
"=>" | #x003D-#x003E | 初期化して、JustCreateSymbolTokenizerへ移動する |
"?" | #x003F | 初期化して、SymbolTokenizer2へ移動する |
"A-Z" | #x0041-#x005A | 初期化して、WordTokenizerへ移動する |
"[" | #x005B | 初期化して、JustCreateSymbolTokenizerへ移動する |
"]" | #x005D | 初期化して、SymbolTokenizer2へ移動する |
"_" | #x005F | 初期化して、WordTokenizerへ移動する |
"a-z" | #x0061-#x007A | 初期化して、WordTokenizerへ移動する |
"|" | #x007C | 初期化して、JustCreateSymbolTokenizerへ移動する |
#x00B7 | 初期化して、WordTokenizerへ移動する | |
#x00C0-#x00D6 | 初期化して、WordTokenizerへ移動する | |
#x00D8-#x00F6 | 初期化して、WordTokenizerへ移動する | |
#x00F8-#x02FF | 初期化して、WordTokenizerへ移動する | |
#x0300-#x036F | 初期化して、WordTokenizerへ移動する | |
#x0370-#x037D | 初期化して、WordTokenizerへ移動する | |
#x037F-#x1FFF | 初期化して、WordTokenizerへ移動する | |
#x200C-#x200D | 初期化して、WordTokenizerへ移動する | |
#x203F-#x2040 | 初期化して、WordTokenizerへ移動する | |
#x2070-#x218F | 初期化して、WordTokenizerへ移動する | |
#x2C00-#x2FEF | 初期化して、WordTokenizerへ移動する | |
#x3001-#xD7FF | 初期化して、WordTokenizerへ移動する | |
#xF900-#xFDCF | 初期化して、WordTokenizerへ移動する | |
#xFDF0-#xFFFD | 初期化して、WordTokenizerへ移動する | |
その他 | 初期化してUnknownTokenを作成する | |
EOF | EofTokenを作成する |
NormalSectionLexerの実装
public class NormalSectionLexer extends MapSwitchLexer
{
private static NormalSectionLexer m_instance = new NormalSectionLexer();
private NormalSectionLexer()
{
super();
Init_MovePos wordTokenizer
= new Init_MovePos(new WordTokenizer());
Init_MovePos whiteSpaceTokenizer
= new Init_MovePos(new WhiteSpaceTokenizer());
Init_MovePos doubleQuoteTokenizer
= new Init_MovePos(new DoubleQuoteTokenizer());
Init_MovePos quoteTokenizer
= new Init_MovePos(new QuoteTokenizer());
ArrayList<String> list = new ArrayList<String>();
list.add("FIXED");
list.add("IMPLIED");
list.add("PCDATA");
list.add("REQUIRED");
Init_MovePos numberSignTokenizer
= new Init_MovePos(new SymbolListTokenizer(list));
Init_MovePos oneCharSymbol
= new Init_MovePos(new JustCreateSymbolTokenizer());
ArrayList<String> list2 = new ArrayList<String>();
list2.add("#x");//先に#xを評価させないと#でOKになってしまうので注意
list2.add("#");
Init_MovePos ampersandTokenizer
= new Init_MovePos(new SymbolListTokenizer2(list2));
ArrayList<String> list3 = new ArrayList<String>();
list3.add("*");//先に#xを評価させないと#でOKになってしまうので注意
list3.add("?");
list3.add("+");
Init_MovePos rightParenTokenizer
= new Init_MovePos(new SymbolListTokenizer2(list3));
Init_MovePos slashTokenizer
= new Init_MovePos(new SymbolTokenizer(">"));
Init_MovePos leftAngleTokenizer
= new Init_MovePos(new LeftAngleTokenizer());
Init_MovePos questionMarkTokenizer
= new Init_MovePos(new SymbolTokenizer2(">"));
Init_MovePos rightBracketTokenizer
= new Init_MovePos(new SymbolTokenizer2("]>"));
Init_MovePos unknownTokenizer
= new Init_MovePos(new UnknownTokenizer());
EofTokenizer eof = new EofTokenizer();
m_map.put('\u0009' , whiteSpaceTokenizer);
m_map.put('\n' , whiteSpaceTokenizer);//u000A
m_map.put('\r' , whiteSpaceTokenizer);//u000D
m_map.put('\u0020' , whiteSpaceTokenizer);
m_map.put('\u0022' , doubleQuoteTokenizer);
m_map.put('\u0023' , numberSignTokenizer);
m_map.put('\u0025' , oneCharSymbol);
m_map.put('\u0026' , ampersandTokenizer);
m_map.put('\'' , quoteTokenizer);//u0027
m_map.put('\u0028' , oneCharSymbol);
m_map.put('\u0029' , rightParenTokenizer);
m_map.put('\u002A', '\u002C', oneCharSymbol);
m_map.put('\u002D', '\u002E', wordTokenizer);
m_map.put('\u002F' , slashTokenizer);
m_map.put('\u0030', '\u003A', wordTokenizer);
m_map.put('\u003B' , oneCharSymbol);
m_map.put('\u003C' , leftAngleTokenizer);
m_map.put('\u003D', '\u003E', oneCharSymbol);
m_map.put('\u003F' , questionMarkTokenizer);
m_map.put('\u0041', '\u005A', wordTokenizer);
m_map.put('\u005B' , oneCharSymbol);
m_map.put('\u005D' , rightBracketTokenizer);
m_map.put('\u005F' , wordTokenizer);
m_map.put('\u0061', '\u007A', wordTokenizer);
m_map.put('\u007C' , oneCharSymbol);
m_map.put('\u00B7' , wordTokenizer);
m_map.put('\u00C0', '\u00D6', wordTokenizer);
m_map.put('\u00D8', '\u00F6', wordTokenizer);
m_map.put('\u00F8', '\u02FF', wordTokenizer);
m_map.put('\u0300', '\u036F', wordTokenizer);
m_map.put('\u0370', '\u037D', wordTokenizer);
m_map.put('\u037F', '\u1FFF', wordTokenizer);
m_map.put('\u200C', '\u200D', wordTokenizer);
m_map.put('\u203F', '\u2040', wordTokenizer);
m_map.put('\u2070', '\u218F', wordTokenizer);
m_map.put('\u2C00', '\u2FEF', wordTokenizer);
m_map.put('\u3001', '\uD7FF', wordTokenizer);
m_map.put('\uF900', '\uFDCF', wordTokenizer);
m_map.put('\uFDF0', '\uFFFD', wordTokenizer);
m_map.setOutOfRange(unknownTokenizer);
m_map.setEofFunctor(eof);
}
public static NormalSectionLexer getInstance()
{
return m_instance;
}
}
NormalSectionLexerで必要なTokenizerの実装
NormalSectionLexerで出現した未解説のクラスについて紹介しておきます。中身は単純ですので細かい説明をしなくても良いと思います。
■WhiteSpaceTokenizer
■LiteralTokenizer
■QuoteTokenizer
長くなりましたので、残りの未解説クラスは次回のコラムで説明します。
■WhiteSpaceTokenizer
public class WhiteSpaceTokenizer extends MapSwitchTokenizer
{
private class WhiteSpaceTokenMaker implements Functor
{
public WhiteSpaceTokenMaker(){}
@Override
public Token tokenize(StringBuilder str, int pos)
{
return new WhiteSpaceToken();
}
}
public WhiteSpaceTokenizer()
{
//
// 記号 処理
// -----------------------------------------------------
// \r 今の文字を確定して次へ
// \n 今の文字を確定して次へ
// \u0009 今の文字を確定して次へ
// \u0020 今の文字を確定して次へ
// その他 WHITE_SPACEを作成する
// EOF WHITE_SPACEを作成する
//
// 処理1:今の文字を確定して次へ
// 処理2:WHITE_SPACEを作成する
//
Update_MovePos proc1 = new Update_MovePos();
WhiteSpaceTokenMaker proc2 = new WhiteSpaceTokenMaker();
m_map.put('\r' , proc1);
m_map.put('\n' , proc1);
m_map.put('\u0009', proc1);
m_map.put('\u0020', proc1);
m_map.setOutOfRange(proc2);
m_map.setEofFunctor(proc2);
}
}
NormalSectionLexerで出てくるDoubleQuoteTokenizerとQuoteTokenizerについて検討します。
どちらのトークナイザも終了文字までを読み込むという意味では同じなので処理もほぼ同じにできます。そこで共通の親となるLiteralTokenizerを作成します。
■DoubleQuoteTokenizerどちらのトークナイザも終了文字までを読み込むという意味では同じなので処理もほぼ同じにできます。そこで共通の親となるLiteralTokenizerを作成します。
public abstract class LiteralTokenizer extends MapSwitchTokenizer
{
private class LiteralTokenMaker implements Functor
{
public LiteralTokenMaker(){}
@Override
public Token tokenize(StringBuilder str, int pos)
{
m_tokenBuilder.update(m_char);
return new LiteralToken();
}
}
public LiteralTokenizer(char endChar)
{
//
// 記号 処理
// -----------------------------------------------------
// endChar 今の文字を確定して、LITERALを作成する
// その他 今の文字を確定して次へ
// EOF UnKnownTokenを作成する
//
// 処理1:今の文字を確定して、LITERALを作成する
// 処理2:今の文字を確定して次へ
// 処理3:UnKnownTokenを作成する
//
LiteralTokenMaker proc1 = new LiteralTokenMaker();
Update_MovePos proc2 = new Update_MovePos();
UnknownTokenizer proc3 = new UnknownTokenizer();
m_map.put(endChar, proc1);
m_map.setOutOfRange(proc2);
m_map.setEofFunctor(proc3);
}
}
public class DoubleQuoteTokenizer extends LiteralTokenizer
{
public DoubleQuoteTokenizer()
{
super('"');
}
}
public class QuoteTokenizer extends LiteralTokenizer
{
public QuoteTokenizer()
{
super('\'');
}
}
コメント
コメントを投稿する
SpecialPR