cpp lexer java_ANTLR: 文法分析利器 (Ⅱ)
发布日期:2021-08-20 01:25:22 浏览次数:7 分类:技术文章

本文共 2234 字,大约阅读时间需要 7 分钟。

在(I)里,我已经简单介绍了ANTLR。现在,让我们继续ANTLR之旅,来真实感受一下它的强大。

和很多词法语法分析软件一样,我也以一个简易计算器作为example。

计算器需求

运算符:+,-,×,÷,(,)

支持整型和浮点型

测试样例

1 + 2 * 3 + 5 - 4/2

(1 + 2) * 3 + 5 - 4 / (2+2)

(1.2*2.5)+8/(4-3)*2.7

下面就让我们动手完成一个计算器,:)

先搭个框架。文件名是calc.g

options {

language = “Cpp”;

}

class CalcParser extends Parser;

class CalcLexer extends Lexer;

这些就是基本框架了。

options里设置language为”Cpp”,表示要生成c++代码。

CalcParser是我们的计算器的语法解析类,继承ANTLR里的Parser类。

同理,CalcLexer是词法分析类,继承ANTLR里的Lexer类。

接着定义计算器的词法规则。

首先是运算符。

PLUS : ‘+’;

SUB : ‘-’ ;

MUL : ‘*’ ;

DIV : ‘/’ ;

LPAREN : ‘(’ ;

RPAREN : ‘)’ ;

接着是操作数。

NUM : (’0′..’9′)+ { $setType(INT); } (’.’ (’0′..’9′)+ { $setType(REAL); } )? ;

(注:这里解释一下NUM这个规则。$setType是ANTLR内置函数,用来设置token类型。所以这个规则的意思就是当匹配到(’0′..’9′)*后,设置token类型为INT,当发现后面跟着小数点和数字后,重新设置token类型为REAL。相信细心的读者会有这种疑问,为什么不用两条规则,通过有无’.‘来匹配。关于这点,我们来回忆一下,ANTLR是采用LL(*),目前的release版本2.7.6只支持fixed-length lookahead,所以用两条规则会引起ambiguity。可以查看我在(I)里的回复,有更详细的描述。)

当然,我们还希望忽略空格,制表符,回车换行这种无意义字符的。

WS : (’ ‘

| ‘\t’

| ‘\n’

| ‘\r’)+

{

$setType(ANTLR_USE_NAMESPACE(antlr)Token::SKIP);

}

;

到这里为止,我们的词法规则就完成了。下面就是语法规则。先来分析一下运算符。显然,(×/÷)>(+/−)。(,)用来组合式子。

至此,语法规则也呼之欲出了。

statement : mexpr ( (PLUS | SUB) mexpr )*

;

mexpr : expr ( (MUL | DIV) expr )*

;

expr : INT

| REAL

| LPAREN statement RPAREN

;

all done。一个计算器的语法程序就写好了。让我们来生成c++代码,实际测试一下.$java -cp /usr/share/java/antlr.jar antlr.Tool calc.gANTLR Parser Generator Version 2.7.6 (20060528) 1989-2005

$ls

calc.g CalcParser.cpp CalcParserTokenTypes.txt

CalcLexer.cpp CalcParser.hpp

CalcLexer.hpp CalcParserTokenTypes.hpp

$

我们可以看到,生成了6个文件。有兴趣的可以自己看一下,每个文件的可读性是很强的,:)。我们写个CalcTest.cpp:

#include “CalcLexer.hpp”

#include “CalcParser.hpp”

#include

using namespace std;

using namespace antlr;

int main()

{

try {

CalcLexer lexer(cin);

CalcParser parser(lexer);

parser.statement();

} catch (exception &e) {

cout << e.what() << endl;

}

}

编译之:$g++ -o Calc CalcTest.cpp CalcParser.cpp CalcLexer.cpp -lantlr

让我们来跑一下测试用例吧,:p

$ ./Calc

1 + 2 * 3 + 5 - 4/2

$ ./Calc

(1 + 2) * 3 + 5 - 4 / (2+2)

$ ./Calc

(1.2*2.5)+8/(4-3)*2.7

$

顺利通过,一切都是那么的自然,lol~。ok, 来些错误的。

$ ./Calc

(1+(1+3.5*(3-2))

line 1:18: expecting RPAREN, found ‘’

可以从错误中看到,还有一个没有匹配的’(‘。 有兴趣的话你就自己测试吧,:)

至此,我们的计算器的有语法解析部分基本已经完成,剩下的就是如何得到计算结果,这个留在后续文章吧。

完整的程序可以从这里下载:calc.tar.gz

enjoy yourself! Any advice prefer.

转载地址:https://blog.csdn.net/weixin_32141627/article/details/114766581 如侵犯您的版权,请留言回复原文章的地址,我们会给您删除此文章,给您带来不便请您谅解!

上一篇:1 n的和在main函数调用java_启动一个没有 main 函数的 java 程序
下一篇:java结果出来0.0_本人Java新手,请教各位大神,为啥输出结果是5个0哇?

发表评论

最新留言

路过,博主的博客真漂亮。。
[***.116.15.85]2024年03月23日 12时44分18秒

关于作者

    喝酒易醉,品茶养心,人生如梦,品茶悟道,何以解忧?唯有杜康!
-- 愿君每日到此一游!

推荐文章

h5引入json_纯js直接引入json文件 2019-04-21
python格式化字符串总结_Python字符串处理方法总结 2019-04-21
python中true什么意思_python中的bool是什么意思 2019-04-21
jacobian 矩阵意义_Jacobian矩阵和Hessian矩阵的作用是什么? 2019-04-21
c++ jna 数据类型_JNA 使用总结 2019-04-21
python中如何遍历列表并将列表值赋予_python中如何实现遍历整个列表? 2019-04-21
apache php mysql架构图_Apache+PHP+MYSQL+Tomcat+JK架构设计技巧与应用实战 2019-04-21
xlnt库如何编译_最新mysql数据库源码编译安装。 2019-04-21
mysql 2003错误 10055_MYSQL无法连接---提示10055错误 2019-04-21
mysql redis缓存层_redis实现缓存的两种方式 2019-04-21
git 改local branch名字_用Git管理Latex写论文的工作流程 2019-04-21
mysql索引篇_MySQL索引篇 2019-04-21
有至少一个用MySQL_Mysql有用的面试题 2019-04-21
mysql select同时update_MySQLSELECT同时UPDATE同一张表 2019-04-21
mysql删除后数据库没变化_mysql之delete删除记录后数据库大小不变 2019-04-21
net mysql start3534_MySQL 5.7.14 net start mysql 服务无法启动-“NET HELPMSG 3534” 的奇怪问题... 2019-04-21
pta两个有序链表的合并_7-1 两个有序链表序列的合并 (20分) --- 内存问题再叙 2019-04-21
python问题描述怎么写_python写文件有时候写不进去怎么办 2019-04-21
qpython3安装lxml_在python的lxml中使用xml目录? 2019-04-21
java 幂取模_快速幂取模算法 2019-04-21