ANTLR构建C1语言词法分析器

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的返回结果生成符号表,并进一步构造有限自动机
参考资料:
  1. https://www.antlr.org/api/Java/org/antlr/v4/runtime/BufferedTokenStream.html
  2. https://blog.csdn.net/qq_35318180/article/details/82056763
  3. https://github.com/antlr/antlr4/tree/master/runtime/Cpp#compiling-on-linux

你可能感兴趣的:(编译原理,词法分析,ANTLR)