ANTLR(Another Tool for Language Recognition)是一个强大的语言识别器生成器,最新的版本是ANTLR4。笔者使用C++进行开发。
首先配置ANTLR4环境,并了解基础的ANTLR4语法(.g4文件),相关参考文章:
然后开始学习ANTLR4 C++接口的配置使用:
Antlr4安装与使用(包括python3与C++版本) - 知乎
https://github.com/antlr/antlr4/tree/master/runtime/Cpp
然后听从学长建议,开始学习WSL2:
4.30更新:找到了一个好的手册ANTLR v4 中文文档
还有:ANTLR Parsing and C++, Part 1: Introduction - CodeProject
老师提供的资料:Getting Started with ANTLR in C++ - Strumenta
在学习过程中遇到了一些问题,首先就是学习C++接口。笔者按照教程生成了demo的C++源文件和头文件,然后阅读其源代码,试图摸清楚其原理。
先看main.cpp:
/* Copyright (c) 2012-2017 The ANTLR Project. All rights reserved.
* Use of this file is governed by the BSD 3-clause license that
* can be found in the LICENSE.txt file in the project root.
*/
//
// main.cpp
// antlr4-cpp-demo
//
// Created by Mike Lischke on 13.03.16.
//
#include <iostream>
#include "antlr4-runtime.h"
#include "TLexer.h"
#include "TParser.h"
#include <Windows.h>
#pragma execution_character_set("utf-8")
using namespace antlrcpptest;
using namespace antlr4;
int main(int argc, const char * argv[]) {
ANTLRInputStream input("a = b + \"c\";(((x * d))) * e + f; a + (x * (y ? 0 : 1) + z);");
TLexer lexer(&input);
CommonTokenStream tokens(&lexer);
TParser parser(&tokens);
tree::ParseTree *tree = parser.main();
auto s = tree->toStringTree(&parser);
std::cout << "Parse Tree: " << s << std::endl;
return 0;
}
我们逐句分析:
首先来看头文件:
#include "antlr4-runtime.h"
#include "TLexer.h"
#include "TParser.h"
antlr4-runtime.h:
这是 ANTLR 4 C++ 运行时库的头文件。ANTLR 4 C++ 运行时库包含了用于解析、分析和处理由 ANTLR 生成的词法和语法分析器所需的类和函数。这个头文件包含了 ANTLR 运行时库的所有公共接口和声明。
TLexer.h:
这是由 ANTLR 工具生成的词法分析器的头文件。ANTLR 使用语法规则描述语言的词法和语法结构,然后根据这些规则生成相应的词法分析器和语法分析器。TLexer.h 中定义了由 ANTLR 自动生成的词法分析器类的声明和接口。
TParser.h:
这是由 ANTLR 工具生成的语法分析器的头文件。语法分析器用于根据语法规则解析输入文本,并构建相应的语法树或执行相应的语义动作。TParser.h 中定义了由 ANTLR 自动生成的语法分析器类的声明和接口。
接下来
#pragma execution_character_set
这行代码是一个预处理指令,用于指定源文件的执行字符集为 UTF-8。在 C++ 中,源文件的默认字符集通常是由编译器或环境决定的,但是通过使用 #pragma execution_character_set
可以显式地指定源文件的执行字符集。
在main主程序中,第一句
ANTLRInputStream input("a = b + \"c\";(((x * d))) * e + f; a + (x * (y ? 0 : 1) + z);");
定义了一个ANTLRInputStream类变量input,input通过类的构造函数赋值为字符串 "a = b + \"c\";(((x * d))) * e + f; a + (x * (y ? 0 : 1) + z);",这是我们整个编译器的输入。
接下来三句
TLexer lexer(&input);
CommonTokenStream tokens(&lexer);
TParser parser(&tokens);
即先把input输入给lexer(词法分析器),再把lexer输入给tokens(符号),最后把tokens输入给parser(语法分析器)。