From 6af6d2ca15243c03eda1d019768ead1855d49b1d Mon Sep 17 00:00:00 2001 From: I-Al-Istannen Date: Mon, 5 May 2025 12:33:55 +0200 Subject: [PATCH] Move integer range checking to semantic analysis --- .gitignore | 3 +++ .../vads/compiler/ir/SsaTranslation.java | 2 +- .../kastel/vads/compiler/parser/Parser.java | 20 +-------------- .../kastel/vads/compiler/parser/Printer.java | 2 +- .../vads/compiler/parser/ast/LiteralTree.java | 25 ++++++++++++++++++- .../semantic/IntegerLiteralRangeAnalysis.java | 17 +++++++++++++ .../compiler/semantic/SemanticAnalysis.java | 1 + 7 files changed, 48 insertions(+), 22 deletions(-) create mode 100644 .gitignore create mode 100644 src/main/java/edu/kit/kastel/vads/compiler/semantic/IntegerLiteralRangeAnalysis.java diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..70d580b --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +/build/ +/.idea/ +/.gradle/ diff --git a/src/main/java/edu/kit/kastel/vads/compiler/ir/SsaTranslation.java b/src/main/java/edu/kit/kastel/vads/compiler/ir/SsaTranslation.java index dac150f..95f885f 100644 --- a/src/main/java/edu/kit/kastel/vads/compiler/ir/SsaTranslation.java +++ b/src/main/java/edu/kit/kastel/vads/compiler/ir/SsaTranslation.java @@ -167,7 +167,7 @@ public class SsaTranslation { @Override public Optional visit(LiteralTree literalTree, SsaTranslation data) { pushSpan(literalTree); - Node node = data.constructor.newConstInt((int) literalTree.value()); + Node node = data.constructor.newConstInt((int) literalTree.parseValue().orElseThrow()); popSpan(); return Optional.of(node); } diff --git a/src/main/java/edu/kit/kastel/vads/compiler/parser/Parser.java b/src/main/java/edu/kit/kastel/vads/compiler/parser/Parser.java index 4b09d47..f152cc8 100644 --- a/src/main/java/edu/kit/kastel/vads/compiler/parser/Parser.java +++ b/src/main/java/edu/kit/kastel/vads/compiler/parser/Parser.java @@ -171,30 +171,12 @@ public class Parser { } case NumberLiteral(String value, int base, Span span) -> { this.tokenSource.consume(); - yield new LiteralTree(parseValue(value, base), span); + yield new LiteralTree(value, base, span); } case Token t -> throw new ParseException("invalid factor " + t); }; } - private static long parseValue(String value, int base) { - int begin = 0; - int end = value.length(); - if (base == 16) { - begin = 2; // ignore 0x - } - long l; - try { - l = Long.parseLong(value, begin, end, base); - } catch (NumberFormatException _) { - throw new ParseException("invalid int literal " + value); - } - if (l < 0 || l > Integer.toUnsignedLong(Integer.MIN_VALUE)) { - throw new ParseException("invalid int literal " + value); - } - return l; - } - private static NameTree name(Identifier ident) { return new NameTree(Name.forIdentifier(ident), ident.span()); } diff --git a/src/main/java/edu/kit/kastel/vads/compiler/parser/Printer.java b/src/main/java/edu/kit/kastel/vads/compiler/parser/Printer.java index f4d4d82..72eb8d2 100644 --- a/src/main/java/edu/kit/kastel/vads/compiler/parser/Printer.java +++ b/src/main/java/edu/kit/kastel/vads/compiler/parser/Printer.java @@ -79,7 +79,7 @@ public class Printer { printTree(rhs); print(")"); } - case LiteralTree(var value, _) -> this.builder.append(value); + case LiteralTree(var value, _, _) -> this.builder.append(value); case NegateTree(var expression, _) -> { print("-("); printTree(expression); diff --git a/src/main/java/edu/kit/kastel/vads/compiler/parser/ast/LiteralTree.java b/src/main/java/edu/kit/kastel/vads/compiler/parser/ast/LiteralTree.java index 68dca65..22dfc81 100644 --- a/src/main/java/edu/kit/kastel/vads/compiler/parser/ast/LiteralTree.java +++ b/src/main/java/edu/kit/kastel/vads/compiler/parser/ast/LiteralTree.java @@ -1,11 +1,34 @@ package edu.kit.kastel.vads.compiler.parser.ast; import edu.kit.kastel.vads.compiler.Span; +import edu.kit.kastel.vads.compiler.parser.ParseException; import edu.kit.kastel.vads.compiler.parser.visitor.Visitor; +import edu.kit.kastel.vads.compiler.semantic.SemanticException; +import java.util.Optional; +import java.util.OptionalLong; -public record LiteralTree(long value, Span span) implements ExpressionTree { +public record LiteralTree(String value, int base, Span span) implements ExpressionTree { @Override public R accept(Visitor visitor, T data) { return visitor.visit(this, data); } + + public OptionalLong parseValue() { + int begin = 0; + int end = value.length(); + if (base == 16) { + begin = 2; // ignore 0x + } + long l; + try { + l = Long.parseLong(value, begin, end, base); + } catch (NumberFormatException _) { + return OptionalLong.empty(); + } + if (l < 0 || l > Integer.toUnsignedLong(Integer.MIN_VALUE)) { + return OptionalLong.empty(); + } + return OptionalLong.of(l); + } + } diff --git a/src/main/java/edu/kit/kastel/vads/compiler/semantic/IntegerLiteralRangeAnalysis.java b/src/main/java/edu/kit/kastel/vads/compiler/semantic/IntegerLiteralRangeAnalysis.java new file mode 100644 index 0000000..bbab8d2 --- /dev/null +++ b/src/main/java/edu/kit/kastel/vads/compiler/semantic/IntegerLiteralRangeAnalysis.java @@ -0,0 +1,17 @@ +package edu.kit.kastel.vads.compiler.semantic; + +import edu.kit.kastel.vads.compiler.parser.ast.LiteralTree; +import edu.kit.kastel.vads.compiler.parser.visitor.NoOpVisitor; +import edu.kit.kastel.vads.compiler.parser.visitor.Unit; + +public class IntegerLiteralRangeAnalysis implements NoOpVisitor> { + + @Override + public Unit visit(LiteralTree literalTree, Namespace data) { + literalTree.parseValue() + .orElseThrow( + () -> new SemanticException("invalid integer literal " + literalTree.value()) + ); + return NoOpVisitor.super.visit(literalTree, data); + } +} diff --git a/src/main/java/edu/kit/kastel/vads/compiler/semantic/SemanticAnalysis.java b/src/main/java/edu/kit/kastel/vads/compiler/semantic/SemanticAnalysis.java index d4f243d..f604bea 100644 --- a/src/main/java/edu/kit/kastel/vads/compiler/semantic/SemanticAnalysis.java +++ b/src/main/java/edu/kit/kastel/vads/compiler/semantic/SemanticAnalysis.java @@ -12,6 +12,7 @@ public class SemanticAnalysis { } public void analyze() { + this.program.accept(new RecursivePostorderVisitor<>(new IntegerLiteralRangeAnalysis()), new Namespace<>()); this.program.accept(new RecursivePostorderVisitor<>(new VariableStatusAnalysis()), new Namespace<>()); this.program.accept(new RecursivePostorderVisitor<>(new ReturnAnalysis()), new ReturnAnalysis.ReturnState()); }