private void dumpProfilerCSV(GrammarParserInterpreter parser, ParseInfo parseInfo) {
		String[] ruleNamesByDecision = new String[parser.getATN().decisionToState.size()];
		for(int i = 0; i < ruleNamesByDecision .length; i++) {
			ruleNamesByDecision [i] = parser.getRuleNames()[parser.getATN().getDecisionState(i).ruleIndex];
		}

		DecisionInfo[] decisionInfo = parseInfo.getDecisionInfo();
		String[][] table = new String[decisionInfo.length][profilerColumnNames.length];

		for (int decision = 0; decision < decisionInfo.length; decision++) {
			for (int col = 0; col < profilerColumnNames.length; col++) {
				Object colVal = getValue(decisionInfo[decision], ruleNamesByDecision, decision, col);
				table[decision][col] = colVal.toString();
			}
		}

		try {
			FileWriter fileWriter = new FileWriter(profileFileName);
			PrintWriter pw = new PrintWriter(fileWriter);

			for (int i = 0; i < profilerColumnNames.length; i++) {
				if (i > 0) pw.print(",");
				pw.print(profilerColumnNames[i]);
			}
			pw.println();
			for (String[] row : table) {
				for (int i = 0; i < profilerColumnNames.length; i++) {
					if (i > 0) pw.print(",");
					pw.print(row[i]);
				}
				pw.println();
			}
			pw.close();
		}
		catch (IOException ioe) {
			System.err.println("Error writing profile info to "+profileFileName+": "+ioe.getMessage());
		}
	}
Interpret a lexer/parser, optionally printing tree string and dumping profile info

 $ java org.antlr.v4.gui.Interpreter [X.g4|XParser.g4 XLexer.g4] startRuleName inputFileName
       [-tree]
       [-gui]
       [-trace]
       [-encoding encoding]
       [-tokens]
       [-profile filename.csv]
tool/src/org/antlr/v4/gui/Interpreter.java