diff --git a/AlgebraicDataflowArchitectureModel/src/code/ast/NumberUtil.java b/AlgebraicDataflowArchitectureModel/src/code/ast/NumberUtil.java index fee1c7a..0daea7d 100644 --- a/AlgebraicDataflowArchitectureModel/src/code/ast/NumberUtil.java +++ b/AlgebraicDataflowArchitectureModel/src/code/ast/NumberUtil.java @@ -48,6 +48,7 @@ while (lexer.peek() != '\0') { char c = lexer.advance(); + // Check for long number suffix if (c == 'l') { // The suffix for a long literal must be the last character in the literal. if (lexer.peek() != '\0') { @@ -91,6 +92,60 @@ } /** + * Check whether the given string is a valid octal number or not. + * A valid octal number starts with '0' and is followed by a + * combination of digits (0 to 7) or underscores ('_'), + * with restrictions on the positioning of underscores. + * + * @param token The string to be evaluated as an octal number. + * @return {@code true} if the given string represents a valid octal number, + * {@code false} otherwise. + * @apiNote This method returns {@code true} if the given token is a valid octal number representation in Java source code. + * Therefore, the validation rules strictly adhere to the Java language specification. + */ + public static boolean isOctalNumber(String token) { + if (token == null) { + return false; + } + + int length = token.length(); + if (length < 1) { + return false; + } + + Lexer lexer = new Lexer(token.toLowerCase()); + + // Octal numbers must start with '0' + if (lexer.peek() != '0') { + return false; + } + + while (lexer.peek() != '\0') { + if (lexer.peek() == '_' && lexer.peekNext() == '\0') { + return false; + } + if (lexer.peek() == '_' && lexer.peekNext() == 'l') { + return false; + } + + if (lexer.peek() == 'l' && lexer.peekNext() == '\0') { + break; + } + + boolean isDigit = lexer.peek() >= '0' && lexer.peek() <= '7'; + boolean isValidFormat = isDigit || lexer.peek() == '_'; + + if (!isValidFormat) { + return false; + } + + lexer.advance(); + } + + return true; + } + + /** * Determines whether the given string is a valid hexadecimal number. * A valid hexadecimal number starts with "0x" or "0X", followed by a * combination of digits (0-9), letters (a-f, A-F), or underscores ('_'), @@ -132,6 +187,7 @@ while (lexer.peek() != '\0') { char c = lexer.advance(); + // Check for long number suffix if (c == 'l') { // The suffix for a long literal must be the last character in the literal. if (lexer.peek() != '\0') { diff --git a/AlgebraicDataflowArchitectureModel/src/tests/NumberUtilTest.java b/AlgebraicDataflowArchitectureModel/src/tests/NumberUtilTest.java index 45df159..1733d1b 100644 --- a/AlgebraicDataflowArchitectureModel/src/tests/NumberUtilTest.java +++ b/AlgebraicDataflowArchitectureModel/src/tests/NumberUtilTest.java @@ -87,4 +87,40 @@ // No digits assertFalse("No binary digits (0bL)", NumberUtil.isBinaryNumber("0bL")); } + + @Test + public void testIsOctalNumber() { + // --- Valid format numbers --- + assertTrue("Standard octal", NumberUtil.isOctalNumber("01234567")); + assertTrue("Octal with underscores", NumberUtil.isOctalNumber("01_23_4")); + assertTrue("Octal with long suffix (L)", NumberUtil.isOctalNumber("0123L")); + assertTrue("Octal with long suffix (l)", NumberUtil.isOctalNumber("0123l")); + assertTrue("Minimum octal number (0)", NumberUtil.isOctalNumber("0")); + assertTrue("Successive underscores", NumberUtil.isOctalNumber("0123__456")); + + // --- Invalid format numbers --- + // Null and empty + assertFalse("Null string", NumberUtil.isOctalNumber(null)); + assertFalse("Empty string", NumberUtil.isOctalNumber("")); + + // Incorrect prefix + assertFalse("Does not start with 0", NumberUtil.isOctalNumber("123")); + assertFalse("Leading space", NumberUtil.isOctalNumber(" 0123")); + + // Invalid characters + assertFalse("Invalid character (8)", NumberUtil.isOctalNumber("0128")); + assertFalse("Invalid character (a)", NumberUtil.isOctalNumber("012a")); + assertFalse("Decimal point", NumberUtil.isOctalNumber("01.2")); + + // Underscore placement rules + assertTrue("Underscore immediately after 0 is valid for octal", NumberUtil.isOctalNumber("0_123")); + assertFalse("Trailing underscore", NumberUtil.isOctalNumber("0123_")); + assertFalse("Trailing underscore with L", NumberUtil.isOctalNumber("0123_L")); + + // Long suffix rules + assertFalse("L in middle", NumberUtil.isOctalNumber("01L2")); + assertFalse("Multiple L", NumberUtil.isOctalNumber("01LL")); + assertFalse("L with invalid char", NumberUtil.isOctalNumber("018L")); + assertTrue("L with the minimum number (0L)", NumberUtil.isOctalNumber("0L")); + } }