From 963b8d9f6c1c4bcce2a82ade137a82b17ef75780 Mon Sep 17 00:00:00 2001 From: Daniel Franke Date: Fri, 18 May 2018 21:59:46 +0200 Subject: math: Add RunCMake.math test to prepare for error cases --- Tests/RunCMake/CMakeLists.txt | 1 + Tests/RunCMake/math/CMakeLists.txt | 3 +++ Tests/RunCMake/math/MATH.cmake | 9 +++++++++ Tests/RunCMake/math/RunCMakeTest.cmake | 3 +++ 4 files changed, 16 insertions(+) create mode 100644 Tests/RunCMake/math/CMakeLists.txt create mode 100644 Tests/RunCMake/math/MATH.cmake create mode 100644 Tests/RunCMake/math/RunCMakeTest.cmake diff --git a/Tests/RunCMake/CMakeLists.txt b/Tests/RunCMake/CMakeLists.txt index daf3940..bd7626a 100644 --- a/Tests/RunCMake/CMakeLists.txt +++ b/Tests/RunCMake/CMakeLists.txt @@ -238,6 +238,7 @@ add_RunCMake_test(include) add_RunCMake_test(include_directories) add_RunCMake_test(include_guard) add_RunCMake_test(list) +add_RunCMake_test(math) add_RunCMake_test(message) add_RunCMake_test(project -DCMake_TEST_RESOURCES=${CMake_TEST_RESOURCES}) add_RunCMake_test(return) diff --git a/Tests/RunCMake/math/CMakeLists.txt b/Tests/RunCMake/math/CMakeLists.txt new file mode 100644 index 0000000..12cd3c7 --- /dev/null +++ b/Tests/RunCMake/math/CMakeLists.txt @@ -0,0 +1,3 @@ +cmake_minimum_required(VERSION 2.8.4) +project(${RunCMake_TEST} NONE) +include(${RunCMake_TEST}.cmake) diff --git a/Tests/RunCMake/math/MATH.cmake b/Tests/RunCMake/math/MATH.cmake new file mode 100644 index 0000000..4ec7f9c --- /dev/null +++ b/Tests/RunCMake/math/MATH.cmake @@ -0,0 +1,9 @@ +macro(math_test expression expected) + math(EXPR evaluated ${expression} ${ARGN}) + if (NOT evaluated STREQUAL ${expected}) + message(FATAL_ERROR "wrong math result: ${evaluated} != ${expected}") + endif () +endmacro() + + +math_test("100 * 10" 1000) diff --git a/Tests/RunCMake/math/RunCMakeTest.cmake b/Tests/RunCMake/math/RunCMakeTest.cmake new file mode 100644 index 0000000..7098f67 --- /dev/null +++ b/Tests/RunCMake/math/RunCMakeTest.cmake @@ -0,0 +1,3 @@ +include(RunCMake) + +run_cmake(MATH) -- cgit v0.12 From 5b0f73a15a7b49461123a969bbebceff4284df9c Mon Sep 17 00:00:00 2001 From: Daniel Franke Date: Fri, 18 May 2018 21:59:46 +0200 Subject: math: Use 64-bit integer type for computation --- Source/cmExprParserHelper.cxx | 3 ++- Source/cmExprParserHelper.h | 10 ++++++---- Source/cmMathCommand.cxx | 7 ++++--- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/Source/cmExprParserHelper.cxx b/Source/cmExprParserHelper.cxx index fe7159a..c68ebc0 100644 --- a/Source/cmExprParserHelper.cxx +++ b/Source/cmExprParserHelper.cxx @@ -13,6 +13,7 @@ cmExprParserHelper::cmExprParserHelper() { this->FileLine = -1; this->FileName = nullptr; + this->Result = 0; } cmExprParserHelper::~cmExprParserHelper() @@ -85,7 +86,7 @@ void cmExprParserHelper::Error(const char* str) this->ErrorString = ostr.str(); } -void cmExprParserHelper::SetResult(int value) +void cmExprParserHelper::SetResult(KWIML_INT_int64_t value) { this->Result = value; } diff --git a/Source/cmExprParserHelper.h b/Source/cmExprParserHelper.h index dcdaca9..c3cb53b 100644 --- a/Source/cmExprParserHelper.h +++ b/Source/cmExprParserHelper.h @@ -5,6 +5,8 @@ #include "cmConfigure.h" // IWYU pragma: keep +#include "cm_kwiml.h" + #include #include @@ -13,7 +15,7 @@ class cmExprParserHelper public: struct ParserType { - int Number; + KWIML_INT_int64_t Number; }; cmExprParserHelper(); @@ -24,9 +26,9 @@ public: int LexInput(char* buf, int maxlen); void Error(const char* str); - void SetResult(int value); + void SetResult(KWIML_INT_int64_t value); - int GetResult() { return this->Result; } + KWIML_INT_int64_t GetResult() { return this->Result; } const char* GetError() { return this->ErrorString.c_str(); } @@ -41,7 +43,7 @@ private: void CleanupParser(); - int Result; + KWIML_INT_int64_t Result; const char* FileName; long FileLine; std::string ErrorString; diff --git a/Source/cmMathCommand.cxx b/Source/cmMathCommand.cxx index c1cd1b6..f0945b2 100644 --- a/Source/cmMathCommand.cxx +++ b/Source/cmMathCommand.cxx @@ -2,10 +2,11 @@ file Copyright.txt or https://cmake.org/licensing for details. */ #include "cmMathCommand.h" -#include - #include "cmExprParserHelper.h" #include "cmMakefile.h" +#include "cm_kwiml.h" + +#include class cmExecutionStatus; @@ -44,7 +45,7 @@ bool cmMathCommand::HandleExprCommand(std::vector const& args) } char buffer[1024]; - sprintf(buffer, "%d", helper.GetResult()); + sprintf(buffer, "%" KWIML_INT_PRId64, helper.GetResult()); this->Makefile->AddDefinition(outputVariable, buffer); return true; -- cgit v0.12 From 7c4c13ffef87d748b896e2c762ad0b2c00afcd31 Mon Sep 17 00:00:00 2001 From: Daniel Franke Date: Fri, 18 May 2018 21:59:46 +0200 Subject: math: Reject unexpected expression input explicitly Switch to C++ exceptions for lexer/parser error handling. Teach the lexer/parser to fail on unexpected input. --- Source/LexerParser/cmExprLexer.cxx | 110 +++++++++-------- Source/LexerParser/cmExprLexer.in.l | 6 +- Source/LexerParser/cmExprParser.cxx | 131 +++++++++++---------- Source/LexerParser/cmExprParser.y | 1 + Source/LexerParser/cmExprParserTokens.h | 4 +- Source/cmExprParserHelper.cxx | 35 +++++- Source/cmExprParserHelper.h | 1 + Source/cmMathCommand.cxx | 6 +- .../math/MATH-InvalidExpression-result.txt | 1 + .../math/MATH-InvalidExpression-stderr.txt | 6 + Tests/RunCMake/math/MATH-InvalidExpression.cmake | 1 + Tests/RunCMake/math/RunCMakeTest.cmake | 1 + 12 files changed, 183 insertions(+), 120 deletions(-) create mode 100644 Tests/RunCMake/math/MATH-InvalidExpression-result.txt create mode 100644 Tests/RunCMake/math/MATH-InvalidExpression-stderr.txt create mode 100644 Tests/RunCMake/math/MATH-InvalidExpression.cmake diff --git a/Source/LexerParser/cmExprLexer.cxx b/Source/LexerParser/cmExprLexer.cxx index 81a1ec5..93b3ffd 100644 --- a/Source/LexerParser/cmExprLexer.cxx +++ b/Source/LexerParser/cmExprLexer.cxx @@ -548,8 +548,8 @@ static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner ); yyg->yy_hold_char = *yy_cp; \ *yy_cp = '\0'; \ yyg->yy_c_buf_p = yy_cp; -#define YY_NUM_RULES 15 -#define YY_END_OF_BUFFER 16 +#define YY_NUM_RULES 17 +#define YY_END_OF_BUFFER 18 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info @@ -557,29 +557,29 @@ struct yy_trans_info flex_int32_t yy_verify; flex_int32_t yy_nxt; }; -static const flex_int16_t yy_accept[23] = +static const flex_int16_t yy_accept[25] = { 0, - 0, 0, 16, 15, 6, 8, 13, 14, 4, 2, - 3, 5, 1, 15, 15, 9, 7, 10, 1, 11, - 12, 0 + 0, 0, 18, 16, 1, 17, 7, 9, 14, 15, + 5, 3, 4, 6, 2, 16, 16, 10, 8, 11, + 2, 12, 13, 0 } ; static const YY_CHAR yy_ec[256] = { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 1, 1, 1, 4, 5, 1, 6, + 7, 8, 9, 1, 10, 1, 11, 12, 12, 12, + 12, 12, 12, 12, 12, 12, 12, 1, 1, 13, + 1, 14, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 2, 3, 1, 4, - 5, 6, 7, 1, 8, 1, 9, 10, 10, 10, - 10, 10, 10, 10, 10, 10, 10, 1, 1, 11, - 1, 12, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 13, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 15, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 14, 1, 15, 1, 1, 1, 1, + 1, 1, 1, 16, 1, 17, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -596,40 +596,40 @@ static const YY_CHAR yy_ec[256] = 1, 1, 1, 1, 1 } ; -static const YY_CHAR yy_meta[16] = +static const YY_CHAR yy_meta[18] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1 + 1, 1, 1, 1, 1, 1, 1 } ; -static const flex_int16_t yy_base[23] = +static const flex_int16_t yy_base[25] = { 0, - 0, 0, 20, 21, 21, 21, 21, 21, 21, 21, - 21, 21, 9, 7, 5, 21, 21, 21, 6, 21, - 21, 21 + 0, 0, 22, 23, 23, 23, 23, 23, 23, 23, + 23, 23, 23, 23, 9, 7, 5, 23, 23, 23, + 6, 23, 23, 23 } ; -static const flex_int16_t yy_def[23] = +static const flex_int16_t yy_def[25] = { 0, - 22, 1, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 0 + 24, 1, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 0 } ; -static const flex_int16_t yy_nxt[37] = +static const flex_int16_t yy_nxt[41] = { 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, - 14, 15, 16, 17, 18, 19, 21, 20, 19, 22, - 3, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22 + 14, 15, 16, 17, 18, 19, 20, 21, 23, 22, + 21, 24, 3, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24 } ; -static const flex_int16_t yy_chk[37] = +static const flex_int16_t yy_chk[41] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 19, 15, 14, 13, 3, - 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, - 22, 22, 22, 22, 22, 22 + 1, 1, 1, 1, 1, 1, 1, 21, 17, 16, + 15, 3, 24, 24, 24, 24, 24, 24, 24, 24, + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24 } ; /* The intent behind this definition is that it'll catch @@ -668,6 +668,8 @@ Modify cmExprLexer.cxx: /* Include the set of tokens from the parser. */ #include "cmExprParserTokens.h" +#include + /*--------------------------------------------------------------------------*/ #define INITIAL 0 @@ -946,13 +948,13 @@ yy_match: while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 23 ) + if ( yy_current_state >= 25 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; ++yy_cp; } - while ( yy_base[yy_current_state] != 21 ); + while ( yy_base[yy_current_state] != 23 ); yy_find_action: yy_act = yy_accept[yy_current_state]; @@ -978,62 +980,70 @@ do_action: /* This label is used only to access EOF actions. */ case 1: YY_RULE_SETUP -{ yylvalp->Number = atoi(yytext); return exp_NUMBER; } +{} YY_BREAK case 2: YY_RULE_SETUP -{ return exp_PLUS; } +{ yylvalp->Number = std::stoll(yytext, nullptr, 10); return exp_NUMBER; } YY_BREAK case 3: YY_RULE_SETUP -{ return exp_MINUS; } +{ return exp_PLUS; } YY_BREAK case 4: YY_RULE_SETUP -{ return exp_TIMES; } +{ return exp_MINUS; } YY_BREAK case 5: YY_RULE_SETUP -{ return exp_DIVIDE; } +{ return exp_TIMES; } YY_BREAK case 6: YY_RULE_SETUP -{ return exp_MOD; } +{ return exp_DIVIDE; } YY_BREAK case 7: YY_RULE_SETUP -{ return exp_OR; } +{ return exp_MOD; } YY_BREAK case 8: YY_RULE_SETUP -{ return exp_AND; } +{ return exp_OR; } YY_BREAK case 9: YY_RULE_SETUP -{ return exp_XOR; } +{ return exp_AND; } YY_BREAK case 10: YY_RULE_SETUP -{ return exp_NOT; } +{ return exp_XOR; } YY_BREAK case 11: YY_RULE_SETUP -{ return exp_SHIFTLEFT; } +{ return exp_NOT; } YY_BREAK case 12: YY_RULE_SETUP -{ return exp_SHIFTRIGHT; } +{ return exp_SHIFTLEFT; } YY_BREAK case 13: YY_RULE_SETUP -{ return exp_OPENPARENT; } +{ return exp_SHIFTRIGHT; } YY_BREAK case 14: YY_RULE_SETUP -{ return exp_CLOSEPARENT; } +{ return exp_OPENPARENT; } YY_BREAK case 15: YY_RULE_SETUP +{ return exp_CLOSEPARENT; } + YY_BREAK +case 16: +YY_RULE_SETUP +{return exp_UNEXPECTED;} + YY_BREAK +case 17: +YY_RULE_SETUP ECHO; YY_BREAK case YY_STATE_EOF(INITIAL): @@ -1334,7 +1344,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 23 ) + if ( yy_current_state >= 25 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; @@ -1363,11 +1373,11 @@ static int yy_get_next_buffer (yyscan_t yyscanner) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 23 ) + if ( yy_current_state >= 25 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; - yy_is_jam = (yy_current_state == 22); + yy_is_jam = (yy_current_state == 24); (void)yyg; return yy_is_jam ? 0 : yy_current_state; diff --git a/Source/LexerParser/cmExprLexer.in.l b/Source/LexerParser/cmExprLexer.in.l index e5f177a..0c4eb9e 100644 --- a/Source/LexerParser/cmExprLexer.in.l +++ b/Source/LexerParser/cmExprLexer.in.l @@ -28,6 +28,8 @@ Modify cmExprLexer.cxx: /* Include the set of tokens from the parser. */ #include "cmExprParserTokens.h" +#include + /*--------------------------------------------------------------------------*/ %} @@ -38,8 +40,9 @@ Modify cmExprLexer.cxx: %pointer %% +[ \t] {} -[0-9][0-9]* { yylvalp->Number = atoi(yytext); return exp_NUMBER; } +[0-9][0-9]* { yylvalp->Number = std::stoll(yytext, nullptr, 10); return exp_NUMBER; } "+" { return exp_PLUS; } "-" { return exp_MINUS; } @@ -54,5 +57,6 @@ Modify cmExprLexer.cxx: ">>" { return exp_SHIFTRIGHT; } "(" { return exp_OPENPARENT; } ")" { return exp_CLOSEPARENT; } +. {return exp_UNEXPECTED;} %% diff --git a/Source/LexerParser/cmExprParser.cxx b/Source/LexerParser/cmExprParser.cxx index 67664a5..1311390 100644 --- a/Source/LexerParser/cmExprParser.cxx +++ b/Source/LexerParser/cmExprParser.cxx @@ -156,7 +156,8 @@ extern int cmExpr_yydebug; exp_AND = 268, exp_XOR = 269, exp_NOT = 270, - exp_NUMBER = 271 + exp_NUMBER = 271, + exp_UNEXPECTED = 272 }; #endif /* Tokens. */ @@ -174,6 +175,7 @@ extern int cmExpr_yydebug; #define exp_XOR 269 #define exp_NOT 270 #define exp_NUMBER 271 +#define exp_UNEXPECTED 272 /* Value type. */ @@ -185,7 +187,7 @@ int cmExpr_yyparse (yyscan_t yyscanner); /* Copy the second part of user declarations. */ -#line 189 "cmExprParser.cxx" /* yacc.c:358 */ +#line 191 "cmExprParser.cxx" /* yacc.c:358 */ #ifdef short # undef short @@ -430,7 +432,7 @@ union yyalloc #define YYLAST 30 /* YYNTOKENS -- Number of terminals. */ -#define YYNTOKENS 17 +#define YYNTOKENS 18 /* YYNNTS -- Number of nonterminals. */ #define YYNNTS 10 /* YYNRULES -- Number of rules. */ @@ -441,7 +443,7 @@ union yyalloc /* YYTRANSLATE[YYX] -- Symbol number corresponding to YYX as returned by yylex, with out-of-bounds checking. */ #define YYUNDEFTOK 2 -#define YYMAXUTOK 271 +#define YYMAXUTOK 272 #define YYTRANSLATE(YYX) \ ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) @@ -477,16 +479,16 @@ static const yytype_uint8 yytranslate[] = 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, - 15, 16 + 15, 16, 17 }; #if YYDEBUG /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_uint8 yyrline[] = { - 0, 73, 73, 78, 81, 86, 89, 94, 97, 102, - 105, 108, 113, 116, 119, 124, 127, 130, 133, 138, - 141, 144, 149, 152 + 0, 74, 74, 79, 82, 87, 90, 95, 98, 103, + 106, 109, 114, 117, 120, 125, 128, 131, 134, 139, + 142, 145, 150, 153 }; #endif @@ -498,8 +500,9 @@ static const char *const yytname[] = "$end", "error", "$undefined", "exp_PLUS", "exp_MINUS", "exp_TIMES", "exp_DIVIDE", "exp_MOD", "exp_SHIFTLEFT", "exp_SHIFTRIGHT", "exp_OPENPARENT", "exp_CLOSEPARENT", "exp_OR", "exp_AND", "exp_XOR", - "exp_NOT", "exp_NUMBER", "$accept", "start", "exp", "bitwiseor", - "bitwisexor", "bitwiseand", "shift", "term", "unary", "factor", YY_NULLPTR + "exp_NOT", "exp_NUMBER", "\"character\"", "$accept", "start", "exp", + "bitwiseor", "bitwisexor", "bitwiseand", "shift", "term", "unary", + "factor", YY_NULLPTR }; #endif @@ -509,7 +512,7 @@ static const char *const yytname[] = static const yytype_uint16 yytoknum[] = { 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, - 265, 266, 267, 268, 269, 270, 271 + 265, 266, 267, 268, 269, 270, 271, 272 }; # endif @@ -579,18 +582,18 @@ static const yytype_int8 yycheck[] = symbol of state STATE-NUM. */ static const yytype_uint8 yystos[] = { - 0, 3, 4, 10, 16, 18, 19, 20, 21, 22, - 23, 24, 25, 26, 25, 25, 19, 0, 12, 14, - 13, 8, 9, 3, 4, 5, 6, 7, 11, 20, - 21, 22, 23, 23, 24, 24, 25, 25, 25 + 0, 3, 4, 10, 16, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 26, 26, 20, 0, 12, 14, + 13, 8, 9, 3, 4, 5, 6, 7, 11, 21, + 22, 23, 24, 24, 25, 25, 26, 26, 26 }; /* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ static const yytype_uint8 yyr1[] = { - 0, 17, 18, 19, 19, 20, 20, 21, 21, 22, - 22, 22, 23, 23, 23, 24, 24, 24, 24, 25, - 25, 25, 26, 26 + 0, 18, 19, 20, 20, 21, 21, 22, 22, 23, + 23, 23, 24, 24, 24, 25, 25, 25, 25, 26, + 26, 26, 27, 27 }; /* YYR2[YYN] -- Number of symbols on the right hand side of rule YYN. */ @@ -1281,183 +1284,183 @@ yyreduce: switch (yyn) { case 2: -#line 73 "cmExprParser.y" /* yacc.c:1646 */ +#line 74 "cmExprParser.y" /* yacc.c:1646 */ { cmExpr_yyget_extra(yyscanner)->SetResult((yyvsp[0].Number)); } -#line 1289 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1292 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 3: -#line 78 "cmExprParser.y" /* yacc.c:1646 */ +#line 79 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[0].Number); } -#line 1297 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1300 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 4: -#line 81 "cmExprParser.y" /* yacc.c:1646 */ +#line 82 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[-2].Number) | (yyvsp[0].Number); } -#line 1305 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1308 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 5: -#line 86 "cmExprParser.y" /* yacc.c:1646 */ +#line 87 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[0].Number); } -#line 1313 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1316 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 6: -#line 89 "cmExprParser.y" /* yacc.c:1646 */ +#line 90 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[-2].Number) ^ (yyvsp[0].Number); } -#line 1321 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1324 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 7: -#line 94 "cmExprParser.y" /* yacc.c:1646 */ +#line 95 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[0].Number); } -#line 1329 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1332 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 8: -#line 97 "cmExprParser.y" /* yacc.c:1646 */ +#line 98 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[-2].Number) & (yyvsp[0].Number); } -#line 1337 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1340 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 9: -#line 102 "cmExprParser.y" /* yacc.c:1646 */ +#line 103 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[0].Number); } -#line 1345 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1348 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 10: -#line 105 "cmExprParser.y" /* yacc.c:1646 */ +#line 106 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[-2].Number) << (yyvsp[0].Number); } -#line 1353 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1356 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 11: -#line 108 "cmExprParser.y" /* yacc.c:1646 */ +#line 109 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[-2].Number) >> (yyvsp[0].Number); } -#line 1361 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1364 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 12: -#line 113 "cmExprParser.y" /* yacc.c:1646 */ +#line 114 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[0].Number); } -#line 1369 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1372 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 13: -#line 116 "cmExprParser.y" /* yacc.c:1646 */ +#line 117 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[-2].Number) + (yyvsp[0].Number); } -#line 1377 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1380 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 14: -#line 119 "cmExprParser.y" /* yacc.c:1646 */ +#line 120 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[-2].Number) - (yyvsp[0].Number); } -#line 1385 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1388 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 15: -#line 124 "cmExprParser.y" /* yacc.c:1646 */ +#line 125 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[0].Number); } -#line 1393 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1396 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 16: -#line 127 "cmExprParser.y" /* yacc.c:1646 */ +#line 128 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[-2].Number) * (yyvsp[0].Number); } -#line 1401 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1404 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 17: -#line 130 "cmExprParser.y" /* yacc.c:1646 */ +#line 131 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[-2].Number) / (yyvsp[0].Number); } -#line 1409 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1412 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 18: -#line 133 "cmExprParser.y" /* yacc.c:1646 */ +#line 134 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[-2].Number) % (yyvsp[0].Number); } -#line 1417 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1420 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 19: -#line 138 "cmExprParser.y" /* yacc.c:1646 */ +#line 139 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[0].Number); } -#line 1425 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1428 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 20: -#line 141 "cmExprParser.y" /* yacc.c:1646 */ +#line 142 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = + (yyvsp[0].Number); } -#line 1433 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1436 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 21: -#line 144 "cmExprParser.y" /* yacc.c:1646 */ +#line 145 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = - (yyvsp[0].Number); } -#line 1441 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1444 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 22: -#line 149 "cmExprParser.y" /* yacc.c:1646 */ +#line 150 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[0].Number); } -#line 1449 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1452 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 23: -#line 152 "cmExprParser.y" /* yacc.c:1646 */ +#line 153 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[-1].Number); } -#line 1457 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1460 "cmExprParser.cxx" /* yacc.c:1646 */ break; -#line 1461 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1464 "cmExprParser.cxx" /* yacc.c:1646 */ default: break; } /* User semantic actions sometimes alter yychar, and that requires @@ -1687,7 +1690,7 @@ yyreturn: #endif return yyresult; } -#line 157 "cmExprParser.y" /* yacc.c:1906 */ +#line 158 "cmExprParser.y" /* yacc.c:1906 */ /* End of grammar */ diff --git a/Source/LexerParser/cmExprParser.y b/Source/LexerParser/cmExprParser.y index d1c3a97..575ffa7 100644 --- a/Source/LexerParser/cmExprParser.y +++ b/Source/LexerParser/cmExprParser.y @@ -63,6 +63,7 @@ static void cmExpr_yyerror(yyscan_t yyscanner, const char* message); %token exp_XOR; %token exp_NOT; %token exp_NUMBER; +%token exp_UNEXPECTED "character"; /*-------------------------------------------------------------------------*/ /* grammar */ diff --git a/Source/LexerParser/cmExprParserTokens.h b/Source/LexerParser/cmExprParserTokens.h index 84b2bbd..00be4e9 100644 --- a/Source/LexerParser/cmExprParserTokens.h +++ b/Source/LexerParser/cmExprParserTokens.h @@ -58,7 +58,8 @@ extern int cmExpr_yydebug; exp_AND = 268, exp_XOR = 269, exp_NOT = 270, - exp_NUMBER = 271 + exp_NUMBER = 271, + exp_UNEXPECTED = 272 }; #endif /* Tokens. */ @@ -76,6 +77,7 @@ extern int cmExpr_yydebug; #define exp_XOR 269 #define exp_NOT 270 #define exp_NUMBER 271 +#define exp_UNEXPECTED 272 /* Value type. */ diff --git a/Source/cmExprParserHelper.cxx b/Source/cmExprParserHelper.cxx index c68ebc0..d90d8b9 100644 --- a/Source/cmExprParserHelper.cxx +++ b/Source/cmExprParserHelper.cxx @@ -6,6 +6,8 @@ #include #include +#include +#include int cmExpr_yyparse(yyscan_t yyscanner); // @@ -38,7 +40,33 @@ int cmExprParserHelper::ParseString(const char* str, int verb) yyscan_t yyscanner; cmExpr_yylex_init(&yyscanner); cmExpr_yyset_extra(this, yyscanner); - int res = cmExpr_yyparse(yyscanner); + int res; + + try { + res = cmExpr_yyparse(yyscanner); + if (res != 0) { + std::string e = "cannot parse the expression: \"" + InputBuffer + "\": "; + e += ErrorString; + e += "."; + this->SetError(std::move(e)); + } + } catch (std::runtime_error const& fail) { + std::string e = + "cannot evaluate the expression: \"" + InputBuffer + "\": "; + e += fail.what(); + e += "."; + this->SetError(std::move(e)); + res = 1; + } catch (std::out_of_range const&) { + std::string e = "cannot evaluate the expression: \"" + InputBuffer + + "\": a numeric value is out of range."; + this->SetError(std::move(e)); + res = 1; + } catch (...) { + std::string e = "cannot parse the expression: \"" + InputBuffer + "\"."; + this->SetError(std::move(e)); + res = 1; + } cmExpr_yylex_destroy(yyscanner); if (res != 0) { // str << "CAL_Parser returned: " << res << std::endl; @@ -90,3 +118,8 @@ void cmExprParserHelper::SetResult(KWIML_INT_int64_t value) { this->Result = value; } + +void cmExprParserHelper::SetError(std::string errorString) +{ + this->ErrorString = std::move(errorString); +} diff --git a/Source/cmExprParserHelper.h b/Source/cmExprParserHelper.h index c3cb53b..d4d95b4 100644 --- a/Source/cmExprParserHelper.h +++ b/Source/cmExprParserHelper.h @@ -42,6 +42,7 @@ private: void Print(const char* place, const char* str); void CleanupParser(); + void SetError(std::string errorString); KWIML_INT_int64_t Result; const char* FileName; diff --git a/Source/cmMathCommand.cxx b/Source/cmMathCommand.cxx index f0945b2..ab77dc3 100644 --- a/Source/cmMathCommand.cxx +++ b/Source/cmMathCommand.cxx @@ -36,11 +36,11 @@ bool cmMathCommand::HandleExprCommand(std::vector const& args) const std::string& outputVariable = args[1]; const std::string& expression = args[2]; + this->Makefile->AddDefinition(outputVariable, "ERROR"); + cmExprParserHelper helper; if (!helper.ParseString(expression.c_str(), 0)) { - std::string e = "cannot parse the expression: \"" + expression + "\": "; - e += helper.GetError(); - this->SetError(e); + this->SetError(helper.GetError()); return false; } diff --git a/Tests/RunCMake/math/MATH-InvalidExpression-result.txt b/Tests/RunCMake/math/MATH-InvalidExpression-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/math/MATH-InvalidExpression-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/math/MATH-InvalidExpression-stderr.txt b/Tests/RunCMake/math/MATH-InvalidExpression-stderr.txt new file mode 100644 index 0000000..18ac9f7 --- /dev/null +++ b/Tests/RunCMake/math/MATH-InvalidExpression-stderr.txt @@ -0,0 +1,6 @@ +^CMake Error at MATH-InvalidExpression.cmake:1 \(math\): + *math cannot parse the expression: "INVALID": syntax error, unexpected + *character, expecting exp_PLUS or exp_MINUS or exp_OPENPARENT or exp_NUMBER + *\(1\). +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/math/MATH-InvalidExpression.cmake b/Tests/RunCMake/math/MATH-InvalidExpression.cmake new file mode 100644 index 0000000..6e37128 --- /dev/null +++ b/Tests/RunCMake/math/MATH-InvalidExpression.cmake @@ -0,0 +1 @@ +math(EXPR var "INVALID") diff --git a/Tests/RunCMake/math/RunCMakeTest.cmake b/Tests/RunCMake/math/RunCMakeTest.cmake index 7098f67..d767547 100644 --- a/Tests/RunCMake/math/RunCMakeTest.cmake +++ b/Tests/RunCMake/math/RunCMakeTest.cmake @@ -1,3 +1,4 @@ include(RunCMake) run_cmake(MATH) +run_cmake(MATH-InvalidExpression) -- cgit v0.12 From 8661e7052c4f711f13e7168231276e23c4c0defd Mon Sep 17 00:00:00 2001 From: Daniel Franke Date: Fri, 18 May 2018 21:59:46 +0200 Subject: math: Diagnose divide-by-zero --- Source/LexerParser/cmExprParser.cxx | 106 ++++++++++++----------- Source/LexerParser/cmExprParser.y | 4 + Tests/RunCMake/math/MATH-DivideByZero-result.txt | 1 + Tests/RunCMake/math/MATH-DivideByZero-stderr.txt | 4 + Tests/RunCMake/math/MATH-DivideByZero.cmake | 1 + Tests/RunCMake/math/RunCMakeTest.cmake | 1 + 6 files changed, 66 insertions(+), 51 deletions(-) create mode 100644 Tests/RunCMake/math/MATH-DivideByZero-result.txt create mode 100644 Tests/RunCMake/math/MATH-DivideByZero-stderr.txt create mode 100644 Tests/RunCMake/math/MATH-DivideByZero.cmake diff --git a/Source/LexerParser/cmExprParser.cxx b/Source/LexerParser/cmExprParser.cxx index 1311390..cbb8078 100644 --- a/Source/LexerParser/cmExprParser.cxx +++ b/Source/LexerParser/cmExprParser.cxx @@ -89,6 +89,7 @@ Modify cmExprParser.cxx: #include #include +#include /*-------------------------------------------------------------------------*/ #define YYDEBUG 1 @@ -108,7 +109,7 @@ static void cmExpr_yyerror(yyscan_t yyscanner, const char* message); # pragma warning (disable: 4065) /* Switch statement contains default but no case. */ #endif -#line 112 "cmExprParser.cxx" /* yacc.c:339 */ +#line 113 "cmExprParser.cxx" /* yacc.c:339 */ # ifndef YY_NULLPTR # if defined __cplusplus && 201103L <= __cplusplus @@ -187,7 +188,7 @@ int cmExpr_yyparse (yyscan_t yyscanner); /* Copy the second part of user declarations. */ -#line 191 "cmExprParser.cxx" /* yacc.c:358 */ +#line 192 "cmExprParser.cxx" /* yacc.c:358 */ #ifdef short # undef short @@ -486,9 +487,9 @@ static const yytype_uint8 yytranslate[] = /* YYRLINE[YYN] -- Source line where rule number YYN was defined. */ static const yytype_uint8 yyrline[] = { - 0, 74, 74, 79, 82, 87, 90, 95, 98, 103, - 106, 109, 114, 117, 120, 125, 128, 131, 134, 139, - 142, 145, 150, 153 + 0, 75, 75, 80, 83, 88, 91, 96, 99, 104, + 107, 110, 115, 118, 121, 126, 129, 132, 138, 143, + 146, 149, 154, 157 }; #endif @@ -1284,183 +1285,186 @@ yyreduce: switch (yyn) { case 2: -#line 74 "cmExprParser.y" /* yacc.c:1646 */ +#line 75 "cmExprParser.y" /* yacc.c:1646 */ { cmExpr_yyget_extra(yyscanner)->SetResult((yyvsp[0].Number)); } -#line 1292 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1293 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 3: -#line 79 "cmExprParser.y" /* yacc.c:1646 */ +#line 80 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[0].Number); } -#line 1300 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1301 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 4: -#line 82 "cmExprParser.y" /* yacc.c:1646 */ +#line 83 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[-2].Number) | (yyvsp[0].Number); } -#line 1308 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1309 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 5: -#line 87 "cmExprParser.y" /* yacc.c:1646 */ +#line 88 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[0].Number); } -#line 1316 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1317 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 6: -#line 90 "cmExprParser.y" /* yacc.c:1646 */ +#line 91 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[-2].Number) ^ (yyvsp[0].Number); } -#line 1324 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1325 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 7: -#line 95 "cmExprParser.y" /* yacc.c:1646 */ +#line 96 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[0].Number); } -#line 1332 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1333 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 8: -#line 98 "cmExprParser.y" /* yacc.c:1646 */ +#line 99 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[-2].Number) & (yyvsp[0].Number); } -#line 1340 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1341 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 9: -#line 103 "cmExprParser.y" /* yacc.c:1646 */ +#line 104 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[0].Number); } -#line 1348 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1349 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 10: -#line 106 "cmExprParser.y" /* yacc.c:1646 */ +#line 107 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[-2].Number) << (yyvsp[0].Number); } -#line 1356 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1357 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 11: -#line 109 "cmExprParser.y" /* yacc.c:1646 */ +#line 110 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[-2].Number) >> (yyvsp[0].Number); } -#line 1364 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1365 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 12: -#line 114 "cmExprParser.y" /* yacc.c:1646 */ +#line 115 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[0].Number); } -#line 1372 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1373 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 13: -#line 117 "cmExprParser.y" /* yacc.c:1646 */ +#line 118 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[-2].Number) + (yyvsp[0].Number); } -#line 1380 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1381 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 14: -#line 120 "cmExprParser.y" /* yacc.c:1646 */ +#line 121 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[-2].Number) - (yyvsp[0].Number); } -#line 1388 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1389 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 15: -#line 125 "cmExprParser.y" /* yacc.c:1646 */ +#line 126 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[0].Number); } -#line 1396 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1397 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 16: -#line 128 "cmExprParser.y" /* yacc.c:1646 */ +#line 129 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[-2].Number) * (yyvsp[0].Number); } -#line 1404 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1405 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 17: -#line 131 "cmExprParser.y" /* yacc.c:1646 */ +#line 132 "cmExprParser.y" /* yacc.c:1646 */ { + if (yyvsp[0].Number == 0) { + throw std::overflow_error("divide by zero"); + } (yyval.Number) = (yyvsp[-2].Number) / (yyvsp[0].Number); } -#line 1412 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1416 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 18: -#line 134 "cmExprParser.y" /* yacc.c:1646 */ +#line 138 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[-2].Number) % (yyvsp[0].Number); } -#line 1420 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1424 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 19: -#line 139 "cmExprParser.y" /* yacc.c:1646 */ +#line 143 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[0].Number); } -#line 1428 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1432 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 20: -#line 142 "cmExprParser.y" /* yacc.c:1646 */ +#line 146 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = + (yyvsp[0].Number); } -#line 1436 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1440 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 21: -#line 145 "cmExprParser.y" /* yacc.c:1646 */ +#line 149 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = - (yyvsp[0].Number); } -#line 1444 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1448 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 22: -#line 150 "cmExprParser.y" /* yacc.c:1646 */ +#line 154 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[0].Number); } -#line 1452 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1456 "cmExprParser.cxx" /* yacc.c:1646 */ break; case 23: -#line 153 "cmExprParser.y" /* yacc.c:1646 */ +#line 157 "cmExprParser.y" /* yacc.c:1646 */ { (yyval.Number) = (yyvsp[-1].Number); } -#line 1460 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1464 "cmExprParser.cxx" /* yacc.c:1646 */ break; -#line 1464 "cmExprParser.cxx" /* yacc.c:1646 */ +#line 1468 "cmExprParser.cxx" /* yacc.c:1646 */ default: break; } /* User semantic actions sometimes alter yychar, and that requires @@ -1690,7 +1694,7 @@ yyreturn: #endif return yyresult; } -#line 158 "cmExprParser.y" /* yacc.c:1906 */ +#line 162 "cmExprParser.y" /* yacc.c:1906 */ /* End of grammar */ diff --git a/Source/LexerParser/cmExprParser.y b/Source/LexerParser/cmExprParser.y index 575ffa7..510daaa 100644 --- a/Source/LexerParser/cmExprParser.y +++ b/Source/LexerParser/cmExprParser.y @@ -18,6 +18,7 @@ Modify cmExprParser.cxx: #include #include +#include /*-------------------------------------------------------------------------*/ #define YYDEBUG 1 @@ -129,6 +130,9 @@ term: $$ = $1 * $3; } | term exp_DIVIDE unary { + if (yyvsp[0].Number == 0) { + throw std::overflow_error("divide by zero"); + } $$ = $1 / $3; } | term exp_MOD unary { diff --git a/Tests/RunCMake/math/MATH-DivideByZero-result.txt b/Tests/RunCMake/math/MATH-DivideByZero-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/math/MATH-DivideByZero-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/math/MATH-DivideByZero-stderr.txt b/Tests/RunCMake/math/MATH-DivideByZero-stderr.txt new file mode 100644 index 0000000..66ad633 --- /dev/null +++ b/Tests/RunCMake/math/MATH-DivideByZero-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at MATH-DivideByZero.cmake:1 \(math\): + math cannot evaluate the expression: "100/0": divide by zero. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/math/MATH-DivideByZero.cmake b/Tests/RunCMake/math/MATH-DivideByZero.cmake new file mode 100644 index 0000000..3ac161e --- /dev/null +++ b/Tests/RunCMake/math/MATH-DivideByZero.cmake @@ -0,0 +1 @@ +math(EXPR var "100/0") diff --git a/Tests/RunCMake/math/RunCMakeTest.cmake b/Tests/RunCMake/math/RunCMakeTest.cmake index d767547..4c4b725 100644 --- a/Tests/RunCMake/math/RunCMakeTest.cmake +++ b/Tests/RunCMake/math/RunCMakeTest.cmake @@ -2,3 +2,4 @@ include(RunCMake) run_cmake(MATH) run_cmake(MATH-InvalidExpression) +run_cmake(MATH-DivideByZero) -- cgit v0.12 From 5dbee9d2d0f68e1fc343d04ac00a4a35d43df6fa Mon Sep 17 00:00:00 2001 From: Daniel Franke Date: Fri, 18 May 2018 21:59:46 +0200 Subject: math: Add options to calculate and format output as hexadecimal --- Help/command/math.rst | 18 +++- Help/release/dev/math-hex.rst | 4 + Source/LexerParser/cmExprLexer.cxx | 112 +++++++++++---------- Source/LexerParser/cmExprLexer.in.l | 1 + Source/cmMathCommand.cxx | 58 ++++++++++- Tests/MathTest/CMakeLists.txt | 33 ++++-- Tests/MathTest/MathTestExec.cxx | 40 ++++++-- Tests/RunCMake/math/MATH-DoubleOption-result.txt | 1 + Tests/RunCMake/math/MATH-DoubleOption-stderr.txt | 4 + Tests/RunCMake/math/MATH-DoubleOption.cmake | 1 + .../RunCMake/math/MATH-TooManyArguments-result.txt | 1 + .../RunCMake/math/MATH-TooManyArguments-stderr.txt | 4 + Tests/RunCMake/math/MATH-TooManyArguments.cmake | 1 + Tests/RunCMake/math/MATH-WrongArgument-result.txt | 1 + Tests/RunCMake/math/MATH-WrongArgument-stderr.txt | 4 + Tests/RunCMake/math/MATH-WrongArgument.cmake | 1 + Tests/RunCMake/math/MATH.cmake | 3 + Tests/RunCMake/math/RunCMakeTest.cmake | 3 + 18 files changed, 221 insertions(+), 69 deletions(-) create mode 100644 Help/release/dev/math-hex.rst create mode 100644 Tests/RunCMake/math/MATH-DoubleOption-result.txt create mode 100644 Tests/RunCMake/math/MATH-DoubleOption-stderr.txt create mode 100644 Tests/RunCMake/math/MATH-DoubleOption.cmake create mode 100644 Tests/RunCMake/math/MATH-TooManyArguments-result.txt create mode 100644 Tests/RunCMake/math/MATH-TooManyArguments-stderr.txt create mode 100644 Tests/RunCMake/math/MATH-TooManyArguments.cmake create mode 100644 Tests/RunCMake/math/MATH-WrongArgument-result.txt create mode 100644 Tests/RunCMake/math/MATH-WrongArgument-stderr.txt create mode 100644 Tests/RunCMake/math/MATH-WrongArgument.cmake diff --git a/Help/command/math.rst b/Help/command/math.rst index f99dc3d..63af931 100644 --- a/Help/command/math.rst +++ b/Help/command/math.rst @@ -5,10 +5,26 @@ Mathematical expressions. :: - math(EXPR ) + math(EXPR [OUTPUT_FORMAT ]) ``EXPR`` evaluates mathematical expression and returns result in the output variable. Example mathematical expression is ``5 * (10 + 13)``. Supported operators are ``+``, ``-``, ``*``, ``/``, ``%``, ``|``, ``&``, ``^``, ``~``, ``<<``, ``>>``, and ``(...)``. They have the same meaning as they do in C code. + +Numeric constants are evaluated in decimal or hexadecimal representation. + +The result is formatted according to the option "OUTPUT_FORMAT" , +where ```` is one of: +:: + + HEXADECIMAL = Result in output variable will be formatted in C code + Hexadecimal notation. + DECIMAL = Result in output variable will be formatted in decimal notation. + + +For example:: + + math(EXPR value "100 * 0xA" DECIMAL) results in value is set to "1000" + math(EXPR value "100 * 0xA" HEXADECIMAL) results in value is set to "0x3e8" diff --git a/Help/release/dev/math-hex.rst b/Help/release/dev/math-hex.rst new file mode 100644 index 0000000..16e21ec --- /dev/null +++ b/Help/release/dev/math-hex.rst @@ -0,0 +1,4 @@ +math-hex +-------- + +* The :command:`math` command gained options for hexadecimal. diff --git a/Source/LexerParser/cmExprLexer.cxx b/Source/LexerParser/cmExprLexer.cxx index 93b3ffd..1548daf 100644 --- a/Source/LexerParser/cmExprLexer.cxx +++ b/Source/LexerParser/cmExprLexer.cxx @@ -548,8 +548,8 @@ static void yynoreturn yy_fatal_error ( const char* msg , yyscan_t yyscanner ); yyg->yy_hold_char = *yy_cp; \ *yy_cp = '\0'; \ yyg->yy_c_buf_p = yy_cp; -#define YY_NUM_RULES 17 -#define YY_END_OF_BUFFER 18 +#define YY_NUM_RULES 18 +#define YY_END_OF_BUFFER 19 /* This struct is not used in this scanner, but its presence is necessary. */ struct yy_trans_info @@ -557,11 +557,11 @@ struct yy_trans_info flex_int32_t yy_verify; flex_int32_t yy_nxt; }; -static const flex_int16_t yy_accept[25] = +static const flex_int16_t yy_accept[29] = { 0, - 0, 0, 18, 16, 1, 17, 7, 9, 14, 15, - 5, 3, 4, 6, 2, 16, 16, 10, 8, 11, - 2, 12, 13, 0 + 0, 0, 19, 17, 1, 18, 8, 10, 15, 16, + 6, 4, 5, 7, 2, 2, 17, 17, 11, 9, + 12, 2, 0, 13, 14, 3, 3, 0 } ; static const YY_CHAR yy_ec[256] = @@ -570,16 +570,16 @@ static const YY_CHAR yy_ec[256] = 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 4, 5, 1, 6, - 7, 8, 9, 1, 10, 1, 11, 12, 12, 12, - 12, 12, 12, 12, 12, 12, 12, 1, 1, 13, - 1, 14, 1, 1, 1, 1, 1, 1, 1, 1, + 7, 8, 9, 1, 10, 1, 11, 12, 13, 13, + 13, 13, 13, 13, 13, 13, 13, 1, 1, 14, + 1, 15, 1, 1, 16, 16, 16, 16, 16, 16, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 15, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 17, 1, 1, + 1, 1, 1, 18, 1, 1, 16, 16, 16, 16, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 16, 1, 17, 1, 1, 1, 1, + 16, 16, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 17, + 1, 1, 1, 19, 1, 20, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, @@ -596,40 +596,46 @@ static const YY_CHAR yy_ec[256] = 1, 1, 1, 1, 1 } ; -static const YY_CHAR yy_meta[18] = +static const YY_CHAR yy_meta[21] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1 + 1, 2, 2, 1, 1, 3, 4, 1, 1, 1 } ; -static const flex_int16_t yy_base[25] = +static const flex_int16_t yy_base[32] = { 0, - 0, 0, 22, 23, 23, 23, 23, 23, 23, 23, - 23, 23, 23, 23, 9, 7, 5, 23, 23, 23, - 6, 23, 23, 23 + 0, 0, 34, 35, 35, 35, 35, 35, 35, 35, + 35, 35, 35, 35, 16, 9, 18, 11, 35, 35, + 35, 11, 0, 35, 35, 0, 0, 35, 23, 26, + 28 } ; -static const flex_int16_t yy_def[25] = +static const flex_int16_t yy_def[32] = { 0, - 24, 1, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 0 + 28, 1, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 29, 28, 28, 28, 28, 28, + 28, 28, 30, 28, 28, 31, 31, 0, 28, 28, + 28 } ; -static const flex_int16_t yy_nxt[41] = +static const flex_int16_t yy_nxt[56] = { 0, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, - 14, 15, 16, 17, 18, 19, 20, 21, 23, 22, - 21, 24, 3, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24 + 14, 15, 16, 17, 18, 4, 4, 19, 20, 21, + 22, 22, 22, 22, 22, 25, 22, 26, 26, 27, + 27, 24, 23, 28, 3, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28 } ; -static const flex_int16_t yy_chk[41] = +static const flex_int16_t yy_chk[56] = { 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 21, 17, 16, - 15, 3, 24, 24, 24, 24, 24, 24, 24, 24, - 24, 24, 24, 24, 24, 24, 24, 24, 24, 24 + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 16, 16, 22, 22, 29, 18, 29, 30, 30, 31, + 31, 17, 15, 3, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, + 28, 28, 28, 28, 28 } ; /* The intent behind this definition is that it'll catch @@ -948,13 +954,13 @@ yy_match: while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 25 ) + if ( yy_current_state >= 29 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; ++yy_cp; } - while ( yy_base[yy_current_state] != 23 ); + while ( yy_base[yy_current_state] != 35 ); yy_find_action: yy_act = yy_accept[yy_current_state]; @@ -988,62 +994,66 @@ YY_RULE_SETUP YY_BREAK case 3: YY_RULE_SETUP -{ return exp_PLUS; } +{ yylvalp->Number = std::stoll(yytext, nullptr, 16); return exp_NUMBER; } YY_BREAK case 4: YY_RULE_SETUP -{ return exp_MINUS; } +{ return exp_PLUS; } YY_BREAK case 5: YY_RULE_SETUP -{ return exp_TIMES; } +{ return exp_MINUS; } YY_BREAK case 6: YY_RULE_SETUP -{ return exp_DIVIDE; } +{ return exp_TIMES; } YY_BREAK case 7: YY_RULE_SETUP -{ return exp_MOD; } +{ return exp_DIVIDE; } YY_BREAK case 8: YY_RULE_SETUP -{ return exp_OR; } +{ return exp_MOD; } YY_BREAK case 9: YY_RULE_SETUP -{ return exp_AND; } +{ return exp_OR; } YY_BREAK case 10: YY_RULE_SETUP -{ return exp_XOR; } +{ return exp_AND; } YY_BREAK case 11: YY_RULE_SETUP -{ return exp_NOT; } +{ return exp_XOR; } YY_BREAK case 12: YY_RULE_SETUP -{ return exp_SHIFTLEFT; } +{ return exp_NOT; } YY_BREAK case 13: YY_RULE_SETUP -{ return exp_SHIFTRIGHT; } +{ return exp_SHIFTLEFT; } YY_BREAK case 14: YY_RULE_SETUP -{ return exp_OPENPARENT; } +{ return exp_SHIFTRIGHT; } YY_BREAK case 15: YY_RULE_SETUP -{ return exp_CLOSEPARENT; } +{ return exp_OPENPARENT; } YY_BREAK case 16: YY_RULE_SETUP -{return exp_UNEXPECTED;} +{ return exp_CLOSEPARENT; } YY_BREAK case 17: YY_RULE_SETUP +{return exp_UNEXPECTED;} + YY_BREAK +case 18: +YY_RULE_SETUP ECHO; YY_BREAK case YY_STATE_EOF(INITIAL): @@ -1344,7 +1354,7 @@ static int yy_get_next_buffer (yyscan_t yyscanner) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 25 ) + if ( yy_current_state >= 29 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; @@ -1373,11 +1383,11 @@ static int yy_get_next_buffer (yyscan_t yyscanner) while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) { yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 25 ) + if ( yy_current_state >= 29 ) yy_c = yy_meta[yy_c]; } yy_current_state = yy_nxt[yy_base[yy_current_state] + yy_c]; - yy_is_jam = (yy_current_state == 24); + yy_is_jam = (yy_current_state == 28); (void)yyg; return yy_is_jam ? 0 : yy_current_state; diff --git a/Source/LexerParser/cmExprLexer.in.l b/Source/LexerParser/cmExprLexer.in.l index 0c4eb9e..87237d1 100644 --- a/Source/LexerParser/cmExprLexer.in.l +++ b/Source/LexerParser/cmExprLexer.in.l @@ -43,6 +43,7 @@ Modify cmExprLexer.cxx: [ \t] {} [0-9][0-9]* { yylvalp->Number = std::stoll(yytext, nullptr, 10); return exp_NUMBER; } +0[xX][0-9a-fA-F][0-9a-fA-F]* { yylvalp->Number = std::stoll(yytext, nullptr, 16); return exp_NUMBER; } "+" { return exp_PLUS; } "-" { return exp_MINUS; } diff --git a/Source/cmMathCommand.cxx b/Source/cmMathCommand.cxx index ab77dc3..5d1b099 100644 --- a/Source/cmMathCommand.cxx +++ b/Source/cmMathCommand.cxx @@ -28,16 +28,59 @@ bool cmMathCommand::InitialPass(std::vector const& args, bool cmMathCommand::HandleExprCommand(std::vector const& args) { - if (args.size() != 3) { + if ((args.size() != 3) && (args.size() != 5)) { this->SetError("EXPR called with incorrect arguments."); return false; } + enum class NumericFormat + { + UNINITIALIZED, + DECIMAL, + HEXADECIMAL, + }; + const std::string& outputVariable = args[1]; const std::string& expression = args[2]; + size_t argumentIndex = 3; + NumericFormat outputFormat = NumericFormat::UNINITIALIZED; this->Makefile->AddDefinition(outputVariable, "ERROR"); + if (argumentIndex < args.size()) { + const std::string messageHint = "sub-command EXPR "; + const std::string option = args[argumentIndex++]; + if (option == "OUTPUT_FORMAT") { + if (argumentIndex < args.size()) { + const std::string argument = args[argumentIndex++]; + if (argument == "DECIMAL") { + outputFormat = NumericFormat::DECIMAL; + } else if (argument == "HEXADECIMAL") { + outputFormat = NumericFormat::HEXADECIMAL; + } else { + std::string error = messageHint + "value \"" + argument + + "\" for option \"" + option + "\" is invalid."; + this->SetError(error); + return false; + } + } else { + std::string error = + messageHint + "missing argument for option \"" + option + "\"."; + this->SetError(error); + return false; + } + } else { + std::string error = + messageHint + "option \"" + option + "\" is unknown."; + this->SetError(error); + return false; + } + } + + if (outputFormat == NumericFormat::UNINITIALIZED) { + outputFormat = NumericFormat::DECIMAL; + } + cmExprParserHelper helper; if (!helper.ParseString(expression.c_str(), 0)) { this->SetError(helper.GetError()); @@ -45,7 +88,18 @@ bool cmMathCommand::HandleExprCommand(std::vector const& args) } char buffer[1024]; - sprintf(buffer, "%" KWIML_INT_PRId64, helper.GetResult()); + const char* fmt; + switch (outputFormat) { + case NumericFormat::HEXADECIMAL: + fmt = "0x%" KWIML_INT_PRIx64; + break; + case NumericFormat::DECIMAL: + CM_FALLTHROUGH; + default: + fmt = "%" KWIML_INT_PRId64; + break; + } + sprintf(buffer, fmt, helper.GetResult()); this->Makefile->AddDefinition(outputVariable, buffer); return true; diff --git a/Tests/MathTest/CMakeLists.txt b/Tests/MathTest/CMakeLists.txt index f764b3a..5403d29 100644 --- a/Tests/MathTest/CMakeLists.txt +++ b/Tests/MathTest/CMakeLists.txt @@ -13,14 +13,35 @@ set(expressions "-1 + +1" "+1 - -1" "+1 - - + + -(-3 + - - +1)" + "1000 -12*5" + "1000 +12*-5" + "1000 -12*-5" ) -set(FILE_EXPRESSIONS "") -foreach(expression - ${expressions}) - math(EXPR expr "${expression}") - string(APPEND FILE_EXPRESSIONS "TEST_EXPRESSION(${expression}, ${expr})\n") -endforeach() +set(FILE_EXPRESSIONS "extern void test_expression(int x, int y, const char * text);\n") + + +macro(add_math_test expression) + math(EXPR result ${expression} ${ARGV1} ${ARGV2}) + set(CODE "test_expression(${expression}, ${result}, \"${expression}\");") + string(APPEND FILE_EXPRESSIONS "${CODE}\n") +endmacro() + +macro(add_math_tests) + foreach (expression ${expressions}) + add_math_test(${expression} ${ARGV0} ${ARGV1}) + endforeach () +endmacro() + +add_math_tests() +add_math_tests("OUTPUT_FORMAT" "DECIMAL") +add_math_tests("OUTPUT_FORMAT" "HEXADECIMAL") + +# Avoid the test with negative result and hexadecimal formatting +# therefore more tests with a negative result +add_math_test("-12*5") +add_math_test("12*-5") + configure_file( "${CMAKE_CURRENT_SOURCE_DIR}/MathTestTests.h.in" diff --git a/Tests/MathTest/MathTestExec.cxx b/Tests/MathTest/MathTestExec.cxx index 124eba4..fbcddc4 100644 --- a/Tests/MathTest/MathTestExec.cxx +++ b/Tests/MathTest/MathTestExec.cxx @@ -1,21 +1,43 @@ #include +#include +#include -#define TEST_EXPRESSION(x, y) \ - if ((x) != (y)) { \ - printf("Problem with EXPR: Expression: \"%s\" in C returns %d while in " \ - "CMake returns: %d\n", \ - #x, (x), (y)); \ - res++; \ +int res = 0; +bool print = false; + +void test_expression(int x, int y, const char* text) +{ + bool fail = (x) != (y); + if (fail) { + res++; + printf("Problem with EXPR:"); + } + if (fail || print) { + printf("Expression: \"%s\" in CMake returns %d", text, (y)); + if (fail) { + printf(" while in C returns: %d", (x)); + } + printf("\n"); } +} int main(int argc, char* argv[]) { - if (argc > 1) { - printf("Usage: %s\n", argv[0]); + if (argc > 2) { + printf("Usage: %s [print]\n", argv[0]); return 1; } - int res = 0; + + if (argc > 1) { + if (strcmp(argv[1], "print") != 0) { + printf("Usage: %s [print]\n", argv[0]); + return 1; + } + print = true; + } + #include "MathTestTests.h" + if (res != 0) { printf("%s: %d math tests failed\n", argv[0], res); return 1; diff --git a/Tests/RunCMake/math/MATH-DoubleOption-result.txt b/Tests/RunCMake/math/MATH-DoubleOption-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/math/MATH-DoubleOption-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/math/MATH-DoubleOption-stderr.txt b/Tests/RunCMake/math/MATH-DoubleOption-stderr.txt new file mode 100644 index 0000000..767a060 --- /dev/null +++ b/Tests/RunCMake/math/MATH-DoubleOption-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at MATH-DoubleOption.cmake:1 \(math\): + math EXPR called with incorrect arguments. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/math/MATH-DoubleOption.cmake b/Tests/RunCMake/math/MATH-DoubleOption.cmake new file mode 100644 index 0000000..7bcb78e --- /dev/null +++ b/Tests/RunCMake/math/MATH-DoubleOption.cmake @@ -0,0 +1 @@ +math(EXPR var "10*10" OUTPUT_FORMAT DECIMAL OUTPUT_FORMAT HEXADECIMAL) diff --git a/Tests/RunCMake/math/MATH-TooManyArguments-result.txt b/Tests/RunCMake/math/MATH-TooManyArguments-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/math/MATH-TooManyArguments-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/math/MATH-TooManyArguments-stderr.txt b/Tests/RunCMake/math/MATH-TooManyArguments-stderr.txt new file mode 100644 index 0000000..fdcfecf --- /dev/null +++ b/Tests/RunCMake/math/MATH-TooManyArguments-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at MATH-TooManyArguments.cmake:1 \(math\): + math EXPR called with incorrect arguments. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/math/MATH-TooManyArguments.cmake b/Tests/RunCMake/math/MATH-TooManyArguments.cmake new file mode 100644 index 0000000..969dc80 --- /dev/null +++ b/Tests/RunCMake/math/MATH-TooManyArguments.cmake @@ -0,0 +1 @@ +math(EXPR var "10*10" OUTPUT_FORMAT DECIMAL OUTPUT_FORMAT ) diff --git a/Tests/RunCMake/math/MATH-WrongArgument-result.txt b/Tests/RunCMake/math/MATH-WrongArgument-result.txt new file mode 100644 index 0000000..d00491f --- /dev/null +++ b/Tests/RunCMake/math/MATH-WrongArgument-result.txt @@ -0,0 +1 @@ +1 diff --git a/Tests/RunCMake/math/MATH-WrongArgument-stderr.txt b/Tests/RunCMake/math/MATH-WrongArgument-stderr.txt new file mode 100644 index 0000000..bbe54bf --- /dev/null +++ b/Tests/RunCMake/math/MATH-WrongArgument-stderr.txt @@ -0,0 +1,4 @@ +^CMake Error at MATH-WrongArgument.cmake:1 \(math\): + math sub-command EXPR option "OUT" is unknown. +Call Stack \(most recent call first\): + CMakeLists.txt:3 \(include\)$ diff --git a/Tests/RunCMake/math/MATH-WrongArgument.cmake b/Tests/RunCMake/math/MATH-WrongArgument.cmake new file mode 100644 index 0000000..fb6d2e7 --- /dev/null +++ b/Tests/RunCMake/math/MATH-WrongArgument.cmake @@ -0,0 +1 @@ +math(EXPR var "10*10" OUT HEX ) diff --git a/Tests/RunCMake/math/MATH.cmake b/Tests/RunCMake/math/MATH.cmake index 4ec7f9c..a5f50cd 100644 --- a/Tests/RunCMake/math/MATH.cmake +++ b/Tests/RunCMake/math/MATH.cmake @@ -7,3 +7,6 @@ endmacro() math_test("100 * 10" 1000) +math_test("100 * 10" 1000 OUTPUT_FORMAT DECIMAL) +math_test("100 * 0xA" 1000 OUTPUT_FORMAT DECIMAL) +math_test("100 * 0xA" 0x3e8 OUTPUT_FORMAT HEXADECIMAL) diff --git a/Tests/RunCMake/math/RunCMakeTest.cmake b/Tests/RunCMake/math/RunCMakeTest.cmake index 4c4b725..494b813 100644 --- a/Tests/RunCMake/math/RunCMakeTest.cmake +++ b/Tests/RunCMake/math/RunCMakeTest.cmake @@ -1,5 +1,8 @@ include(RunCMake) run_cmake(MATH) +run_cmake(MATH-WrongArgument) +run_cmake(MATH-DoubleOption) +run_cmake(MATH-TooManyArguments) run_cmake(MATH-InvalidExpression) run_cmake(MATH-DivideByZero) -- cgit v0.12