[Cmake-commits] CMake branch, master, updated. v3.12.0-rc2-142-gca733cd

Kitware Robot kwrobot at kitware.com
Thu Jul 5 10:35:04 EDT 2018


This is an automated email from the git hooks/post-receive script. It was
generated because a ref change was pushed to the repository containing
the project "CMake".

The branch, master has been updated
       via  ca733cdf4532a4a3d05b82c49a5f2fbf994149de (commit)
       via  5dbee9d2d0f68e1fc343d04ac00a4a35d43df6fa (commit)
       via  8661e7052c4f711f13e7168231276e23c4c0defd (commit)
       via  7c4c13ffef87d748b896e2c762ad0b2c00afcd31 (commit)
       via  5b0f73a15a7b49461123a969bbebceff4284df9c (commit)
       via  963b8d9f6c1c4bcce2a82ade137a82b17ef75780 (commit)
      from  5fec622ece869b30560b797e469c93c57d7016b6 (commit)

Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.

- Log -----------------------------------------------------------------
https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=ca733cdf4532a4a3d05b82c49a5f2fbf994149de
commit ca733cdf4532a4a3d05b82c49a5f2fbf994149de
Merge: 5fec622 5dbee9d
Author:     Brad King <brad.king at kitware.com>
AuthorDate: Thu Jul 5 14:25:56 2018 +0000
Commit:     Kitware Robot <kwrobot at kitware.com>
CommitDate: Thu Jul 5 10:26:05 2018 -0400

    Merge topic 'math-hex'
    
    5dbee9d2d0 math: Add options to calculate and format output as hexadecimal
    8661e7052c math: Diagnose divide-by-zero
    7c4c13ffef math: Reject unexpected expression input explicitly
    5b0f73a15a math: Use 64-bit integer type for computation
    963b8d9f6c math: Add RunCMake.math test to prepare for error cases
    
    Acked-by: Kitware Robot <kwrobot at kitware.com>
    Merge-request: !2056


https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=5dbee9d2d0f68e1fc343d04ac00a4a35d43df6fa
commit 5dbee9d2d0f68e1fc343d04ac00a4a35d43df6fa
Author:     Daniel Franke <franke at edf-online.de>
AuthorDate: Fri May 18 21:59:46 2018 +0200
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Tue Jul 3 09:55:58 2018 -0400

    math: Add options to calculate and format output as hexadecimal

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 <output-variable> <math-expression>)
+  math(EXPR <output-variable> <math-expression> [OUTPUT_FORMAT <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 ``<format>`` 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<std::string> const& args,
 
 bool cmMathCommand::HandleExprCommand(std::vector<std::string> 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<std::string> 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 <stdio.h>
+#include <stdlib.h>
+#include <string.h>
 
-#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)

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=8661e7052c4f711f13e7168231276e23c4c0defd
commit 8661e7052c4f711f13e7168231276e23c4c0defd
Author:     Daniel Franke <franke at edf-online.de>
AuthorDate: Fri May 18 21:59:46 2018 +0200
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Tue Jun 26 14:21:18 2018 -0400

    math: Diagnose divide-by-zero

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 <stdlib.h>
 #include <string.h>
+#include <stdexcept>
 
 /*-------------------------------------------------------------------------*/
 #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 <stdlib.h>
 #include <string.h>
+#include <stdexcept>
 
 /*-------------------------------------------------------------------------*/
 #define YYDEBUG 1
@@ -129,6 +130,9 @@ term:
     $<Number>$ = $<Number>1 * $<Number>3;
   }
 | term exp_DIVIDE unary {
+    if (yyvsp[0].Number == 0) {
+      throw std::overflow_error("divide by zero");
+    }
     $<Number>$ = $<Number>1 / $<Number>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)

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=7c4c13ffef87d748b896e2c762ad0b2c00afcd31
commit 7c4c13ffef87d748b896e2c762ad0b2c00afcd31
Author:     Daniel Franke <franke at edf-online.de>
AuthorDate: Fri May 18 21:59:46 2018 +0200
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Tue Jun 26 14:15:21 2018 -0400

    math: Reject unexpected expression input explicitly
    
    Switch to C++ exceptions for lexer/parser error handling.
    Teach the lexer/parser to fail on unexpected input.

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 <string>
+
 /*--------------------------------------------------------------------------*/
 
 #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 <string>
+
 /*--------------------------------------------------------------------------*/
 %}
 
@@ -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 <iostream>
 #include <sstream>
+#include <stdexcept>
+#include <utility>
 
 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<std::string> 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)

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=5b0f73a15a7b49461123a969bbebceff4284df9c
commit 5b0f73a15a7b49461123a969bbebceff4284df9c
Author:     Daniel Franke <franke at edf-online.de>
AuthorDate: Fri May 18 21:59:46 2018 +0200
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Fri Jun 22 09:00:34 2018 -0400

    math: Use 64-bit integer type for computation

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 <string>
 #include <vector>
 
@@ -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 <stdio.h>
-
 #include "cmExprParserHelper.h"
 #include "cmMakefile.h"
+#include "cm_kwiml.h"
+
+#include <stdio.h>
 
 class cmExecutionStatus;
 
@@ -44,7 +45,7 @@ bool cmMathCommand::HandleExprCommand(std::vector<std::string> const& args)
   }
 
   char buffer[1024];
-  sprintf(buffer, "%d", helper.GetResult());
+  sprintf(buffer, "%" KWIML_INT_PRId64, helper.GetResult());
 
   this->Makefile->AddDefinition(outputVariable, buffer);
   return true;

https://cmake.org/gitweb?p=cmake.git;a=commitdiff;h=963b8d9f6c1c4bcce2a82ade137a82b17ef75780
commit 963b8d9f6c1c4bcce2a82ade137a82b17ef75780
Author:     Daniel Franke <franke at edf-online.de>
AuthorDate: Fri May 18 21:59:46 2018 +0200
Commit:     Brad King <brad.king at kitware.com>
CommitDate: Fri Jun 22 09:00:34 2018 -0400

    math: Add RunCMake.math test to prepare for error cases

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)

-----------------------------------------------------------------------

Summary of changes:
 Help/command/math.rst                              |  18 ++-
 Help/release/dev/math-hex.rst                      |   4 +
 Source/LexerParser/cmExprLexer.cxx                 | 126 +++++++++++--------
 Source/LexerParser/cmExprLexer.in.l                |   7 +-
 Source/LexerParser/cmExprParser.cxx                | 137 +++++++++++----------
 Source/LexerParser/cmExprParser.y                  |   5 +
 Source/LexerParser/cmExprParserTokens.h            |   4 +-
 Source/cmExprParserHelper.cxx                      |  38 +++++-
 Source/cmExprParserHelper.h                        |  11 +-
 Source/cmMathCommand.cxx                           |  69 +++++++++--
 Tests/MathTest/CMakeLists.txt                      |  33 ++++-
 Tests/MathTest/MathTestExec.cxx                    |  40 ++++--
 Tests/RunCMake/CMakeLists.txt                      |   1 +
 Tests/RunCMake/{while => math}/CMakeLists.txt      |   0
 .../MATH-DivideByZero-result.txt}                  |   0
 Tests/RunCMake/math/MATH-DivideByZero-stderr.txt   |   4 +
 Tests/RunCMake/math/MATH-DivideByZero.cmake        |   1 +
 .../MATH-DoubleOption-result.txt}                  |   0
 Tests/RunCMake/math/MATH-DoubleOption-stderr.txt   |   4 +
 Tests/RunCMake/math/MATH-DoubleOption.cmake        |   1 +
 .../MATH-InvalidExpression-result.txt}             |   0
 .../math/MATH-InvalidExpression-stderr.txt         |   6 +
 Tests/RunCMake/math/MATH-InvalidExpression.cmake   |   1 +
 .../MATH-TooManyArguments-result.txt}              |   0
 .../RunCMake/math/MATH-TooManyArguments-stderr.txt |   4 +
 Tests/RunCMake/math/MATH-TooManyArguments.cmake    |   1 +
 .../MATH-WrongArgument-result.txt}                 |   0
 Tests/RunCMake/math/MATH-WrongArgument-stderr.txt  |   4 +
 Tests/RunCMake/math/MATH-WrongArgument.cmake       |   1 +
 Tests/RunCMake/math/MATH.cmake                     |  12 ++
 Tests/RunCMake/math/RunCMakeTest.cmake             |   8 ++
 31 files changed, 391 insertions(+), 149 deletions(-)
 create mode 100644 Help/release/dev/math-hex.rst
 copy Tests/RunCMake/{while => math}/CMakeLists.txt (100%)
 copy Tests/RunCMake/{while/MissingArgument-result.txt => math/MATH-DivideByZero-result.txt} (100%)
 create mode 100644 Tests/RunCMake/math/MATH-DivideByZero-stderr.txt
 create mode 100644 Tests/RunCMake/math/MATH-DivideByZero.cmake
 copy Tests/RunCMake/{while/MissingArgument-result.txt => math/MATH-DoubleOption-result.txt} (100%)
 create mode 100644 Tests/RunCMake/math/MATH-DoubleOption-stderr.txt
 create mode 100644 Tests/RunCMake/math/MATH-DoubleOption.cmake
 copy Tests/RunCMake/{while/MissingArgument-result.txt => math/MATH-InvalidExpression-result.txt} (100%)
 create mode 100644 Tests/RunCMake/math/MATH-InvalidExpression-stderr.txt
 create mode 100644 Tests/RunCMake/math/MATH-InvalidExpression.cmake
 copy Tests/RunCMake/{while/MissingArgument-result.txt => math/MATH-TooManyArguments-result.txt} (100%)
 create mode 100644 Tests/RunCMake/math/MATH-TooManyArguments-stderr.txt
 create mode 100644 Tests/RunCMake/math/MATH-TooManyArguments.cmake
 copy Tests/RunCMake/{while/MissingArgument-result.txt => math/MATH-WrongArgument-result.txt} (100%)
 create mode 100644 Tests/RunCMake/math/MATH-WrongArgument-stderr.txt
 create mode 100644 Tests/RunCMake/math/MATH-WrongArgument.cmake
 create mode 100644 Tests/RunCMake/math/MATH.cmake
 create mode 100644 Tests/RunCMake/math/RunCMakeTest.cmake


hooks/post-receive
-- 
CMake


More information about the Cmake-commits mailing list