Files
Software-Analysis/ExprTool.java
2025-09-27 17:07:46 -06:00

102 lines
3.7 KiB
Java

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.Scanner;
import org.antlr.v4.runtime.*;
import org.antlr.v4.runtime.misc.ParseCancellationException;
import org.antlr.v4.runtime.tree.*;
public class ExprTool {
public static void main(String[] args) throws Exception {
String inputText;
String sourceName = "<stdin>";
if (args.length > 0) {
try {
inputText = new String(Files.readAllBytes(Paths.get(args[0])));
sourceName = args[0]; // set source name to file path
} catch (IOException e) {
System.err.println("Error reading file: " + args[0]);
return;
}
} else {
Scanner scanner = new Scanner(System.in);
StringBuilder inputBuilder = new StringBuilder();
while (scanner.hasNextLine()) {
inputBuilder.append(scanner.nextLine()).append("\n");
}
inputText = inputBuilder.toString();
scanner.close();
}
// Create char stream with source name
CharStream input = CharStreams.fromString(inputText, sourceName);
// Create lexer
ExprLexer lexer = new ExprLexer(input);
lexer.removeErrorListeners();
lexer.addErrorListener(new ThrowingErrorListener());
// Create token stream
CommonTokenStream tokens = new CommonTokenStream(lexer);
// Create parser
ExprSyntactic parser = new ExprSyntactic(tokens);
parser.removeErrorListeners();
parser.addErrorListener(new ThrowingErrorListener());
try {
// Use compilationUnit as the start rule
ParseTree tree = parser.compilationUnit();
// Walk the tree and print class declarations
ParseTreeWalker walker = new ParseTreeWalker();
walker.walk(new ClassPrinter(sourceName), tree);
} catch (RuntimeException e) {
System.err.println("Parsing failed: " + e.getMessage());
}
}
// Listener to print class declarations with line/column
public static class ClassPrinter extends ExprSyntacticBaseListener {
private final String sourceName;
public ClassPrinter(String sourceName) {
this.sourceName = sourceName;
}
@Override
public void enterClassDeclaration(ExprSyntactic.ClassDeclarationContext ctx) {
int line = ctx.getStart().getLine();
int col = ctx.getStart().getCharPositionInLine();
// Get the class name from the identifier rule
String className = ctx.identifier().getText();
System.out.printf(" file %s, class %s at line %d, column %d%n",
sourceName, className, line, col);
}
}
// Custom error listener for cleaner error handling
public static class ThrowingErrorListener extends BaseErrorListener {
@Override
public void syntaxError(Recognizer<?, ?> recognizer,
Object offendingSymbol,
int line, int charPositionInLine,
String msg,
RecognitionException e) {
String sourceName = recognizer.getInputStream().getSourceName();
if (sourceName == null || sourceName.isEmpty()) {
sourceName = "<unknown>";
}
String formatted = String.format(
" file %s, line %d, column %d%n%s",
sourceName, line, charPositionInLine, msg
);
throw new ParseCancellationException(formatted);
}
}
}