1
0
mirror of https://github.com/Kitware/CMake.git synced 2025-10-14 02:08:27 +08:00

cmCommandArgumentParserHelper: rework input handling

Old implementation uses involved Flex input management technique that
requires usage of obsolete YY_INPUT macro. This causes a lot of useless
allocations and byte-by-byte scanning. New implementation avoids those
hacks, it uses yy_scan_string() API to setup Flex input. Also it fixes
reporting of syntax error position and corresponding tests.
This commit is contained in:
Oleksandr Koval
2020-09-09 15:49:35 +03:00
parent 9a0a5f8420
commit 62d7acc6d4
20 changed files with 50 additions and 62 deletions

View File

@@ -653,7 +653,7 @@ This file must be translated to C++ and modified to build everywhere.
Run flex >= 2.6 like this: Run flex >= 2.6 like this:
flex --nounistd -DFLEXINT_H --noline --header-file=cmCommandArgumentLexer.h -ocmCommandArgumentLexer.cxx cmCommandArgumentLexer.in.l flex --nounistd --never-interactive --batch -DFLEXINT_H --noline --header-file=cmCommandArgumentLexer.h -ocmCommandArgumentLexer.cxx cmCommandArgumentLexer.in.l
Modify cmCommandArgumentLexer.cxx: Modify cmCommandArgumentLexer.cxx:
- remove trailing whitespace: sed -i 's/\s*$//' cmCommandArgumentLexer.h cmCommandArgumentLexer.cxx - remove trailing whitespace: sed -i 's/\s*$//' cmCommandArgumentLexer.h cmCommandArgumentLexer.cxx
@@ -668,10 +668,7 @@ Modify cmCommandArgumentLexer.cxx:
#include "cmCommandArgumentParserHelper.h" #include "cmCommandArgumentParserHelper.h"
/* Replace the lexer input function. */ #define YY_USER_ACTION yyextra->UpdateInputPosition(yyleng);
#undef YY_INPUT
#define YY_INPUT(buf, result, max_size) \
do { result = yyextra->LexInput(buf, max_size); } while (0)
/* Include the set of tokens from the parser. */ /* Include the set of tokens from the parser. */
#include "cmCommandArgumentParserTokens.h" #include "cmCommandArgumentParserTokens.h"
@@ -967,16 +964,12 @@ yy_match:
yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c];
++yy_cp; ++yy_cp;
} }
while ( yy_base[yy_current_state] != 41 ); while ( yy_current_state != 29 );
yy_cp = yyg->yy_last_accepting_cpos;
yy_current_state = yyg->yy_last_accepting_state;
yy_find_action: yy_find_action:
yy_act = yy_accept[yy_current_state]; yy_act = yy_accept[yy_current_state];
if ( yy_act == 0 )
{ /* have to back up */
yy_cp = yyg->yy_last_accepting_cpos;
yy_current_state = yyg->yy_last_accepting_state;
yy_act = yy_accept[yy_current_state];
}
YY_DO_BEFORE_ACTION; YY_DO_BEFORE_ACTION;
@@ -1173,7 +1166,8 @@ case YY_STATE_EOF(NOESCAPES):
else else
{ {
yy_cp = yyg->yy_c_buf_p; yy_cp = yyg->yy_last_accepting_cpos;
yy_current_state = yyg->yy_last_accepting_state;
goto yy_find_action; goto yy_find_action;
} }
} }
@@ -1661,7 +1655,7 @@ static void yy_load_buffer_state (yyscan_t yyscanner)
b->yy_bs_column = 0; b->yy_bs_column = 0;
} }
b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; b->yy_is_interactive = 0;
errno = oerrno; errno = oerrno;
} }

View File

@@ -7,7 +7,7 @@ This file must be translated to C++ and modified to build everywhere.
Run flex >= 2.6 like this: Run flex >= 2.6 like this:
flex --nounistd -DFLEXINT_H --noline --header-file=cmCommandArgumentLexer.h -ocmCommandArgumentLexer.cxx cmCommandArgumentLexer.in.l flex --nounistd --never-interactive --batch -DFLEXINT_H --noline --header-file=cmCommandArgumentLexer.h -ocmCommandArgumentLexer.cxx cmCommandArgumentLexer.in.l
Modify cmCommandArgumentLexer.cxx: Modify cmCommandArgumentLexer.cxx:
- remove trailing whitespace: sed -i 's/\s*$//' cmCommandArgumentLexer.h cmCommandArgumentLexer.cxx - remove trailing whitespace: sed -i 's/\s*$//' cmCommandArgumentLexer.h cmCommandArgumentLexer.cxx
@@ -22,10 +22,7 @@ Modify cmCommandArgumentLexer.cxx:
#include "cmCommandArgumentParserHelper.h" #include "cmCommandArgumentParserHelper.h"
/* Replace the lexer input function. */ #define YY_USER_ACTION yyextra->UpdateInputPosition(yyleng);
#undef YY_INPUT
#define YY_INPUT(buf, result, max_size) \
do { result = yyextra->LexInput(buf, max_size); } while (0)
/* Include the set of tokens from the parser. */ /* Include the set of tokens from the parser. */
#include "cmCommandArgumentParserTokens.h" #include "cmCommandArgumentParserTokens.h"

View File

@@ -205,23 +205,24 @@ bool cmCommandArgumentParserHelper::HandleEscapeSymbol(
void cmCommandArgument_SetupEscapes(yyscan_t yyscanner, bool noEscapes); void cmCommandArgument_SetupEscapes(yyscan_t yyscanner, bool noEscapes);
int cmCommandArgumentParserHelper::ParseString(const char* str, int verb) int cmCommandArgumentParserHelper::ParseString(std::string const& str,
int verb)
{ {
if (!str) { if (str.empty()) {
return 0; return 0;
} }
this->InputSize = str.size();
this->Verbose = verb; this->Verbose = verb;
this->InputBuffer = str;
this->InputBufferPos = 0;
this->CurrentLine = 0;
this->Result.clear(); this->Result.clear();
yyscan_t yyscanner; yyscan_t yyscanner;
cmCommandArgument_yylex_init(&yyscanner); cmCommandArgument_yylex_init(&yyscanner);
auto scanBuf = cmCommandArgument_yy_scan_string(str.c_str(), yyscanner);
cmCommandArgument_yyset_extra(this, yyscanner); cmCommandArgument_yyset_extra(this, yyscanner);
cmCommandArgument_SetupEscapes(yyscanner, this->NoEscapeMode); cmCommandArgument_SetupEscapes(yyscanner, this->NoEscapeMode);
int res = cmCommandArgument_yyparse(yyscanner); int res = cmCommandArgument_yyparse(yyscanner);
cmCommandArgument_yy_delete_buffer(scanBuf, yyscanner);
cmCommandArgument_yylex_destroy(yyscanner); cmCommandArgument_yylex_destroy(yyscanner);
if (res != 0) { if (res != 0) {
return 0; return 0;
@@ -241,25 +242,14 @@ void cmCommandArgumentParserHelper::CleanupParser()
this->Variables.clear(); this->Variables.clear();
} }
int cmCommandArgumentParserHelper::LexInput(char* buf, int maxlen)
{
if (maxlen < 1) {
return 0;
}
if (this->InputBufferPos < this->InputBuffer.size()) {
buf[0] = this->InputBuffer[this->InputBufferPos++];
if (buf[0] == '\n') {
this->CurrentLine++;
}
return (1);
}
buf[0] = '\n';
return (0);
}
void cmCommandArgumentParserHelper::Error(const char* str) void cmCommandArgumentParserHelper::Error(const char* str)
{ {
unsigned long pos = static_cast<unsigned long>(this->InputBufferPos); auto pos = this->InputBufferPos;
auto const isEof = (this->InputSize < this->InputBufferPos);
if (!isEof) {
pos -= this->LastTokenLength;
}
std::ostringstream ostr; std::ostringstream ostr;
ostr << str << " (" << pos << ")"; ostr << str << " (" << pos << ")";
this->SetError(ostr.str()); this->SetError(ostr.str());
@@ -286,3 +276,9 @@ void cmCommandArgumentParserHelper::SetError(std::string const& msg)
this->ErrorString = msg; this->ErrorString = msg;
} }
} }
void cmCommandArgumentParserHelper::UpdateInputPosition(int const tokenLength)
{
this->InputBufferPos += tokenLength;
this->LastTokenLength = tokenLength;
}

View File

@@ -25,7 +25,7 @@ public:
cmCommandArgumentParserHelper& operator=( cmCommandArgumentParserHelper& operator=(
cmCommandArgumentParserHelper const&) = delete; cmCommandArgumentParserHelper const&) = delete;
int ParseString(const char* str, int verb); int ParseString(std::string const& str, int verb);
// For the lexer: // For the lexer:
void AllocateParserType(cmCommandArgumentParserHelper::ParserType* pt, void AllocateParserType(cmCommandArgumentParserHelper::ParserType* pt,
@@ -33,7 +33,6 @@ public:
bool HandleEscapeSymbol(cmCommandArgumentParserHelper::ParserType* pt, bool HandleEscapeSymbol(cmCommandArgumentParserHelper::ParserType* pt,
char symbol); char symbol);
int LexInput(char* buf, int maxlen);
void Error(const char* str); void Error(const char* str);
// For yacc // For yacc
@@ -46,6 +45,8 @@ public:
void SetMakefile(const cmMakefile* mf); void SetMakefile(const cmMakefile* mf);
void UpdateInputPosition(int tokenLength);
std::string& GetResult() { return this->Result; } std::string& GetResult() { return this->Result; }
void SetLineFile(long line, const char* file); void SetLineFile(long line, const char* file);
@@ -57,8 +58,9 @@ public:
const char* GetError() { return this->ErrorString.c_str(); } const char* GetError() { return this->ErrorString.c_str(); }
private: private:
std::string::size_type InputBufferPos; std::string::size_type InputBufferPos{ 1 };
std::string InputBuffer; std::string::size_type LastTokenLength{};
std::string::size_type InputSize{};
std::vector<char> OutputBuffer; std::vector<char> OutputBuffer;
void Print(const char* place, const char* str); void Print(const char* place, const char* str);
@@ -75,7 +77,6 @@ private:
std::string ErrorString; std::string ErrorString;
const char* FileName; const char* FileName;
long FileLine; long FileLine;
int CurrentLine;
int Verbose; int Verbose;
bool EscapeQuotes; bool EscapeQuotes;
bool NoEscapeMode; bool NoEscapeMode;

View File

@@ -2898,7 +2898,7 @@ MessageType cmMakefile::ExpandVariablesInStringOld(
parser.SetNoEscapeMode(noEscapes); parser.SetNoEscapeMode(noEscapes);
parser.SetReplaceAtSyntax(replaceAt); parser.SetReplaceAtSyntax(replaceAt);
parser.SetRemoveEmpty(removeEmpty); parser.SetRemoveEmpty(removeEmpty);
int res = parser.ParseString(source.c_str(), 0); int res = parser.ParseString(source, 0);
const char* emsg = parser.GetError(); const char* emsg = parser.GetError();
MessageType mtype = MessageType::LOG; MessageType mtype = MessageType::LOG;
if (res && !emsg[0]) { if (res && !emsg[0]) {

View File

@@ -19,6 +19,6 @@ CMake Error at CMP0053-Dollar-OLD.cmake:6 \(message\):
-->\${\$}<-- -->\${\$}<--
syntax error, unexpected \$, expecting } \(7\) syntax error, unexpected \$, expecting } \(6\)
Call Stack \(most recent call first\): Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)$ CMakeLists.txt:3 \(include\)$

View File

@@ -7,6 +7,6 @@
\${var\\rwith\\rcarriagereturn} \${var\\rwith\\rcarriagereturn}
syntax error, unexpected cal_SYMBOL, expecting } \(7\) syntax error, unexpected cal_SYMBOL, expecting } \(6\)
Call Stack \(most recent call first\): Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)$ CMakeLists.txt:3 \(include\)$

View File

@@ -7,6 +7,6 @@
\${var\\rwith\\rcarriagereturn} \${var\\rwith\\rcarriagereturn}
syntax error, unexpected cal_SYMBOL, expecting } \(7\) syntax error, unexpected cal_SYMBOL, expecting } \(6\)
Call Stack \(most recent call first\): Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)$ CMakeLists.txt:3 \(include\)$

View File

@@ -7,6 +7,6 @@
\${var\\ with\\ escaped\\ space} \${var\\ with\\ escaped\\ space}
syntax error, unexpected cal_SYMBOL, expecting } \(7\) syntax error, unexpected cal_SYMBOL, expecting } \(6\)
Call Stack \(most recent call first\): Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)$ CMakeLists.txt:3 \(include\)$

View File

@@ -7,6 +7,6 @@
\${var\\ with\\ escaped\\ space} \${var\\ with\\ escaped\\ space}
syntax error, unexpected cal_SYMBOL, expecting } \(7\) syntax error, unexpected cal_SYMBOL, expecting } \(6\)
Call Stack \(most recent call first\): Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)$ CMakeLists.txt:3 \(include\)$

View File

@@ -7,6 +7,6 @@
\${var\\nwith\\nnewline} \${var\\nwith\\nnewline}
syntax error, unexpected cal_SYMBOL, expecting } \(7\) syntax error, unexpected cal_SYMBOL, expecting } \(6\)
Call Stack \(most recent call first\): Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)$ CMakeLists.txt:3 \(include\)$

View File

@@ -7,6 +7,6 @@
\${var\\nwith\\nnewline} \${var\\nwith\\nnewline}
syntax error, unexpected cal_SYMBOL, expecting } \(7\) syntax error, unexpected cal_SYMBOL, expecting } \(6\)
Call Stack \(most recent call first\): Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)$ CMakeLists.txt:3 \(include\)$

View File

@@ -7,6 +7,6 @@
\${var \${var
syntax error, unexpected \$end, expecting } \(5\) syntax error, unexpected \$end, expecting } \(6\)
Call Stack \(most recent call first\): Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)$ CMakeLists.txt:3 \(include\)$

View File

@@ -7,6 +7,6 @@
\${var with space} \${var with space}
syntax error, unexpected cal_SYMBOL, expecting } \(17\) syntax error, unexpected cal_SYMBOL, expecting } \(3\)
Call Stack \(most recent call first\): Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)$ CMakeLists.txt:3 \(include\)$

View File

@@ -7,6 +7,6 @@
\${var \${var
syntax error, unexpected \$end, expecting } \(5\) syntax error, unexpected \$end, expecting } \(6\)
Call Stack \(most recent call first\): Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)$ CMakeLists.txt:3 \(include\)$

View File

@@ -7,6 +7,6 @@
\${var with tab} \${var with tab}
syntax error, unexpected cal_SYMBOL, expecting } \(15\) syntax error, unexpected cal_SYMBOL, expecting } \(3\)
Call Stack \(most recent call first\): Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\)$ CMakeLists.txt:3 \(include\)$

View File

@@ -15,6 +15,6 @@ CMake Error at ParenInENV.cmake:2 \(message\):
-->\$ENV{e -->\$ENV{e
syntax error, unexpected \$end, expecting } \(9\) syntax error, unexpected \$end, expecting } \(10\)
Call Stack \(most recent call first\): Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\) CMakeLists.txt:3 \(include\)

View File

@@ -7,6 +7,6 @@ CMake Error at ParenInVarName1.cmake:4 \(message\):
-->\${e\(x\)}<-- -->\${e\(x\)}<--
syntax error, unexpected cal_SYMBOL, expecting } \(10\) syntax error, unexpected cal_SYMBOL, expecting } \(6\)
Call Stack \(most recent call first\): Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\) CMakeLists.txt:3 \(include\)

View File

@@ -7,6 +7,6 @@ CMake Error at UnterminatedBrace0.cmake:2 \(set\):
\${ \${
syntax error, unexpected \$end, expecting } \(2\) syntax error, unexpected \$end, expecting } \(3\)
Call Stack \(most recent call first\): Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\) CMakeLists.txt:3 \(include\)

View File

@@ -7,7 +7,7 @@ CMake Warning \(dev\) at UnterminatedBrace1.cmake:3 \(set\):
\${ \${
syntax error, unexpected \$end, expecting } \(2\) syntax error, unexpected \$end, expecting } \(3\)
Call Stack \(most recent call first\): Call Stack \(most recent call first\):
CMakeLists.txt:3 \(include\) CMakeLists.txt:3 \(include\)
This warning is for project developers. Use -Wno-dev to suppress it. This warning is for project developers. Use -Wno-dev to suppress it.