将 ANTLR 解析树转换为 JSON
Convert ANTLR parse tree to JSON
我有一个可用的语法并实现了一个侦听器(在 Java 中)。我可以在控制台中使用缩进显示解析树,但是我想要将它导出到 JSON 结构,以便它可以在任何通用查看器中使用。
是否有已经制定的方法可以做到这一点,或者我是否必须以某种方式完全从头开始创建 json 文件?
谢谢!
PS:我还设法通过 TreeView 在 Swing 中显示 class...
Is there an already made method that can do this or will I have to create the json file absolutely from scratch somehow?
正如评论中已经提到的:不,ANTLR API 的核心中没有这样的方法。你将不得不自己动手。
我有一个用于调试目的的实用方法,可以将 ANTLR ParseTree
转换为 java.util.Map
,后者可以轻松转换为 JSON 对象。很高兴在这里分享。
给定以下语法:
grammar Expression;
parse
: expr EOF
;
expr
: '(' expr ')' #nestedExpr
| '-' expr #unartyMinusExpr
| expr ( '*' | '/' | '%' ) expr #multExpr
| expr ( '+' | '-' ) expr #addExpr
| expr ( '>' | '>=' | '<' | '<=' ) expr #compareExpr
| expr ( '=' | '!=' ) expr #eqExpr
| expr AND expr #andExpr
| expr OR expr #orExpr
| function_call #functionCallExpr
| ID #idExpr
| NUMBER #numberExpr
| STRING #stringExpr
;
function_call
: ID args
;
args
: '(' ( expr ( ',' expr )* )? ')'
;
ADD : '+';
MINUS : '-';
MULT : '*';
DIV : '/';
MOD : '%';
OPAR : '(';
CPAR : ')';
LTE : '<=';
LT : '<';
GTE : '>=';
GT : '>';
EQ : '=';
NEQ : '!=';
AND : 'and';
OR : 'or';
NUMBER : ( [0-9]* '.' )? [0-9]+;
ID : [a-zA-Z_] [a-zA-Z_0-9]*;
STRING : '"' ~["\r\n]* '"';
NL : '\r'? '\n' | '\r';
SPACE : [ \t] -> skip;
和下面的 Main class,它处理输入 (1 + 2) * 3
:
public class Examples {
private static final Gson PRETTY_PRINT_GSON = new GsonBuilder().setPrettyPrinting().create();
private static final Gson GSON = new Gson();
public static String toJson(ParseTree tree) {
return toJson(tree, true);
}
public static String toJson(ParseTree tree, boolean prettyPrint) {
return prettyPrint ? PRETTY_PRINT_GSON.toJson(toMap(tree)) : GSON.toJson(toMap(tree));
}
public static Map<String, Object> toMap(ParseTree tree) {
Map<String, Object> map = new LinkedHashMap<>();
traverse(tree, map);
return map;
}
public static void traverse(ParseTree tree, Map<String, Object> map) {
if (tree instanceof TerminalNodeImpl) {
Token token = ((TerminalNodeImpl) tree).getSymbol();
map.put("type", token.getType());
map.put("text", token.getText());
}
else {
List<Map<String, Object>> children = new ArrayList<>();
String name = tree.getClass().getSimpleName().replaceAll("Context$", "");
map.put(Character.toLowerCase(name.charAt(0)) + name.substring(1), children);
for (int i = 0; i < tree.getChildCount(); i++) {
Map<String, Object> nested = new LinkedHashMap<>();
children.add(nested);
traverse(tree.getChild(i), nested);
}
}
}
public static void main(String[] args) {
String source = "(1 + 2) * 3";
ExpressionLexer lexer = new ExpressionLexer(CharStreams.fromString(source));
ExpressionParser parser = new ExpressionParser(new CommonTokenStream(lexer));
System.out.println(toJson(parser.parse()));
}
}
您将看到以下内容打印到您的控制台:
{
"parse": [
{
"multExpr": [
{
"nestedExpr": [
{
"type": 7,
"text": "("
},
{
"addExpr": [
{
"numberExpr": [
{
"type": 17,
"text": "1"
}
]
},
{
"type": 2,
"text": "+"
},
{
"numberExpr": [
{
"type": 17,
"text": "2"
}
]
}
]
},
{
"type": 8,
"text": ")"
}
]
},
{
"type": 4,
"text": "*"
},
{
"numberExpr": [
{
"type": 17,
"text": "3"
}
]
}
]
},
{
"type": -1,
"text": "\u003cEOF\u003e"
}
]
}
将 Bart 的解决方案翻译成 C#
public static Dictionary<String, Object> toMap(IParseTree tree, YOURPARSERHERE parser)
{
Dictionary<String, Object> map = new Dictionary<String, Object>();
traverse(tree, map);
return map;
}
public static void traverse(IParseTree tree, Dictionary<String, Object> map)
{
if (tree is TerminalNodeImpl)
{
map.Add("type", tree.GetType());
map.Add("text", tree.GetText());
}
else
{
List<Dictionary<String, Object>> children = new List<Dictionary<String,Object>>();
String name = tree.GetType().Name.Replace("Context", "");
map.Add(char.ToLower(name.ElementAt(0)) + name.Substring(1), children);
for (int i = 0; i < tree.ChildCount; i++)
{
Dictionary<String, Object> nested = new Dictionary<string, object>();
children.Add(nested);
traverse(tree.GetChild(i), nested);
}
}
}
我有一个可用的语法并实现了一个侦听器(在 Java 中)。我可以在控制台中使用缩进显示解析树,但是我想要将它导出到 JSON 结构,以便它可以在任何通用查看器中使用。
是否有已经制定的方法可以做到这一点,或者我是否必须以某种方式完全从头开始创建 json 文件?
谢谢!
PS:我还设法通过 TreeView 在 Swing 中显示 class...
Is there an already made method that can do this or will I have to create the json file absolutely from scratch somehow?
正如评论中已经提到的:不,ANTLR API 的核心中没有这样的方法。你将不得不自己动手。
我有一个用于调试目的的实用方法,可以将 ANTLR ParseTree
转换为 java.util.Map
,后者可以轻松转换为 JSON 对象。很高兴在这里分享。
给定以下语法:
grammar Expression;
parse
: expr EOF
;
expr
: '(' expr ')' #nestedExpr
| '-' expr #unartyMinusExpr
| expr ( '*' | '/' | '%' ) expr #multExpr
| expr ( '+' | '-' ) expr #addExpr
| expr ( '>' | '>=' | '<' | '<=' ) expr #compareExpr
| expr ( '=' | '!=' ) expr #eqExpr
| expr AND expr #andExpr
| expr OR expr #orExpr
| function_call #functionCallExpr
| ID #idExpr
| NUMBER #numberExpr
| STRING #stringExpr
;
function_call
: ID args
;
args
: '(' ( expr ( ',' expr )* )? ')'
;
ADD : '+';
MINUS : '-';
MULT : '*';
DIV : '/';
MOD : '%';
OPAR : '(';
CPAR : ')';
LTE : '<=';
LT : '<';
GTE : '>=';
GT : '>';
EQ : '=';
NEQ : '!=';
AND : 'and';
OR : 'or';
NUMBER : ( [0-9]* '.' )? [0-9]+;
ID : [a-zA-Z_] [a-zA-Z_0-9]*;
STRING : '"' ~["\r\n]* '"';
NL : '\r'? '\n' | '\r';
SPACE : [ \t] -> skip;
和下面的 Main class,它处理输入 (1 + 2) * 3
:
public class Examples {
private static final Gson PRETTY_PRINT_GSON = new GsonBuilder().setPrettyPrinting().create();
private static final Gson GSON = new Gson();
public static String toJson(ParseTree tree) {
return toJson(tree, true);
}
public static String toJson(ParseTree tree, boolean prettyPrint) {
return prettyPrint ? PRETTY_PRINT_GSON.toJson(toMap(tree)) : GSON.toJson(toMap(tree));
}
public static Map<String, Object> toMap(ParseTree tree) {
Map<String, Object> map = new LinkedHashMap<>();
traverse(tree, map);
return map;
}
public static void traverse(ParseTree tree, Map<String, Object> map) {
if (tree instanceof TerminalNodeImpl) {
Token token = ((TerminalNodeImpl) tree).getSymbol();
map.put("type", token.getType());
map.put("text", token.getText());
}
else {
List<Map<String, Object>> children = new ArrayList<>();
String name = tree.getClass().getSimpleName().replaceAll("Context$", "");
map.put(Character.toLowerCase(name.charAt(0)) + name.substring(1), children);
for (int i = 0; i < tree.getChildCount(); i++) {
Map<String, Object> nested = new LinkedHashMap<>();
children.add(nested);
traverse(tree.getChild(i), nested);
}
}
}
public static void main(String[] args) {
String source = "(1 + 2) * 3";
ExpressionLexer lexer = new ExpressionLexer(CharStreams.fromString(source));
ExpressionParser parser = new ExpressionParser(new CommonTokenStream(lexer));
System.out.println(toJson(parser.parse()));
}
}
您将看到以下内容打印到您的控制台:
{
"parse": [
{
"multExpr": [
{
"nestedExpr": [
{
"type": 7,
"text": "("
},
{
"addExpr": [
{
"numberExpr": [
{
"type": 17,
"text": "1"
}
]
},
{
"type": 2,
"text": "+"
},
{
"numberExpr": [
{
"type": 17,
"text": "2"
}
]
}
]
},
{
"type": 8,
"text": ")"
}
]
},
{
"type": 4,
"text": "*"
},
{
"numberExpr": [
{
"type": 17,
"text": "3"
}
]
}
]
},
{
"type": -1,
"text": "\u003cEOF\u003e"
}
]
}
将 Bart 的解决方案翻译成 C#
public static Dictionary<String, Object> toMap(IParseTree tree, YOURPARSERHERE parser)
{
Dictionary<String, Object> map = new Dictionary<String, Object>();
traverse(tree, map);
return map;
}
public static void traverse(IParseTree tree, Dictionary<String, Object> map)
{
if (tree is TerminalNodeImpl)
{
map.Add("type", tree.GetType());
map.Add("text", tree.GetText());
}
else
{
List<Dictionary<String, Object>> children = new List<Dictionary<String,Object>>();
String name = tree.GetType().Name.Replace("Context", "");
map.Add(char.ToLower(name.ElementAt(0)) + name.Substring(1), children);
for (int i = 0; i < tree.ChildCount; i++)
{
Dictionary<String, Object> nested = new Dictionary<string, object>();
children.Add(nested);
traverse(tree.GetChild(i), nested);
}
}
}