環境
Visual Studio 2017
Windows 10
セットアップ
ツール > 拡張機能と更新プログラム > antlrで検索
antlr language supportをダウンロード
Hello abc
趣味プログラミングの部屋の(01)ANTLR4をC#で使ってみるを参考に、簡単なプログラムを作る。
Hello.g4とProgram.csはこのサイトからの引用。
- 新規プロジェクト作成 コンソールアプリ(.NET Framework)
- antlr4パッケージインストール
nugetパッケージマネージャーコンソールで実行。
Install-Package antlr4 - Grammerファイル作成 ソリューションエクスプローラー > 追加 > ANTLR4 Combined Grammar
Hello.g4
// Define a grammar called Hello`
grammar Hello;
r : 'hello' ID ; // match keyword hello followed by an identifier
ID : [a-z]+ ; // match lower-case identifiers
WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines
- Program.cs編集
- using追加
using Antlr4.Runtime;
を追加。 - mainを書き換える
- using追加
using Antlr4.Runtime;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AntlrTest01
{
class Program
{
static void Main(string[] args)
{
string parsedString = "hello abc";
var inputStream = new AntlrInputStream(parsedString);
var lexer = new HelloLexer(inputStream);
var commonTokenStream = new CommonTokenStream(lexer);
var parser = new HelloParser(commonTokenStream);
HelloListener listener = new HelloListener();
parser.AddParseListener(listener);
var graphContext = parser.r();
Console.WriteLine(graphContext.ToStringTree());
}
}
}
- ビルドして実行
([] hello abc)
Listenerを使ってみる
グラマーファイルで定義したgrammerの名前 + 'BaseListener'という名前のクラスが自動生成されている。
この中ではグラマーファイルで定義したrの要素のListenerが定義されている。
この継承したクラスを定義し、Listenerをoverrideして作成しListenerを記述する。
HelloListener.cs
usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading.Tasks;usingAntlr4.Runtime.Misc;namespaceAntlrTest01{publicclassHelloListener:HelloBaseListener{publicoverridevoidExitR([NotNull]HelloParser.RContextcontext){base.ExitR(context);foreach(varchildincontext.children){Console.WriteLine("ExitR {0}",child.GetText());}}}}- mainでリスナーを設定
static void Main(string[] args)
{
string parsedString = "hello abc";
var inputStream = new AntlrInputStream(parsedString);
var lexer = new HelloLexer(inputStream);
var commonTokenStream = new CommonTokenStream(lexer);
var parser = new HelloParser(commonTokenStream);
HelloListener listener = new HelloListener(); //追加
parser.AddParseListener(listener); //追加
var graphContext = parser.r();
Console.WriteLine(graphContext.ToStringTree());
}
実行結果
ExitR hello
ExitR abc
([] hello abc)
疑問 Listnerができる条件は?
ラベルを使用したリスナーイベントによると、
#演算子で始まるルール内の代替ラベルにラベルを付けると、代替ラベルに対応するラベルごとにリスナー・メソッドを生成するようにANTLRに指示します。
r要素のListenerは定義されたが、ID,WSのListenerは無い。それらを作るには、#を付ければよいのだろうか。
やってみる。
Hello.g4
// Define a grammar called Hello`
grammar Hello;
r : 'hello' #ID ; // match keyword hello followed by an identifier
ID : [a-z]+ ; // match lower-case identifiers
WS : [ \t\r\n]+ -> skip ; // skip spaces, tabs, newlines
HelloListenerクラスに追加
public override void ExitID([NotNull] HelloParser.IDContext context)
{
base.ExitID(context);
Console.WriteLine("ExitID");
}
- 実行結果
ExitID
([] hello)
なぜ!?