ANTLR4安装教程及使用示例(Windows版本)


前言

由于最近需要对智能合约源代码进行预处理,将其处理成适用于神经网络(如GRU)的输入形式,需要使用现有的支持代码标记化的工具如ANTLR来对源代码进行预处理。由于是第一次接触这个工具,所以来记录一下该工具的安装和简单使用。

这里智能合约源代码是使用Solidity语言编写的,ANTLR也是支持其他编程语言代码的~


一、ANTLR是什么?

ANTLR(Another Tool for Language Recognition)是一个功能强大的解析器生成器,用于读取、处理、执行和翻译结构化文本或二进制文件。ANTLR可以帮助创建语言解析器、编译器、解释器和分析工具,尤其适合对编程语言或数据格式进行语法分析。

ANTLR的主要功能

  • 语法定义: 可以通过ANTLR定义编程语言的语法。ANTLR使用语法规则文件描述语言的词法和语法结构。
  • 代码生成: 根据定义的语法规则生成解析器、词法分析器、语法树等代码。支持多种编程语言的代码,包括Java、Python、C++、JavaScript等。
  • 语法分析: 生成的解析器可以将输入文本或代码解析成抽象语法树(AST),方便进一步的分析、转换和编译。
  • 错误处理: 内置错误处理机制,可以捕捉和报告语法错误,帮助调试和验证输入是否符合语法规则。

ANTLR的组成部分

  • 词法分析器: 将输入分解为一系列标记(Tokens),如关键词、标识符、数字、运算符等。
  • 解析器: 根据词法分析器生成的标记序列,构建抽象语法树或解析树,描述代码的层次结构和语法关系。
  • 抽象语法树: 树状数据结构,描述代码的语法结构。可以通过AST进行代码分析、优化和转换。
  • 代码生成器: ANTLR生成的代码可以集成到项目中,生成自定义的编程语言工具。

二、ANTLR4安装

注意:ANTLR安装是需要Java环境的,如果自己电脑中没有Java环境的话需要先安装一下。可以通过命令行窗口(cmd)来检查自己的Java环境是否安装成功。

C:\Users\drh20>java --version
java 17.0.10 2024-01-16 LTS
Java(TM) SE Runtime Environment (build 17.0.10+11-LTS-240)
Java HotSpot(TM) 64-Bit Server VM (build 17.0.10+11-LTS-240, mixed mode, sharing)

1.下载

官网下载ANTLR4,下载页面如下:

在这里插入图片描述

下载后的jar包长这样,可以新建一个目录存放(我是存放在了D:\Software\ANTLR目录下):
在这里插入图片描述

2.安装及环境配置

接下来,在D:\Software\ANTLR目录下新建两个文件夹,battest

在这里插入图片描述
配置CLASSPATH

扫描二维码关注公众号,回复: 17460549 查看本文章

打开环境变量配置界面(控制面板->系统->高级系统设置->高级->环境变量),选择系统变量,如果自己系统变量中没有CLASSPATH,可以点击“新建”选项进行新建。变量名是CLASSPATH,变量值是刚从官网下载的jar包的存放路径,比如我的就是D:\Software\ANTLR\antlr-4.13.2-complete.jar。然后再点击“新建”按钮添加一个.(需要有这一步,不然后面的话可能会报错)

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

接下来找到系统变量中的Path并进行修改,双击打开,然后将新建的bat文件路径添加进去。完成之后记得一路点击“确定”,这样就完成环境变量配置啦。

在这里插入图片描述

在这里插入图片描述

bat文件夹

在bat文件夹下新建两个txt文件,分别为antlr4.txtgrun.txt

antlr4.txt中添加如下内容:

java org.antlr.v4.Tool %*

grun.txt中添加如下内容:

java org.antlr.v4.gui.TestRig %*

然后将两个文件的后缀名改为.bat

在这里插入图片描述

测试安装是否成功

打开命令行窗口(cmd),输入antlr4,然后回车,输出结果如下所示。

在这里插入图片描述
接着输入命令grun,回车,如果正常输出的话那证明我们的ANTLR4安装和环境配置成功啦!

在这里插入图片描述

三、使用ANTLR4进行一个简单的词法分析示例

为了更直观地感受ANTLR4工具,选取了一个智能合约源代码文件,我们来对它进行词法分析,生成源代码转换后的数值序列。

test.sol

pragma solidity ^0.4.18;
contract Ownable {
  address public owner;
  event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
  function Ownable() public {
    owner = msg.sender;
  }
  modifier onlyOwner() {
    require(msg.sender == owner);
    _;
  }
  function transferOwnership(address newOwner) public onlyOwner {
    require(newOwner != address(0));
    OwnershipTransferred(owner, newOwner);
    owner = newOwner;
  }
}
contract ERC20Basic {
  uint256 public totalSupply;
  function balanceOf(address who) public view returns (uint256);
  function transfer(address to, uint256 value) public returns (bool);
  event Transfer(address indexed from, address indexed to, uint256 value);
}
contract IntermediateWallet is Ownable {
  address public wallet;
  function IntermediateWallet() public {
    wallet = 0x246a8bC2bC20826Ba19D8F7FC5799fF69A79388d;
  }
  function setWallet(address newWallet) public onlyOwner {
    wallet = newWallet;
  }
  function retrieveTokens(address to, address anotherToken) public onlyOwner {
    ERC20Basic alienToken = ERC20Basic(anotherToken);
    alienToken.transfer(to, alienToken.balanceOf(this));
  }
  function () payable public {
    wallet.transfer(msg.value);
  }
}

1. 获取Solidity语法文件

要解析Solidity代码,首先需要一个描述Solidity语言语法的.g4文件。可以从Solidity ANTLR Grammar上找到现成的语法文件。下载并保存Solidity.g4

在这里插入图片描述

利用ANTLR4工具,生成词法分析器(Lexer)和解析器(Parser)目标编程语言的代码,需要指定目标语言,为了确保ANTLR4生成的分析器代码适配我们项目的代码。(若不指定目标语言,会默认生成Java的分析器代码)
在该test目录下打开命令行窗口,输入如下命令:

antlr4 -Dlanguage=Python Solidity.g4

回车,会生成相应的文件。

在这里插入图片描述

2. 对test.sol进行词法分析,生成词汇表vocab.json

把上一步生成的SolidityLexer.py和SolidityParser.py放到自己的项目中(此处放在了项目根目录下的myTokensize文件夹中),然后将SolidityLexerSolidityParser作为头文件导进来。其他头文件根据需要自行导入。

from antlr4 import *
from myTokenize.SolidityLexer import SolidityLexer
from myTokenize.SolidityParser import SolidityParser

if __name__ == '__main__':

    # 合约源代码路径
    file_path = r'.\sourceCode\test.sol'
    all_tokens = []  # 存放每个词法标记,关键词、标识符、运算符等

    # 打开合约文件
    input_stream = FileStream(file_path, encoding='utf-8')

    # 创建词法分析器,可能会出现异常
    lexer = SolidityLexer(input_stream)
    token_stream = CommonTokenStream(lexer)
    # 创建解析器
    parser = SolidityParser(token_stream)

    # 获取词法标记
    tokens = lexer.getAllTokens()
    all_tokens.extend([token.text for token in tokens])
    print(all_tokens)

    # 构建全局词汇表,确保每个 token 只出现一次,并按字典序排序
    unique_tokens = sorted(set(all_tokens))
    vocab = {
    
    token: idx for idx, token in enumerate(unique_tokens)}

    # 将全局词汇表保存为 vocab.json 文件
    with open('./vocab.json', 'w', encoding='utf-8') as f:
        json.dump(vocab, f, ensure_ascii=False, indent=4)

    print('词汇表构建完成!')

生成的词汇表vocab.json,源代码被分解为一系列的标记(Token),每个Token对应一个唯一的索引(ID)。

{
    
    
    "!=": 0,
    "(": 1,
    ")": 2,
    ",": 3,
    ".": 4,
    "0": 5,
    "0.4.18": 6,
    "0x246a8bC2bC20826Ba19D8F7FC5799fF69A79388d": 7,
    ";": 8,
    "=": 9,
    "==": 10,
    "ERC20Basic": 11,
    "IntermediateWallet": 12,
    "Ownable": 13,
    "OwnershipTransferred": 14,
    "Transfer": 15,
    "^": 16,
    "_": 17,
    "address": 18,
    "alienToken": 19,
    "anotherToken": 20,
    "balanceOf": 21,
    "bool": 22,
    "contract": 23,
    "event": 24,
    "from": 25,
    "function": 26,
    "indexed": 27,
    "is": 28,
    "modifier": 29,
    "msg": 30,
    "newOwner": 31,
    "newWallet": 32,
    "onlyOwner": 33,
    "owner": 34,
    "payable": 35,
    "pragma": 36,
    "previousOwner": 37,
    "public": 38,
    "require": 39,
    "retrieveTokens": 40,
    "returns": 41,
    "sender": 42,
    "setWallet": 43,
    "solidity": 44,
    "this": 45,
    "to": 46,
    "totalSupply": 47,
    "transfer": 48,
    "transferOwnership": 49,
    "uint256": 50,
    "value": 51,
    "view": 52,
    "wallet": 53,
    "who": 54,
    "{": 55,
    "}": 56
}

3. 根据构建的词汇表对源代码进行词法标记,并转换为数值序列

from antlr4 import *
from myTokenize.SolidityLexer import SolidityLexer
from myTokenize.SolidityParser import SolidityParser

if __name__ == '__main__':

    # 从 vocab.json 文件中加载词汇表
    with open('./vocab.json', 'r', encoding='utf-8') as f:
        vocab = json.load(f)

    file_path = r'.\sourceCode\test.sol'

    # 打开合约文件
    input_stream = FileStream(file_path, encoding='utf-8')

    # 创建词法分析器,可能会出现异常
    lexer = SolidityLexer(input_stream)
    token_stream = CommonTokenStream(lexer)
    # 创建解析器
    parser = SolidityParser(token_stream)

    # 获取词法标记(关键词、标识符、操作符等)
    tokens = lexer.getAllTokens()
    # 将标记转换为数值序列 [1,2,3,4,5...]
    indexed_tokens = [vocab[token.text] for token in tokens if token.text in vocab]
    print(indexed_tokens)  # [36, 44, 16, 6, 8, 23, 13, 55, 18, 38, 34, 8, 24, 14...]

总结

本文介绍了ANTLR4工具的下载安装和简单使用,第一次使用ANTLR4,有误的地方欢迎大家指正~

猜你喜欢

转载自blog.csdn.net/hhh10242048/article/details/143237398