使用 Python 解析 C++
Parse C++ with Python
我正在尝试使用 python 解析 cpp。我用 ANTLR 为 python 生成了解析器,现在我想访问树并收集一些信息。
- 是否可以将 ANTLR 树转储为 JSON 格式的 AST?
- 我试图跟踪函数调用,我期待像 CallExpr 这样的东西,但我在生成的解析器文件中找不到任何东西。
这是我使用的语法文件 https://github.com/antlr/grammars-v4/blob/master/cpp/CPP14.g4
我尝试了以下命令来获取 CPP 解析器,
java -jar antlr-4.8-complete.jar -Dlanguage=Python3 ./CPP14.g4 -visitor
这是我拥有的最基本的代码
import sys
import os
from antlr4 import *
from CPP14Lexer import *
from CPP14Parser import *
from CPP14Visitor import *
class TREEVisitor(CPP14Visitor):
def __init__(self):
pass
def visitExpressionstatement(self, ctx):
print(ctx.getText())
return self.visitChildren(ctx)
if __name__ == '__main__':
dtype = ""
input_stream = FileStream(sys.argv[1])
cpplex = CPP14Lexer(input_stream)
commtokstream = CommonTokenStream(cpplex)
cpparser = CPP14Parser(commtokstream)
print("parse errors: {}".format(cpparser._syntaxErrors))
tree = cpparser.translationunit()
tv = TREEVisitor()
tv.visit(tree)
我正在尝试解析输入文件,
#include <iostream>
using namespace std;
int foo(int i, int i2)
{
return i * i2;
}
int main(int argc, char *argv[])
{
cout << "test" << endl;
foo(1, 3);
return 0;
}
谢谢
函数调用由 postfixexpression
规则识别:
postfixexpression
: primaryexpression
| postfixexpression '[' expression ']'
| postfixexpression '[' bracedinitlist ']'
| postfixexpression '(' expressionlist? ')' // <---- this alternative!
| simpletypespecifier '(' expressionlist? ')'
| typenamespecifier '(' expressionlist? ')'
| simpletypespecifier bracedinitlist
| typenamespecifier bracedinitlist
| postfixexpression '.' Template? idexpression
| postfixexpression '->' Template? idexpression
| postfixexpression '.' pseudodestructorname
| postfixexpression '->' pseudodestructorname
| postfixexpression '++'
| postfixexpression '--'
| Dynamic_cast '<' thetypeid '>' '(' expression ')'
| Static_cast '<' thetypeid '>' '(' expression ')'
| Reinterpret_cast '<' thetypeid '>' '(' expression ')'
| Const_cast '<' thetypeid '>' '(' expression ')'
| typeidofthetypeid '(' expression ')'
| typeidofthetypeid '(' thetypeid ')'
;
因此,如果您将此添加到您的访客:
def visitPostfixexpression(self, ctx:CPP14Parser.PostfixexpressionContext):
print(ctx.getText())
return self.visitChildren(ctx)
它将被打印出来。请注意,它现在将打印比函数调用更多的内容,因为它匹配的内容远不止于此。你可以 label the alternatives:
postfixexpression
: primaryexpression #otherPostfixexpression
| postfixexpression '[' expression ']' #otherPostfixexpression
| postfixexpression '[' bracedinitlist ']' #otherPostfixexpression
| postfixexpression '(' expressionlist? ')' #functionCallPostfixexpression
| simpletypespecifier '(' expressionlist? ')' #otherPostfixexpression
| typenamespecifier '(' expressionlist? ')' #otherPostfixexpression
| simpletypespecifier bracedinitlist #otherPostfixexpression
| typenamespecifier bracedinitlist #otherPostfixexpression
| postfixexpression '.' Template? idexpression #otherPostfixexpression
| postfixexpression '->' Template? idexpression #otherPostfixexpression
| postfixexpression '.' pseudodestructorname #otherPostfixexpression
| postfixexpression '->' pseudodestructorname #otherPostfixexpression
| postfixexpression '++' #otherPostfixexpression
| postfixexpression '--' #otherPostfixexpression
| Dynamic_cast '<' thetypeid '>' '(' expression ')' #otherPostfixexpression
| Static_cast '<' thetypeid '>' '(' expression ')' #otherPostfixexpression
| Reinterpret_cast '<' thetypeid '>' '(' expression ')' #otherPostfixexpression
| Const_cast '<' thetypeid '>' '(' expression ')' #otherPostfixexpression
| typeidofthetypeid '(' expression ')' #otherPostfixexpression
| typeidofthetypeid '(' thetypeid ')' #otherPostfixexpression
;
然后你可以这样做:
def visitFunctionCallPostfixexpression(self, ctx:CPP14Parser.FunctionCallPostfixexpressionContext):
print(ctx.getText())
return self.visitChildren(ctx)
然后只打印 foo(1,3)
(请注意,您可能希望在 postfixexpression
规则内将更多规则标记为 functionCallPostfixexpression
)。
Is there anyway to dump the ANTLR tree as AST in JSON format?
没有。
但是您当然可以轻松地自己创建一些东西:每个解析器规则返回的对象,如 translationunit
,包含整个树。一个简单粗暴的例子:
import antlr4
from antlr4.tree.Tree import TerminalNodeImpl
import json
# import CPP14Lexer, CPP14Parser, ...
def to_dict(root):
obj = {}
_fill(obj, root)
return obj
def _fill(obj, node):
if isinstance(node, TerminalNodeImpl):
obj["type"] = node.symbol.type
obj["text"] = node.getText()
return
class_name = type(node).__name__.replace('Context', '')
rule_name = '{}{}'.format(class_name[0].lower(), class_name[1:])
arr = []
obj[rule_name] = arr
for child_node in node.children:
child_obj = {}
arr.append(child_obj)
_fill(child_obj, child_node)
if __name__ == '__main__':
source = """
#include <iostream>
using namespace std;
int foo(int i, int i2)
{
return i * i2;
}
int main(int argc, char *argv[])
{
cout << "test" << endl;
foo(1, 3);
return 0;
}
"""
lexer = CPP14Lexer(antlr4.InputStream(source))
parser = CPP14Parser(antlr4.CommonTokenStream(lexer))
tree = parser.translationunit()
tree_dict = to_dict(tree)
json_str = json.dumps(tree_dict, indent=2)
print(json_str)
我正在尝试使用 python 解析 cpp。我用 ANTLR 为 python 生成了解析器,现在我想访问树并收集一些信息。
- 是否可以将 ANTLR 树转储为 JSON 格式的 AST?
- 我试图跟踪函数调用,我期待像 CallExpr 这样的东西,但我在生成的解析器文件中找不到任何东西。
这是我使用的语法文件 https://github.com/antlr/grammars-v4/blob/master/cpp/CPP14.g4
我尝试了以下命令来获取 CPP 解析器, java -jar antlr-4.8-complete.jar -Dlanguage=Python3 ./CPP14.g4 -visitor
这是我拥有的最基本的代码
import sys
import os
from antlr4 import *
from CPP14Lexer import *
from CPP14Parser import *
from CPP14Visitor import *
class TREEVisitor(CPP14Visitor):
def __init__(self):
pass
def visitExpressionstatement(self, ctx):
print(ctx.getText())
return self.visitChildren(ctx)
if __name__ == '__main__':
dtype = ""
input_stream = FileStream(sys.argv[1])
cpplex = CPP14Lexer(input_stream)
commtokstream = CommonTokenStream(cpplex)
cpparser = CPP14Parser(commtokstream)
print("parse errors: {}".format(cpparser._syntaxErrors))
tree = cpparser.translationunit()
tv = TREEVisitor()
tv.visit(tree)
我正在尝试解析输入文件,
#include <iostream>
using namespace std;
int foo(int i, int i2)
{
return i * i2;
}
int main(int argc, char *argv[])
{
cout << "test" << endl;
foo(1, 3);
return 0;
}
谢谢
函数调用由 postfixexpression
规则识别:
postfixexpression
: primaryexpression
| postfixexpression '[' expression ']'
| postfixexpression '[' bracedinitlist ']'
| postfixexpression '(' expressionlist? ')' // <---- this alternative!
| simpletypespecifier '(' expressionlist? ')'
| typenamespecifier '(' expressionlist? ')'
| simpletypespecifier bracedinitlist
| typenamespecifier bracedinitlist
| postfixexpression '.' Template? idexpression
| postfixexpression '->' Template? idexpression
| postfixexpression '.' pseudodestructorname
| postfixexpression '->' pseudodestructorname
| postfixexpression '++'
| postfixexpression '--'
| Dynamic_cast '<' thetypeid '>' '(' expression ')'
| Static_cast '<' thetypeid '>' '(' expression ')'
| Reinterpret_cast '<' thetypeid '>' '(' expression ')'
| Const_cast '<' thetypeid '>' '(' expression ')'
| typeidofthetypeid '(' expression ')'
| typeidofthetypeid '(' thetypeid ')'
;
因此,如果您将此添加到您的访客:
def visitPostfixexpression(self, ctx:CPP14Parser.PostfixexpressionContext):
print(ctx.getText())
return self.visitChildren(ctx)
它将被打印出来。请注意,它现在将打印比函数调用更多的内容,因为它匹配的内容远不止于此。你可以 label the alternatives:
postfixexpression
: primaryexpression #otherPostfixexpression
| postfixexpression '[' expression ']' #otherPostfixexpression
| postfixexpression '[' bracedinitlist ']' #otherPostfixexpression
| postfixexpression '(' expressionlist? ')' #functionCallPostfixexpression
| simpletypespecifier '(' expressionlist? ')' #otherPostfixexpression
| typenamespecifier '(' expressionlist? ')' #otherPostfixexpression
| simpletypespecifier bracedinitlist #otherPostfixexpression
| typenamespecifier bracedinitlist #otherPostfixexpression
| postfixexpression '.' Template? idexpression #otherPostfixexpression
| postfixexpression '->' Template? idexpression #otherPostfixexpression
| postfixexpression '.' pseudodestructorname #otherPostfixexpression
| postfixexpression '->' pseudodestructorname #otherPostfixexpression
| postfixexpression '++' #otherPostfixexpression
| postfixexpression '--' #otherPostfixexpression
| Dynamic_cast '<' thetypeid '>' '(' expression ')' #otherPostfixexpression
| Static_cast '<' thetypeid '>' '(' expression ')' #otherPostfixexpression
| Reinterpret_cast '<' thetypeid '>' '(' expression ')' #otherPostfixexpression
| Const_cast '<' thetypeid '>' '(' expression ')' #otherPostfixexpression
| typeidofthetypeid '(' expression ')' #otherPostfixexpression
| typeidofthetypeid '(' thetypeid ')' #otherPostfixexpression
;
然后你可以这样做:
def visitFunctionCallPostfixexpression(self, ctx:CPP14Parser.FunctionCallPostfixexpressionContext):
print(ctx.getText())
return self.visitChildren(ctx)
然后只打印 foo(1,3)
(请注意,您可能希望在 postfixexpression
规则内将更多规则标记为 functionCallPostfixexpression
)。
Is there anyway to dump the ANTLR tree as AST in JSON format?
没有。
但是您当然可以轻松地自己创建一些东西:每个解析器规则返回的对象,如 translationunit
,包含整个树。一个简单粗暴的例子:
import antlr4
from antlr4.tree.Tree import TerminalNodeImpl
import json
# import CPP14Lexer, CPP14Parser, ...
def to_dict(root):
obj = {}
_fill(obj, root)
return obj
def _fill(obj, node):
if isinstance(node, TerminalNodeImpl):
obj["type"] = node.symbol.type
obj["text"] = node.getText()
return
class_name = type(node).__name__.replace('Context', '')
rule_name = '{}{}'.format(class_name[0].lower(), class_name[1:])
arr = []
obj[rule_name] = arr
for child_node in node.children:
child_obj = {}
arr.append(child_obj)
_fill(child_obj, child_node)
if __name__ == '__main__':
source = """
#include <iostream>
using namespace std;
int foo(int i, int i2)
{
return i * i2;
}
int main(int argc, char *argv[])
{
cout << "test" << endl;
foo(1, 3);
return 0;
}
"""
lexer = CPP14Lexer(antlr4.InputStream(source))
parser = CPP14Parser(antlr4.CommonTokenStream(lexer))
tree = parser.translationunit()
tree_dict = to_dict(tree)
json_str = json.dumps(tree_dict, indent=2)
print(json_str)