Commit 5dbee9d2 by Daniel Franke Committed by Brad King

parent 8661e705
 ... ... @@ -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"
 math-hex -------- * The :command:`math` command gained options for hexadecimal.
 ... ... @@ -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; ... ...
 ... ... @@ -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; } ... ...
 ... ... @@ -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; ... ...
 ... ... @@ -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" ... ...
 #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; ... ...
 1
 ^CMake Error at MATH-DoubleOption.cmake:1 \(math\): math EXPR called with incorrect arguments. Call Stack \(most recent call first\): CMakeLists.txt:3 \(include\)\$
 math(EXPR var "10*10" OUTPUT_FORMAT DECIMAL OUTPUT_FORMAT HEXADECIMAL)
 1
 ^CMake Error at MATH-TooManyArguments.cmake:1 \(math\): math EXPR called with incorrect arguments. Call Stack \(most recent call first\): CMakeLists.txt:3 \(include\)\$
 math(EXPR var "10*10" OUTPUT_FORMAT DECIMAL OUTPUT_FORMAT )
 1
 ^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\)\$
 math(EXPR var "10*10" OUT HEX )
 ... ... @@ -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)
 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)
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!