diff --git a/basic/qa/cppunit/test_compiler_checks.cxx b/basic/qa/cppunit/test_compiler_checks.cxx index 773719e9fd45..2b8e72997c64 100644 --- a/basic/qa/cppunit/test_compiler_checks.cxx +++ b/basic/qa/cppunit/test_compiler_checks.cxx @@ -114,4 +114,57 @@ CPPUNIT_TEST_FIXTURE(CppUnit::TestFixture, testTdf149402_vba) CPPUNIT_ASSERT(!aMacro.HasError()); } +CPPUNIT_TEST_FIXTURE(CppUnit::TestFixture, testTdf93727_if) +{ + // #If and #End directive + MacroSnippet aMacro("Sub doUnitTest\n" + " #If 1 = 1 Then\n" + " Const a = 10\n" + " #End If\n" + "End Sub\n"); + aMacro.Compile(); + CPPUNIT_ASSERT_MESSAGE("#If directive causes compile error", !aMacro.HasError()); +} + +CPPUNIT_TEST_FIXTURE(CppUnit::TestFixture, testTdf93727_else) +{ + // #Else directive + MacroSnippet aMacro("Sub doUnitTest\n" + "a = 0\n" + "#If 1 = 0 Then\n" + " a = 10\n" + "#Else\n" + " a = 20\n" + "#End If\n" + "End Sub\n"); + aMacro.Compile(); + CPPUNIT_ASSERT_MESSAGE("#Else directive causes compile error", !aMacro.HasError()); +} + +CPPUNIT_TEST_FIXTURE(CppUnit::TestFixture, testTdf93727_elseif) +{ + // #ElseIf directive + MacroSnippet aMacro("Sub doUnitTest\n" + "a = 0\n" + " #If 1 = 0 Then\n" + " a = 10\n" + " #ElseIf 2 = 2 Then\n" + " a = 20\n" + " #End If\n" + "End Sub\n"); + aMacro.Compile(); + CPPUNIT_ASSERT_MESSAGE("#ElseIf directive causes compile error", !aMacro.HasError()); +} + +CPPUNIT_TEST_FIXTURE(CppUnit::TestFixture, testTdf93727_const) +{ + // #Const directive + MacroSnippet aMacro("#Const MaxValue = 1000\n" + "Sub doUnitTest\n" + " Dim value As Integer\n" + " value = MaxValue\n" + "End Sub\n"); + aMacro.Compile(); + CPPUNIT_ASSERT_MESSAGE("#Const directive causes compile error", !aMacro.HasError()); +} /* vim:set shiftwidth=4 softtabstop=4 expandtab cinoptions=b1,g0,N-s cinkeys+=0=break: */ diff --git a/basic/source/comp/scanner.cxx b/basic/source/comp/scanner.cxx index 45b65a29b129..820951889ad7 100644 --- a/basic/source/comp/scanner.cxx +++ b/basic/source/comp/scanner.cxx @@ -29,6 +29,7 @@ #include #include #include +#include SbiScanner::SbiScanner(OUString _aBuf, StarBASIC* p) : aBuf(std::move(_aBuf)) @@ -209,6 +210,17 @@ bool SbiScanner::readLine() return true; } +// Function to check if a string is a valid compiler directive +static bool isValidCompilerDirective(std::u16string_view directive) { + static const std::vector validDirectives = { + u"if", u"elseif", u"else", u"end", u"const" + }; + + return std::any_of(validDirectives.begin(), validDirectives.end(), [&](const auto& valid) { + return o3tl::matchIgnoreAsciiCase(directive, valid); + }); +} + bool SbiScanner::NextSym() { // memorize for the EOLN-case @@ -220,7 +232,6 @@ bool SbiScanner::NextSym() eScanType = SbxVARIANT; aSym.clear(); bHash = bSymbol = bNumber = bSpaces = false; - bool bCompilerDirective = false; // read in line? if (nLineIdx == -1) @@ -256,6 +267,8 @@ bool SbiScanner::NextSym() if(nCol < aLine.getLength() && aLine[nCol] == '#') { sal_Int32 nLineTempIdx = nLineIdx; + std::u16string_view candidate(aLine.subView(nCol + 1)); + do { nLineTempIdx++; @@ -266,9 +279,20 @@ bool SbiScanner::NextSym() { ++nLineIdx; ++nCol; - //ignore compiler directives (# is first non-space character) + //handle compiler directives (# is first non-space character) if (nOldCol2 == 0) - bCompilerDirective = true; + { + if (isValidCompilerDirective(candidate)) + { + // Skip the whole line if starts with a hash and is a valid compiler directive + nCol = 0; + goto eoln; + } + else + { + GenError(ERRCODE_BASIC_SYNTAX); + } + } else bHash = true; } @@ -660,10 +684,9 @@ bool SbiScanner::NextSym() PrevLineCommentLbl: - if( bPrevLineExtentsComment || (eScanType != SbxSTRING && - ( bCompilerDirective || - aSym.startsWith("'") || - aSym.equalsIgnoreAsciiCase( "REM" ) ) ) ) + if (bPrevLineExtentsComment || + (eScanType != SbxSTRING && + (aSym.startsWith("'") || aSym.equalsIgnoreAsciiCase("REM") || aSym.startsWith("#")))) { bPrevLineExtentsComment = false; aSym = "REM";