赤宿 = Red Inn

素人の試行錯誤と2Dローグライク・ゲーム制作

Parsing in Amaranth

 Amaranthにおけるコンテンツのパースを具体的に把握する。単にソースを読めばいい気もするが……。自分の言葉を確かめつつ、備忘録として。

Overview

 regexによるmatchingを利用してファイルをパースし、文字列のデータをPropertyBagの木構造に変換する。個々のフィールド(: string)をパースし、特定のType Objectを生成する。

PropertyBag

 子を持てるstringのハッシュマップ。

Type Object

 オブジェクトの「型』を外部オブジェクトに依存させるデザインパタン。ここをデータ駆動にする。
 データをオブジェクトに変換するため、抽象化を挟められる。

余談: Property Bag Design Pattern
.propertyBag: HashMap をフィールドに加えることで、『サーバサイドのコードに手を加えずにプロパティの数を変更できる』。というのもデザインパタンらしい?

The File Format

 regexを用いて、以下の通り、パタンへの分解や、置換を行う。

  • '// comment'
  • '#include path'
  • 'name = value'
    • 名前を定義しなければ、プロパティの番号が名前(stringIndex)になる
  • 'name ='
    • 次の行からインデントしてa multi-line text property
    • 改行は空白文字に置換した形に変換される(インデントは削除)
  • 'name'
    • a collection property
    • 次の行からインデントすればchildの定義になる
  • ':: abstract' でcollection prop.の基底を定義
    • 'derivingCollection :: base' は基底に追記した形のデータとして振る舞う
      • 内部的にFlattenPropertiesに展開する形で実装
      • 当然、各データはoverridableになる

Regex (System.Text.RegularExpressions.Regex)

c.f. Character Classes in Regular Expressions
c.f. Best Practices for Regular Expressions in .NET

  • class Regex
    • ::Regex( pattern: string ) -> Self
    • .Match( input: string ) -> Match
  • class Match
    • .Groups: GroupCollection
      • Match.Groups[stringIndex] の形で用いられている
    • .Success: bool
      • : このKeyは見つかったか?
    • .Length: int
  • class GroupCollection

 なお、C#では@“string literal”の形で、エスケープ文字を使わずに文字列リテラルを書くことができる。(ただし”(double quotes)はエスケープされない)。

Parsing into PropertyBag-s

PropertyBag

 これの木構造に分解するのが目標。

  • .name, .value: string
  • .bases, .children: List<Self>
    • basesをあたってプロパティを遅延評価するような形 (故にoverridable)
  • .[stringIndex] -> Self: 子を探す
class IndentaionTree

 まず、これでインデントによる木構造に分ける。

  • .Parse( lines: IEnumerable<string> )
    • Stackを利用しながら、インデントに応じたツリー構造を構築する
    • 最後に.NormalizeIndentation() とし、空白の数 -> インデンテーションレベルに変換
  • .mIndent: int
  • .mText: string
  • .mChildren: List<Self>
PropertyBagParser

 次に、これで継承などを実装しつつ、文字列の木構造に変換する。

  • .sXxxRegex: Regex
    • パース用のstatic objects
      • .Match() すれば、key-valueペアに分解してくれる
    • Comment, Include, Line
      • sLineRegexでは、『基底』『継承』も扱われる
  • .Parse()
    • まずコメントや空白行を削除
    • 次にインデントの木構造(IndentationTree)に分解
    • 最後に.ParseTree()サブルーチンに委ねる
  • .ParseTree( tree: IT, parents: Stack<IT>, abstracts: Stack<IT> )
    • IT: IndentationTree
    • regexで頑張る