lablexer
实验中遇到的问题
-
环境配置:antlr-4.7.2-complete.jar的路径错误。
导致报错:“找不到或无法加载主类 org.antlr.v4.tool”,无法构建文件
将.jar文件放在/usr/local/lib下并修改.bashrc后问题解决。
-
java可以运行但cpp无法构建
但是java能够正常进行词法分析在Google中找到的一个解决方案是https://github.com/antlr/antlr4/issues/2285中提出,可能是我使用的g++版本和链接所需要的g++版本不同,可以尝试将gcc更新到7.3.0
而我的当前版本是5.4.0
按照https://blog.csdn.net/qq_33622849/article/details/100635915中给出的方法,安装g++ -7.3.0后来发现是路径错误。删除"-L…/Libs_for_clr_ref/"即可
-
找不到-lantlr-runtime
经助教提示,是缺少libantlr4-runtime.so文件按照https://github.com/antlr/antlr4/tree/master/runtime/Cpp#compiling-on-linux上给出的方法编译生成该文件
生成的libantlr4-runtime.so.4.7.2存放在Cpp/dist目录下,配置好LD_LIBRARY_PATH即可 -
段错误
后来发现是我虚拟机上的ld没有安装好
执行sudo apt install --reinstall binutils
后即可成功运行
分析与设计
-
源程序比较:
- C++和Java词法分析器源程序都是通过使用C1Lexer.g4来构建词法分析器的。C++源程序C1Lexer.cpp中链接了C1Lexer.h,并使用C1Lexer类的方法来构建有限自动机(_decisionToDFA),Lexer.cpp将字符流传入Lexer生成的自动机中,然后对返回的token做出简单解析即可
- Java词法分析器源程序中描述了有限自动机(_decisionToDFA),并直接链接org.antlr.v4.runtime中的方法来构建自动机,再使用一些简单的函数来解析得到的token
-
词法描述文件和源码之间的关系:
词法描述文件(.g4)通过antlr4工具在/build下生成词法分析器的目标文件(源码),默认生成.java文件,可以通过-Dlanguage选项来指定生成的源码语言(如Cpp)
-
测试样例设计:
正确的测试样例中是一些简单的变量声明、函数定义、语句块等内容。错误的测试样例中包含标识符以数字开头、指数格式不正确、16进制数格式不正确、出现@等非法字符的问题
Q&A
-
Lexer-Q1 理解构建步骤
ANTLR根据C1Lexer.g4词法描述文件,在/build目录下生成词法分析器源码。如果是java语言的,通过javac进行编译生成.class文件,然后在Java虚拟机下运行;如果是C++语言,则通过g++工具,与lexer.cpp共同编译,并链接antlr4-runtime库中的代码,生成目标文件c1lexer,直接运行c1lexer即可。
antlr
缺省时生成的分析器源码是Java编写的。 -
Lexer-Q2 理解生成的分析器源码(C1Lexer类)
- C++数据成员:_ruleNames, _tokenNames, _modeNames, _literalNames, _vocabulary等,用来命名和标记词法规则、token名、符号表等信息
- Java数据成员:_decisionToDFA, _sharedContextCache, channelNames, modeNames, RuleNames, tokenNames等,同C++用来命名和标记词法规则、token等信息
-
Lexer-Q3 理解执行流程
- 执行C1词法分析器的main函数定义在c1recognizer/test/lexer.cpp中
- Lexer::nextToken()会创建一个临时变量来储存读取到的字符,当字符能够与词法规则匹配时,把这个变量作为一个token对象返回给调用者。当调用nextToken()时,其所有权将会转移至处理读入token字符流。当一个词法规则分析完一个被标记skip的token时nextToken() 会自动寻找下一个。如果规则结束时token为空,它将仍会创建一个token并且将它送到token流。
- BufferedTokenStream::LA(ssize_t i),在token流中获取偏移量为i的token的值
- 依赖关系
- BufferedTokenStream将已经返回的token其放置在缓冲区中并提供索引来访问已经得到的token
- CommonTokenStream是对BufferedTokenStream的继承,它的fetch()函数能够循环调用Lexer::nextToken()方法,对返回的token按次序排列
- Lexer提供输入接口,并能够依据返回的TokenStream进行分析,并能够识别简单的错误(syntaxErrors)
- C1Lexer根据Lexer的返回结果生成符号表,并进一步构造有限自动机
参考资料:
- https://www.antlr.org/api/Java/org/antlr/v4/runtime/BufferedTokenStream.html
- https://blog.csdn.net/qq_35318180/article/details/82056763
- https://github.com/antlr/antlr4/tree/master/runtime/Cpp#compiling-on-linux