View on GitHub

Bve5_Parsing

.NET Parsing Library for BveTrainsim 5.

Bve5_Parsing 技術解説

面接の説明用と興味のある人向けのBve5_Parsing解説。

このライブラリについて

BveTrainsim5というソフトウェアのDSL(ドメイン特化言語)に対応したC#用パーサライブラリです。パースの処理にはパーサジェネレータであるANTLR4を利用。

BveTrainsim5とは、フリーの鉄道運転シミュレータで、用意された構文を用いて路線等を作成することが可能。 →簡単に言うと、電車でGo!みたいなもの。

ここでは一番複雑なマップ(路線)ファイル構文のパースについて紹介します。 構文一覧 → 公式サイト

マップファイル構文について

mapFile

パース処理の主な流れ

パースの処理はMapGrammarParserクラスParseメソッドで行っています。→ソースコードへ

処理の流れとしては、
字句解析 → 構文解析 → CST(具象構文木)の取得 → AST(抽象構文木)の作成 → ASTの評価
となっており、これらの内、字句解析と構文解析は後述の定義よりANTLR4が行ってくれます。

字句と構文の定義

字句解析器と構文解析器を生成する元となる、ANTLR4の文法ファイルの定義。

字句解析 MapGrammarLexer.g4

マップファイル構文における字句の定義。

構文解析 MapGrammarParser.g4

先ほどの字句を利用したマップファイル構文の定義。

以上の定義から、字句解析と構文解析を行い、CSTを作成します。

CST-Sample

この画像はCSTのサンプルです。Eclipseのプラグイン、ANTLR4 IDEを利用して出力したもの。

ASTの作成

上記のCSTから、必要な要素のみを抜き出したASTを作成します。

AST-Sample

画像は、先ほどのCSTから作成したASTのサンプルです。

まず、ASTのノードとなるクラスと、 それを継承した各ノードを定義します。 → AstNodes.cs
各ノードには保持する情報と子ノードを定義します。

続いて、CSTを訪れて必要な情報を抜き出し、ASTを作成します。
ANTLR4にはCSTをVisitorパターンを利用して巡回する、MapGrammarParserBaseVisitorクラスが用意されているので、このクラスを継承したBuildAstVisitorクラスでASTを作成します。 → ソースコードへ

ASTの評価

Bve5_Parsingでは、パースされた構文はMapDataクラスに代入して返します。 → MapData.cs
その為、ASTを巡回するVisitorクラスを用意し、ASTを評価(つまりMapDataクラスに代入)していきます。 → AstEvaluator.cs

字句解析・構文解析エラーの取得

ANTLR4では、BaseErrorListenerクラスをパーサに指定することで、エラーを取得することが出来ます。 → エラーリスナー指定部分
BaseErrorListenerクラスを継承したParseErrorListenerクラスを作成し、ライブラリの利用側でエラーの取得が出来るようにしました。 → ErrorListener.cs

実際の動作

サンプルとして簡単なマップファイルを用意しました。

  BveTs Map 2.02

  Structure.Load('Structures.csv');

  0;
    $Span = 100 - 95;
    $Interval = $Span * 2 - 5;

    Track['Me'].Position(0,0);
    Repeater['Track-Me'].Begin0('Me',3,$Span,$Interval,'Ballast5M');

このマップファイルを本家ソフトウェアで読み込むと以下のような路線がプレイできます。

SampleRoute

直線の単線が延々と続く路線です。

Bve5_Parsingに上記の入力を与え、返ってきたMapDataクラスを全てテキストで出力するプログラムを作成し、実際にパースしてみます。

その結果がこちら。

====================================
MapGrammar Parser Output:
Version: 2.02
Encoding:
StructureListPath: Structures.csv
StationListPath:
SignalListPath:
SoundListPath:
Sound3DListPath:
---------------SyntaxData----------------
Distance: 0
MapElement[0]: track
Key: Me
Function: position
Args:
x: 0
y: 0
---------------SyntaxData----------------
Distance: 0
MapElement[0]: repeater
Key: Track-Me
Function: begin0
Args:
trackkey: Me
tilt: 3
span: 5
interval: 5
key1: Ballast5M

StructureListPathにStructures.csv、続いてTrack構文とRepeater構文が0mに記述されている、ということが分かるかと思います。