diff --git a/src/parser/GraphScanner.h b/src/parser/GraphScanner.h
index 6323b662bad81c62e4fd42c160e8863a73111f70..429c46f5f3e358ce1187a8fb1a35528ae41a8c74 100644
--- a/src/parser/GraphScanner.h
+++ b/src/parser/GraphScanner.h
@@ -88,6 +88,79 @@ protected:
         return sbuf_.get();
     }
 
+    using TokenType = nebula::GraphParser::token;
+    auto parseDecimal() const {
+        try {
+            folly::StringPiece text(yytext, yyleng);
+            uint64_t val = folly::to<uint64_t>(text);
+            if (val > MAX_ABS_INTEGER) {
+                throw GraphParser::syntax_error(*yylloc, "Out of range:");
+            }
+            if (val == MAX_ABS_INTEGER && !hasUnaryMinus()) {
+                throw GraphParser::syntax_error(*yylloc, "Out of range:");
+            }
+            yylval->intval = val;
+        } catch (...) {
+            throw GraphParser::syntax_error(*yylloc, "Out of range:");
+        }
+        return TokenType::INTEGER;
+    }
+
+    auto parseDouble() const {
+        try {
+            folly::StringPiece text(yytext, yyleng);
+            yylval->doubleval = folly::to<double>(text);
+        } catch (...) {
+            throw GraphParser::syntax_error(*yylloc, "Out of range:");
+        }
+        return TokenType::DOUBLE;
+    }
+
+    auto parseHex() const {
+        if (yyleng > 18) {
+            auto i = 2;
+            while (i < yyleng && yytext[i] == '0') {
+                i++;
+            }
+            if (yyleng - i > 16) {
+                throw GraphParser::syntax_error(*yylloc, "Out of range:");
+            }
+        }
+        uint64_t val = 0;
+        sscanf(yytext, "%lx", &val);
+        if (val > MAX_ABS_INTEGER) {
+            throw GraphParser::syntax_error(*yylloc, "Out of range:");
+        }
+        if (val == MAX_ABS_INTEGER && !hasUnaryMinus()) {
+            throw GraphParser::syntax_error(*yylloc, "Out of range:");
+        }
+        yylval->intval = static_cast<int64_t>(val);
+        return TokenType::INTEGER;
+    }
+
+    auto parseOct() const {
+        if (yyleng > 22) {
+            auto i = 1;
+            while (i < yyleng && yytext[i] == '0') {
+                i++;
+            }
+            if (yyleng - i > 22 ||
+                    (yyleng - i == 22 && yytext[i] != '1')) {
+                throw GraphParser::syntax_error(*yylloc, "Out of range:");
+            }
+        }
+        uint64_t val = 0;
+        sscanf(yytext, "%lo", &val);
+        if (val > MAX_ABS_INTEGER) {
+            throw GraphParser::syntax_error(*yylloc, "Out of range:");
+        }
+        if (val == MAX_ABS_INTEGER && !hasUnaryMinus()) {
+            throw GraphParser::syntax_error(*yylloc, "Out of range:");
+        }
+        yylval->intval = static_cast<int64_t>(val);
+        return TokenType::INTEGER;
+    }
+
 private:
     friend class Scanner_Basic_Test;
     int yylex() override;
diff --git a/src/parser/parser.yy b/src/parser/parser.yy
index af4dc6421e6647f3184102e239e0701d60f57447..accf788bfd29bb63e409ac0e574050bac1da54d1 100644
--- a/src/parser/parser.yy
+++ b/src/parser/parser.yy
@@ -158,7 +158,7 @@ static constexpr size_t MAX_ABS_INTEGER = 9223372036854775808ULL;
 /* symbols */
 %token L_PAREN R_PAREN L_BRACKET R_BRACKET L_BRACE R_BRACE COMMA
 %token PIPE ASSIGN
-%token DOT COLON SEMICOLON L_ARROW R_ARROW AT
+%token DOT DOT_DOT COLON SEMICOLON L_ARROW R_ARROW AT
 %token ID_PROP TYPE_PROP SRC_ID_PROP DST_ID_PROP RANK_PROP INPUT_REF DST_REF SRC_REF
 
 /* token type specification */
@@ -1145,14 +1145,14 @@ match_step_range
     | STAR legal_integer {
         $$ = new MatchStepRange($2, $2);
     }
-    | STAR DOT DOT legal_integer {
-        $$ = new MatchStepRange(1, $4);
+    | STAR DOT_DOT legal_integer {
+        $$ = new MatchStepRange(1, $3);
     }
-    | STAR legal_integer DOT DOT {
+    | STAR legal_integer DOT_DOT {
         $$ = new MatchStepRange($2);
     }
-    | STAR legal_integer DOT DOT legal_integer {
-        $$ = new MatchStepRange($2, $5);
+    | STAR legal_integer DOT_DOT legal_integer {
+        $$ = new MatchStepRange($2, $4);
     }
     ;
 
diff --git a/src/parser/scanner.lex b/src/parser/scanner.lex
index db5a55125cfd4364f7c1142696cee6145415cba9..e7eb4321e4f5b5b1781ce8ea33058b8b9afdae71 100644
--- a/src/parser/scanner.lex
+++ b/src/parser/scanner.lex
@@ -13,8 +13,6 @@
     yylloc->step();                     \
     yylloc->columns(yyleng);
 
-using TokenType = nebula::GraphParser::token;
-
 static constexpr size_t MAX_STRING = 4096;
 
 %}
@@ -364,6 +362,7 @@ FORMAT                      ([Ff][Oo][Rr][Mm][Aa][Tt])
 {FALSE}                     { yylval->boolval = false; return TokenType::BOOL; }
 
 "."                         { return TokenType::DOT; }
+".."                        { return TokenType::DOT_DOT; }
 ","                         { return TokenType::COMMA; }
 ":"                         { return TokenType::COLON; }
 ";"                         { return TokenType::SEMICOLON; }
@@ -433,75 +432,29 @@ FORMAT                      ([Ff][Oo][Rr][Mm][Aa][Tt])
                                 return TokenType::IPV4;
                             }
 0[Xx]{HEX}+                 {
-                                if (yyleng > 18) {
-                                    auto i = 2;
-                                    while (i < yyleng && yytext[i] == '0') {
-                                        i++;
-                                    }
-                                    if (yyleng - i > 16) {
-                                        throw GraphParser::syntax_error(*yylloc, "Out of range:");
-                                    }
-                                }
-                                uint64_t val = 0;
-                                sscanf(yytext, "%lx", &val);
-                                if (val > MAX_ABS_INTEGER) {
-                                    throw GraphParser::syntax_error(*yylloc, "Out of range:");
-                                }
-                                if (val == MAX_ABS_INTEGER && !hasUnaryMinus()) {
-                                    throw GraphParser::syntax_error(*yylloc, "Out of range:");
-                                }
-                                yylval->intval = static_cast<int64_t>(val);
-                                return TokenType::INTEGER;
+                                return parseHex();
                             }
 0{OCT}+                     {
-                                if (yyleng > 22) {
-                                    auto i = 1;
-                                    while (i < yyleng && yytext[i] == '0') {
-                                        i++;
-                                    }
-                                    if (yyleng - i > 22 ||
-                                            (yyleng - i == 22 && yytext[i] != '1')) {
-                                        throw GraphParser::syntax_error(*yylloc, "Out of range:");
-                                    }
-                                }
-                                uint64_t val = 0;
-                                sscanf(yytext, "%lo", &val);
-                                if (val > MAX_ABS_INTEGER) {
-                                    throw GraphParser::syntax_error(*yylloc, "Out of range:");
-                                }
-                                if (val == MAX_ABS_INTEGER && !hasUnaryMinus()) {
-                                    throw GraphParser::syntax_error(*yylloc, "Out of range:");
-                                }
-                                yylval->intval = static_cast<int64_t>(val);
-                                return TokenType::INTEGER;
+                                return parseOct();
+                            }
+
+{DEC}+\.\.                  {
+                                yyless(yyleng - 2);
+                                return parseDecimal();
                             }
 {DEC}+                      {
-                                try {
-                                    folly::StringPiece text(yytext, yyleng);
-                                    uint64_t val = folly::to<uint64_t>(text);
-                                    if (val > MAX_ABS_INTEGER) {
-                                        throw GraphParser::syntax_error(*yylloc, "Out of range:");
-                                    }
-                                    if (val == MAX_ABS_INTEGER && !hasUnaryMinus()) {
-                                        throw GraphParser::syntax_error(*yylloc, "Out of range:");
-                                    }
-                                    yylval->intval = val;
-                                } catch (...) {
-                                    throw GraphParser::syntax_error(*yylloc, "Out of range:");
-                                }
-                                return TokenType::INTEGER;
+                                return parseDecimal();
                             }
-{DEC}+\.{DEC}+              {
-                                try {
-                                    folly::StringPiece text(yytext, yyleng);
-                                    yylval->doubleval = folly::to<double>(text);
-                                } catch (...) {
-                                    throw GraphParser::syntax_error(*yylloc, "Out of range:");
-                                }
-                                return TokenType::DOUBLE;
+
+{DEC}*\.{DEC}+              |
+{DEC}+\.{DEC}*              {
+                                return parseDouble();
                             }
 
-\${LABEL}                   { yylval->strval = new std::string(yytext + 1, yyleng - 1); return TokenType::VARIABLE; }
+\${LABEL}                   {
+                                yylval->strval = new std::string(yytext + 1, yyleng - 1);
+                                return TokenType::VARIABLE;
+                            }
 
 
 \"                          { BEGIN(DQ_STR); sbufPos_ = 0; }
diff --git a/src/parser/test/ScannerTest.cpp b/src/parser/test/ScannerTest.cpp
index fb664ee8b41b560197ac35300ec3f54e99569c58..59e0cd4a73a6236c87dea488c1bdc721ebbdc03a 100644
--- a/src/parser/test/ScannerTest.cpp
+++ b/src/parser/test/ScannerTest.cpp
@@ -134,6 +134,7 @@ TEST(Scanner, Basic) {
 
     std::vector<Validator> validators = {
         CHECK_SEMANTIC_TYPE(".", TokenType::DOT),
+        CHECK_SEMANTIC_TYPE("..", TokenType::DOT_DOT),
         CHECK_SEMANTIC_TYPE(",", TokenType::COMMA),
         CHECK_SEMANTIC_TYPE(":", TokenType::COLON),
         CHECK_SEMANTIC_TYPE(";", TokenType::SEMICOLON),
@@ -468,6 +469,8 @@ TEST(Scanner, Basic) {
         CHECK_SEMANTIC_VALUE("0x123", TokenType::INTEGER, 0x123),
         CHECK_SEMANTIC_VALUE("0xdeadbeef", TokenType::INTEGER, 0xdeadbeef),
         CHECK_SEMANTIC_VALUE("0123", TokenType::INTEGER, 0123),
+        CHECK_SEMANTIC_VALUE("123.", TokenType::DOUBLE, 123.),
+        CHECK_SEMANTIC_VALUE(".123", TokenType::DOUBLE, 0.123),
         CHECK_SEMANTIC_VALUE("123.456", TokenType::DOUBLE, 123.456),
 
         CHECK_SEMANTIC_VALUE("0x7FFFFFFFFFFFFFFF", TokenType::INTEGER, 0x7FFFFFFFFFFFFFFFL),
diff --git a/src/validator/test/YieldValidatorTest.cpp b/src/validator/test/YieldValidatorTest.cpp
index 405fd9ae3a171e05ff2c31a0504f98b2a41fb1b3..88087a25d08320870b0050141ab3d6566d8b2f92 100644
--- a/src/validator/test/YieldValidatorTest.cpp
+++ b/src/validator/test/YieldValidatorTest.cpp
@@ -135,6 +135,10 @@ TEST_F(YieldValidatorTest, TypeCastTest) {
         std::string query = "YIELD (INT)1.23";
         EXPECT_TRUE(checkResult(query, expected_));
     }
+    {
+        std::string query = "YIELD (INT).123";
+        EXPECT_TRUE(checkResult(query, expected_));
+    }
     {
         std::string query = "YIELD (INT)123";
         EXPECT_TRUE(checkResult(query, expected_));