将ANTLR解析树转换为JSON

4

我已经有一个可用的语法并实现了一个监听器(使用Java)。我可以在控制台中显示带缩进的解析树,但是我想将其导出到JSON结构中,以便可以在任何通用的查看器中使用。

是否有已经存在的方法可以做到这一点,还是我必须从头开始创建JSON文件?

谢谢!

PS:我也成功地通过TreeView类在Swing中显示了它...


ANTLR4 源代码 中搜索 JSON 并没有产生任何好的结果。看来你只能自己动手了。 - lexicore
2个回答

11
有没有现成的方法可以做到这一点,还是我必须从头开始创建json文件?
正如在评论中已经提到的: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;

以下是处理输入(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"
    }
  ]
}

非常感谢您的回复!我会尝试根据这个来工作。真的非常感激! - bluiska
它完美地工作了!非常感谢!解析树以一个非常好的JSON格式输出! - bluiska
你是否有类似的代码可以将数据转换为MongoDB的BSON文档而不是JSON格式? - Sahil

1

将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);
        }
    }
}

当我使用System.Text.Json.JsonSerializer.Serialize时,不幸的是,它会为我抛出一个“System.InvalidOperationException: Method may only be called on a Type for which Type.IsGenericParameter is true.”错误。 - Andreas Forslöw

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接