解析中に必要なコンテキストを保持する為に使用。
/* iniファイルに相当? */ class Project... //iniファイル内の各セクションに相当 class Project { public string Code { get; set; } //セクション名 public string Name { get; set; } //nameプロパティ public string Lead { get; set; } //leadプロパティ
/* iniファイルの解析(ビルダー)*/ class ProjectParser... private TextReader input; //プロジェクト(=iniファイル内のセクション)のリスト private List<Project> result = new List<Project>(); //現在のプロジェクト private Project currentProject; public ProjectParser(TextReader input) { this.input = input; } /* プロジェクトの解析 */ public List<Project> Run() { string line; //1行ずつ解析 while ((line = input.ReadLine()) != null) { parseLine(line); } return result; } /* 行単位で解析 */ private void parseLine(string s) { var line = removeComments(s); if (isBlank(line)) return ; else if (isSection(line)) parseSection(line); //セクションの解析 else if (isProperty(line)) parseProperty(line); //プロパティーの解析 else throw new ArgumentException("Unable to parse: " + line); } /* '#' 区切りの最初の文字列(コメント前の記述)を返す */ private string removeComments(string s) { return s.Split('#')[0]; } /* 空白のみかを判定 */ private bool isBlank(string line) { return Regex.IsMatch(line, @"^\s*$"); } /* セクション判定 */ private bool isSection(string line) { //0回以上の空白+ '[' で始まっているか? return Regex.IsMatch(line, @"^\s*\["); } /* セクションの解析 */ private void parseSection(string line) { // lineが"[任意の文字列]"にマッチした場合の"[任意の文字列]"の値 var code = new Regex(@"\[(.*)\]").Match(line).Groups[1].Value; //現在のセクション名でプロジェクトを作成 currentProject = new Project {Code = code}; //iniファイル内のセクションリストに追加 result.Add(currentProject); } /* プロパティー判定 */ private bool isProperty(string line) { // '='を含んでいるか? return Regex.IsMatch(line, @"="); } /* プロパティーの解析 */ private void parseProperty(string line) { //トークンの取得 var tokens = extractPropertyTokens(line); //トークン名でプロパティーを取得し、カレントプロジェクトにトークンの値を設定 setProjectProperty(tokens[0], tokens[1]); } /* プロパティーからトークンの抽出 */ private string[] extractPropertyTokens(string line) { char[] sep = {'='}; //行内の文字列を "="で分割(格納する配列のサイズは2) var tokens = line.Split(sep, 2); if (tokens.Length < 2) throw new ArgumentException("unable to split"); //名前と値をtokensに格納 for (var i = 0; i < tokens.Length; i++) tokens[i] = tokens[i].Trim(); return tokens; } /* セクションのプロパティを設定 */ private void setProjectProperty(string name, string value) { var proj = typeof(Project); var prop = proj.GetProperty(capitalize(name)); if (prop == null) throw new ArgumentException("Unable to find property: " + name); prop.SetValue(currentProject, value, null); } /* 先頭のみ大文字、以降は小文字に変換 */ private string capitalize(string s) { return s.Substring(0, 1).ToUpper() + s.Substring(1).ToLower(); }
コンテキストっていうから、実行環境の事かと思ったら、本当に「文脈」なのね・・・
様は、解析対象(意味論モデル)の内容を保持するクラスの作り方を書きたかった?