diff --git a/ExprTool.java b/ExprTool.java new file mode 100644 index 0000000..cba76f7 --- /dev/null +++ b/ExprTool.java @@ -0,0 +1,105 @@ +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.tree.*; +import org.antlr.v4.runtime.misc.ParseCancellationException; + +public class ExprTool { + public static void main(String[] args) throws Exception { + if (args.length == 0) { + // If no files given then read from stdin + Scanner scanner = new Scanner(System.in); + StringBuilder inputBuilder = new StringBuilder(); + while (scanner.hasNextLine()) { + inputBuilder.append(scanner.nextLine()).append("\n"); + } + scanner.close(); + + parseAndWalk(inputBuilder.toString(), ""); + } else { + // for Loop through all given file paths + for (String filePath : args) { + try { + String inputText = new String(Files.readAllBytes(Paths.get(filePath))); + parseAndWalk(inputText, filePath); + } catch (IOException e) { + System.err.println("Error reading file: " + filePath); + } + } + } + } + + // Reusable parsing + walking + private static void parseAndWalk(String inputText, String sourceName) { + try { + // Create char stream + CharStream input = CharStreams.fromString(inputText, sourceName); + + // Lexer + ExprLexer lexer = new ExprLexer(input); + lexer.removeErrorListeners(); + lexer.addErrorListener(new ThrowingErrorListener()); + + // Tokens + CommonTokenStream tokens = new CommonTokenStream(lexer); + + // Parser + ExprParser parser = new ExprParser(tokens); + parser.removeErrorListeners(); + parser.addErrorListener(new ThrowingErrorListener()); + + // Parse compilation unit + ParseTree tree = parser.compilationUnit(); + + // Walk + 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 ExprParserBaseListener { + private final String sourceName; + + public ClassPrinter(String sourceName) { + this.sourceName = sourceName; + } + + @Override + public void enterClassDeclaration(ExprParser.ClassDeclarationContext ctx) { + int line = ctx.getStart().getLine(); + int col = ctx.getStart().getCharPositionInLine(); + String className = ctx.identifier().getText(); + System.out.printf("Class %s, file %s, line %d, column %d%n", + className, sourceName, line, col); + } + } + + // Custom error listener + 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 = ""; + } + + String formatted = String.format( + " file %s, line %d, column %d%n%s", + sourceName, line, charPositionInLine, msg + ); + + throw new ParseCancellationException(formatted); + } + } +} diff --git a/Test/BadTaxApp.java b/Test/BadTaxApp.java new file mode 100644 index 0000000..d86ee71 --- /dev/null +++ b/Test/BadTaxApp.java @@ -0,0 +1,45 @@ +package Test + +abstract class TaxCalculator { + protected double income + + public TaxCalculator(double income { + this.income = income + } + public abstract double calculateTax() + + public double afterTaxIncome() { + return income - calculateTax() + +} +class FlatTaxCalculator extends TaxCalculator { + private static final double RATE = 0.15 + public FlatTaxCalculator(double income) super(income) + public double calculateTax() { + return income * RATE + } + +public class TaxApp { + static class BracketTaxCalculator extends TaxCalculator { + public BracketTaxCalculator(double income) + super(income) + + public double calculateTax() { + if (income <= 10000) return income * 0.10 + else if (income <= 50000) return (10000 * 0.10) + ((income - 10000) * 0.20) + else return (10000 * 0.10) + (40000 * 0.20) + ((income - 50000) * 0.30) + } + } + + public static void main(String[] args) { + double income = 60000 + + TaxCalculator flat = new FlatTaxCalculator(income) + double flatTax = flat.calculateTax() + double flatAfterTax = flat.afterTaxIncome() + + TaxCalculator bracket = new BracketTaxCalculator(income) + double bracketTax = bracket.calculateTax() + double bracketAfterTax = bracket.afterTaxIncome() + } +} diff --git a/Test/TaxApp.java b/Test/TaxApp.java new file mode 100644 index 0000000..693f2c3 --- /dev/null +++ b/Test/TaxApp.java @@ -0,0 +1,44 @@ +package Test; +abstract class TaxCalculator { + protected double income; + + public TaxCalculator(double income) { + this.income = income; + } + public abstract double calculateTax(); + public double afterTaxIncome() { + return income - calculateTax(); + } +} +class FlatTaxCalculator extends TaxCalculator { + private static final double RATE = 0.15; + public FlatTaxCalculator(double income) {super(income);} + public double calculateTax() { + return income * RATE; + } +} + +public class TaxApp { + static class BracketTaxCalculator extends TaxCalculator { + public BracketTaxCalculator(double income) { + super(income); + } + public double calculateTax() { + if (income <= 10000) {return income * 0.10;} + else if (income <= 50000) { return (10000 * 0.10) + ((income - 10000) * 0.20);} + else { return (10000 * 0.10) + (40000 * 0.20) + ((income - 50000) * 0.30);} + } + } + + public static void main(String[] args) { + double income = 60000; + + TaxCalculator flat = new FlatTaxCalculator(income); + double flatTax = flat.calculateTax(); + double flatAfterTax = flat.afterTaxIncome(); + + TaxCalculator bracket = new BracketTaxCalculator(income); + double bracketTax = bracket.calculateTax(); + double bracketAfterTax = bracket.afterTaxIncome(); + } +}