diff --git a/modcc/lexer.cpp b/modcc/lexer.cpp index 2528f19297c38be9330e5c2b4cbed7d04a6ffe05..b15513a93690006e4696839fd9e158fa356c6419 100644 --- a/modcc/lexer.cpp +++ b/modcc/lexer.cpp @@ -28,6 +28,9 @@ inline bool is_eof(char c) { inline bool is_operator(char c) { return (c=='+' || c=='-' || c=='*' || c=='/' || c=='^' || c=='\''); } +inline bool is_plusminus(char c) { + return (c=='+' || c=='-'); +} //********************* // Lexer @@ -258,13 +261,21 @@ Token Lexer::number() { incorrectly_formed_mantisa = true; } } - else if(c=='e' || c=='E') { - uses_scientific_notation++; - str += c; - current_++; - // Consume the next char if +/- - if (*current_ == '+' || *current_ == '-') { - str += *current_++; + else if(!uses_scientific_notation && (c=='e' || c=='E')) { + if(is_numeric(current_[1]) || + is_plusminus(current_[1]) && is_numeric(current_[2])) + { + uses_scientific_notation++; + str += c; + current_++; + // Consume the next char if +/- + if (is_plusminus(*current_)) { + str += *current_++; + } + } + else { + // the 'e' or 'E' is the beginning of a new token + break; } } else { @@ -283,11 +294,6 @@ Token Lexer::number() { error_string_ = pprintf("too many .'s when reading the number '%'", yellow(str)); status_ = lexerStatus::error; } - // check that e or E is not used more than once in the number - if(uses_scientific_notation>1) { - error_string_ = pprintf("can't parse the number '%'", yellow(str)); - status_ = lexerStatus::error; - } tok type; if(status_==lexerStatus::error) { diff --git a/tests/modcc/test_lexer.cpp b/tests/modcc/test_lexer.cpp index 2b49e3b120049bdd542d20a246b5095cbc66fbde..e148b12b0631e1622bd52c2a4771f9b96802b23b 100644 --- a/tests/modcc/test_lexer.cpp +++ b/tests/modcc/test_lexer.cpp @@ -1,4 +1,6 @@ +#include <cctype> #include <cmath> +#include <cstdio> #include <iterator> #include <utility> @@ -31,6 +33,22 @@ public: } return tok; } + + char character() { + char c = Lexer::character(); + if (g_verbose_flag) { + std::cout << "character: "; + if (!std::isprint(c)) { + char buf[5] = "XXXX"; + snprintf(buf, sizeof buf, "0x%02x", (unsigned)c); + std::cout << buf << '\n'; + } + else { + std::cout << c << '\n'; + } + } + return c; + } }; /************************************************************** @@ -307,4 +325,29 @@ TEST(Lexer, numbers) { EXPECT_EQ(floats.cend(), iter); EXPECT_EQ(tok::eof, t.type); EXPECT_EQ(check_ints, ints); + + // check case where 'E' is not followed by +, -, or a digit explicitly + lexer = VerboseLexer("7.2E"); + t = lexer.parse(); + EXPECT_EQ(lexerStatus::happy, lexer.status()); + EXPECT_EQ(tok::real, t.type); + EXPECT_EQ(t.spelling, "7.2"); + EXPECT_EQ(lexer.character(), 'E'); + + lexer = VerboseLexer("3E+E2"); + t = lexer.parse(); + EXPECT_EQ(lexerStatus::happy, lexer.status()); + EXPECT_EQ(tok::integer, t.type); + EXPECT_EQ(t.spelling, "3"); + EXPECT_EQ(lexer.character(), 'E'); + EXPECT_EQ(lexer.character(), '+'); + + // 'bad' numbers should give errors + lexer = VerboseLexer("1.2.3"); + lexer.parse(); + EXPECT_EQ(lexerStatus::error, lexer.status()); + + lexer = VerboseLexer("1.2E4.3"); + lexer.parse(); + EXPECT_EQ(lexerStatus::error, lexer.status()); } diff --git a/tests/modcc/test_parser.cpp b/tests/modcc/test_parser.cpp index 2f1bb0d76b182916876eed028160684f217b4062..ab25d942dd5c6165b61bfd4940454ac840b9f993 100644 --- a/tests/modcc/test_parser.cpp +++ b/tests/modcc/test_parser.cpp @@ -282,7 +282,7 @@ TEST(Parser, parse_parenthesis_expression) { // test parsing of line expressions TEST(Parser, parse_line_expression) { const char* good_expr[] = { - "qt=q10^((celsius-22)/10)" + "qt=q10^((celsius-22)/10)", "x=2 ", "x=2 ", "x = -y\n " @@ -319,7 +319,7 @@ TEST(Parser, parse_line_expression) { TEST(Parser, parse_stoich_term) { const char* good_pos_expr[] = { - "B", "B3", "3B3", "0A", "12A" + "B", "B3", "3B3", "0A", "12A", "4E" }; for (auto& text: good_pos_expr) { @@ -338,7 +338,7 @@ TEST(Parser, parse_stoich_term) { EXPECT_TRUE((s && s->negative())); } const char* bad_expr[] = { - "0.2A", "5" + "0.2A", "5", "3e2" // "3e2" should lex as real number 300.0 }; for (auto& text: bad_expr) { @@ -403,6 +403,7 @@ TEST(Parser, parse_reaction_expression) { "~ A + B <-> C + D (k1, k2)", "~ 2B <-> C + D + E (k1(3,v), k2)", "~ <-> C + D + 7 E (k1, f(a,b)-2)", + "~ <-> C + D + 7E+F (k1, f(a,b)-2)", "~ <-> (f,g)", "~ A + 3B + C<-> (f,g)" }; @@ -417,6 +418,7 @@ TEST(Parser, parse_reaction_expression) { "~ A + B <-> C + (k1, k2)", "~ 2.3B <-> C + D + E (k1(3,v), k2)", "~ <-> C + D + 7E", + "~ <-> C + D + 7E+2F (k1, f(a,b)-2)", // "7E+2" will lex as real number "~ <-> (,g)", "~ A - 3B + C<-> (f,g)", " A <-> B (k1, k2)",