想对 C 语言的源代码做变换,变换逻辑不太复杂,用 C++/LLVM 实现不合算,尝试一下 antlr4 + python。
访问 ANTLR 官网
下载 antlr 语法文件.g4
的编译器等工具
pip install antlr4-tools
安装 Java 11 和 ANTLR jar
antlr4
虽然 C 源代码结构清晰,但操作系统将其保存为字符串(文件),进入程序的处理流程时也是作为字符串类型的变量。另一方面,拿 C 语言来说,方便程序处理的 “结构体” 数据结构在内存中的格式是 “含有指针的若干记录” 的结构体格式,与字符串有差异。把源代码从字符串格式变换成结构体格式的程序叫语法分析器(parser)。
antlr4 可以根据语法生成识别该语法的 parser,以 Java,Python 或 C++ 等语言的源码形式给出的。不同语法的 parser 存在公共的部分,这部分作项目依赖的 runtime。对于某个语法(用 .g4
文件描述), parser 中特殊的部分合入项目的源码。
源码经 parser 解析后变为语法树,
安装 Python runtime
pip install antlr4-python3-runtime
准备好 github 上的 C 语法描述文件,生成 Parser 和 Visitor 如下
antlr4 -Dlanguage=Python3 -visitor -no-listener C.g4
生成如下文件:
C.g4 C.interp CLexer.interp CLexer.py CLexer.tokens CParser.py C.tokens CVisitor.py
在 python 中使用 parser 的代码:
import sys
from antlr4 import *
from CLexer import CLexer
from CParser import CParser
from CVisitor import CVisitor
class FuseRewriter(CVisitor):
def visitTerminal(self, node):
if node.symbol.type == Token.EOF:
return self.defaultResult()
else:
return [node.getText()]
def visitErrorNode(self, node):
print('parse error')
assert False
def defaultResult(self):
return []
def aggregateResult(self, aggregate, nextResult):
return aggregate + nextResult
def visitPostfixExpression(self, ctx: CParser.PostfixExpressionContext):
return super().visitPostfixExpression(ctx)
def main():
if len(sys.argv) > 1:
input_stream = FileStream(sys.argv[1])
else:
input_stream = InputStream(sys.stdin.read())
lexer = CLexer(input_stream)
stream = CommonTokenStream(lexer)
parser = CParser(stream)
tree = parser.compilationUnit()
c_tree_str = tree.toStringTree(recog=parser)
# print(c_tree_str)
visitor = FuseRewriter()
return visitor.visit(tree)
if __name__ == '__main__':
tokens = main()
print(' '.join(tokens))
antlr4 根据语法描述文件(.g4
)生成语法分析器,该分析器可以根据源文件构建语法树(parse tree)。语法树是一种树形数据结构,其根节点代表整个源文件,叶子节点(称为 TerminalNode,终结符节点)代表不可再分的词法单元(如一个整数常量),其余的位于树中间部分的节点代表语法规则节点(RuleNode)。如果源文件中存在语法错误,则其对应的语法树中还会出现错误节点(ErrorNode)。
操作树形数据结构的算法,可以采用观察者设计模式(Listener)或访问者设计模式(Visitor),antlr4 runtime 通过提供观察者和访问者的基类(Base class),支持了上述两种设计模式。