Quantcast
Channel: C#タグが付けられた新着記事 - Qiita
Viewing all articles
Browse latest Browse all 9749

Antlr4をC#から使ってみる #01

$
0
0

環境

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 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)

なぜ!?


Viewing all articles
Browse latest Browse all 9749

Trending Articles