現在ログインしていません。
新規アカウント作成
ログイン

Antlrの構文定義

もっとも基本的なルールは、セミコロンで終了する単純な名前です。

returnStmt: 'return' ;
■リスト1:単純な構文定義のルールの例

字句定義と同様に | を使って、「または」を表現することもできます。

構文定義のルールでは、そのルール内で別のルールを使用することがほとんどになります。

たとえば、次のreturnStmtというルールは、その中で別のルール WSとID を使用しています。 WSとIDは別の場所で字句定義されていることを想定しています。 慣習上WSという名前の字句定義はスペースやタブを表しています。

returnStmt: 'Return' WS+ ID ;
■リスト2:単純な構文定義のルールの例

ANTLRはパーサーのソースコードを生成するときに構文定義のルールごとにクラスを作成します。 この例では、構文定義はreturnStmtしかないので、パーサーにはreturnStmtContextというクラスが含まれます。

そして、そのルールの中で別のルール(上の例で言うとWSとID)を使用している場合、それらを取得するメソッドが生成されます。

つまり、この場合、WSメソッドとIDメソッドを持つreturnStmtContextクラスが生成されるということです。

理解を含めるために最終的にパーサーを使って構文解析するプログラムも紹介します。 この例では解析対象のソースコードは文字列で与えており「Return myValue」というごく短いソースコードです。 ここからパーサーを生成するまでに4行つかっています。この4行は説明したい部分ではないので割愛します。

パーサーを生成した後、returnStmtメソッドでReturn文の構造を取得します。これがReturnStmtContextクラスです。 ソースコードにReturnしかないと初めからわかっているのでこのようなことができます。本格的な解析ではループをまわしながら種類を判定していくような処理になると思います。

実際にReturnしている変数名(myValue)は、構文定義では ID としているので、IDメソッドで取得できます。最後に取得したものを文字列で取得するためにGetTextメソッドを呼び出しています。 この例を実行すると myValue と表示されます。

'▼解析対象のソースコード
Dim sourceCode As String = "Return myValue"

'▼パーサーの取得
Dim inputStream As New AntlrInputStream(sourceCode)
Dim lexer As New GrammarTestLexer(inputStream)
Dim commonTokenStream As New CommonTokenStream(lexer)
Dim parser As New GrammarTestParser(commonTokenStream)

'▼解析
Dim returnStmt As ReturnStmtContext = parser.returnStmt()

'IDを取得
Dim id As String = returnStmt.ID().GetText()
Console.WriteLine(id)

'終了待機
Console.ReadKey()
■リスト3:Visual Basic版。パーサーを使ってReturnしている変数を取得する例

//▼解析対象のソースコード
string sourceCode = "Return myValue";

//▼パーサーの取得
var inputStream = new AntlrInputStream(sourceCode);
var lexer = new GrammarTestLexer(inputStream);
var commonTokenStream = new CommonTokenStream(lexer);
var parser = new GrammarTestParser(commonTokenStream);

//▼解析
ReturnStmtContext returnStmt = parser.returnStmt();

//IDを取得
string id = returnStmt.ID().GetText();
Console.WriteLine(id);

//終了待機
Console.ReadKey();
■リスト4:C#版。パーサーを使ってReturnしている変数を取得する例

ルールの中で同じルールを複数参照している場合は、生成されるパーサーのメソッドでは順番を示す引数を受け取ることになります。

setExpression : ID '=' ID;
■リスト5:

この例ではIDを2つ使用しているので、生成されるパーサーのソースコードではSetExpressionContextクラスの中に引数つきのIDメソッドが生成されます。

このルールを解析するVBとC#のソースコードの例は次の通りです。

'▼解析対象のソースコード
Dim sourceCode As String = "myValue=startUpParam"

'▼パーサーの取得
Dim inputStream As New AntlrInputStream(sourceCode)
Dim lexer As New GrammarTestLexer(inputStream)
Dim commonTokenStream As New CommonTokenStream(lexer)
Dim parser As New GrammarTestParser(commonTokenStream)

'▼解析
Dim exp As SetExpressionContext = parser.setExpression()

'IDを取得
Console.WriteLine(exp.ID(0).GetText())    ' myValue
Console.WriteLine(exp.ID(1).GetText())    ' startUpParam

'終了待機
Console.ReadKey()

■リスト6:Visual Basic版。パーサーを使って代入式の右辺と左辺の変数名を取得する例

//▼解析対象のソースコード
string sourceCode = "myValue=startUpParam";

//▼パーサーの取得
var inputStream = new AntlrInputStream(sourceCode);
var lexer = new GrammarTestLexer(inputStream);
var commonTokenStream = new CommonTokenStream(lexer);
var parser = new GrammarTestParser(commonTokenStream);

//▼解析
SetExpressionContext exp = parser.setExpression();

//IDを取得
Console.WriteLine(exp.ID(0).GetText());    // myValue
Console.WriteLine(exp.ID(1).GetText());    // startUpParam

//終了待機
Console.ReadKey();
■リスト7:C#版。パーサーを使って代入式の右辺と左辺の変数名を取得する例

ルール名を使う変わりに、ラベルを使ってもっとスマートなプログラムにすることもできます。

setExpression : LeftSide=ID '=' RightSide=ID;
■リスト8:

この例は構文定義という意味では前の例と同じですが、生成されるパーサーに対して左辺のIDにLeftSideという名前を付け、右辺にRightSideという名前をつけるよう定義していることになります。この場合、LeftSideとRightSideはルールの別名ではなく、トークン自体を現すことになるのでVBやC#からアクセスするときの型も違います。

IDというルールを使ってはいるので、前の例と同じようにパーサーはIDメソッドも生成します。そのため前述のVBとC#のプログラムはそのままでも動作します。

ラベルをつけたトークンを使うと次のようにプログラムすることもできるようになります。

'▼解析対象のソースコード
Dim sourceCode As String = "myValue=startUpParam"

'▼パーサーの取得
Dim inputStream As New AntlrInputStream(sourceCode)
Dim lexer As New GrammarTestLexer(inputStream)
Dim commonTokenStream As New CommonTokenStream(lexer)
Dim parser As New GrammarTestParser(commonTokenStream)

'▼解析
Dim exp As SetExpressionContext = parser.setExpression()

'IDを取得
Console.WriteLine(exp.LeftSide.Text)    ' myValue
Console.WriteLine(exp.RightSide.Text)   ' startUpParam

'終了待機
Console.ReadKey()
■リスト9:Visual Basic版。ラベルで指定して代入式の右辺と左辺の変数名を取得する例

//▼解析対象のソースコード
string sourceCode = "myValue=startUpParam";

//▼パーサーの取得
var inputStream = new AntlrInputStream(sourceCode);
var lexer = new GrammarTestLexer(inputStream);
var commonTokenStream = new CommonTokenStream(lexer);
var parser = new GrammarTestParser(commonTokenStream);

//▼解析
SetExpressionContext exp = parser.setExpression();

//IDを取得
Console.WriteLine(exp.LeftSide.Text);    // myValue
Console.WriteLine(exp.RightSide.Text);   // startUpParam

//終了待機
Console.ReadKey();
■リスト10:C#版。ラベルで指定して代入式の右辺と左辺の変数名を取得する例