ANTLR4を使うと自分のプロジェクトに様々な言語のパーサーを実装できる。
ANTLR4の実行形式(javaの実行形式)を実行して、「パースしたい言語」のための、「実装したい言語」用のソースコードを生成する。
今回は、HTMLをパースするためのC++のソースコードを作成する。
こうして出力したC++のパース用コードは、ANTLR4のライブラリとリンクすることでコンパイルできるようになる。
https://www.antlr.org/download.html
URLから、Complete ANTLR 4.13.1 java binaries jarから、antlr-4.13.1-complete.jar をダウンロードする。
-Dlanguage=Cppを指定してC++のコードを出力することを指定。トークン定義ファイルHTMLLexer.g4と、HTMLParser.g4構文解析用のファイル。
実行はHTMLLexer.g4 → HTMLParser.g4 の順で行う。
以下が生成される:
・HTMLLexer.cpp
・HTMLLexer.h
・HTMLLexer.interp
・HTMLLexer.tokens
以下が生成される:
・HTMLParser.cpp
・HTMLParser.h
・HTMLParser.interp
・HTMLParser.tokens
・HTMLParserBaseListener.cpp
・HTMLParserBaseListener.h
・HTMLParserListener.cpp
・HTMLParserListener.h
以下のようなエラーが出る可能性がある(出た)。Java系のエラーなので新しいJavaをインストールして解決する。
このエラーは、「実行しようとしているツールはclass file version 55 (=Java 11)で作られているが、システムに入っているclass file version 52 (=Java 8)だ」という意味。
解決するために、今回は以下からJava 11 をダウンロードする。なおJava 11からJREがなくなったらしい。
https://www.oracle.com/jp/java/technologies/javase/jdk11-archive-downloads.html
なおダウンロードにはOracleプロファイルの作成が必要。勘弁してくれ。
生成したコードはそれだけでは動かないので、antlr4-devをCMakeする。
以下からantlr4のソースコードをダウンロードし、antlr4-dev をVC++用にCMakeにかける。
https://github.com/antlr/antlr4
antlr4-dev/runtime/Cpp/ にCMakeLists.txtがある。
CMAKE_INSTALL_PREFIXだけ好きな場所を指定し、後はそのままConfigure→Generate→Open Project。
・インクルードディレクトリに以下を追加
・追加のライブラリディレクトリに以下を追加
・C++言語標準を「ISO C++17標準」以上にする
・リンクするライブラリ
antlr4-runtime.lib
gmock.lib
gmock_main.lib
gtest.lib
gtest_main.lib
#include <iostream> #include "HTMLLexer.h" #include "HTMLParser.h" #include <antlr4-runtime.h> #pragma comment(lib,"antlr4-runtime.lib") #pragma comment(lib,"gmock.lib") #pragma comment(lib,"gmock_main.lib") #pragma comment(lib,"gtest.lib") #pragma comment(lib,"gtest_main.lib") int main(int, const char**) { // 入力 std::ifstream mysrc; mysrc.open("D:\\test.txt"); // ANTLR入力ストリームを作成 antlr4::ANTLRInputStream input(mysrc); // Lexer、トークンストリームを作成 HTMLLexer lexer(&input); antlr4::CommonTokenStream tokens(&lexer); // トークンストリームをパーサに渡す HTMLParser parser(&tokens); // HTML用のパーサなので最上位がhtmlDocument auto tree = parser.htmlDocument(); // ツリーを表示 std::cout << tree->toStringTree(&parser,true) << std::endl; return 0; }
<html> <head> <title>test</title> </head> <body> <p>test</p> </body> </html>
(htmlDocument (htmlElements (htmlElement < html > (htmlContent (htmlChardata \n) (htmlElement < head > (htmlContent (htmlElement < title > (htmlContent (htmlChardata test)) < / title >)) < / head >) (htmlChardata \n) (htmlElement < body > (htmlContent (htmlChardata \n) (htmlElement < p > (htmlContent (htmlChardata test)) < / p >) (htmlChardata \n)) < / body >) (htmlChardata \n)) < / html >)))