diff --git a/src/json.hpp b/src/json.hpp
index bd43c83c..dfa7e97b 100644
--- a/src/json.hpp
+++ b/src/json.hpp
@@ -2477,13 +2477,13 @@ class basic_json
                 static const unsigned char yybm[] =
                 {
                     0,  64,  64,  64,  64,  64,  64,  64,
-                    64, 192, 192,  64,  64, 192,  64,  64,
+                    64,  96,  96,  64,  64,  96,  64,  64,
                     64,  64,  64,  64,  64,  64,  64,  64,
                     64,  64,  64,  64,  64,  64,  64,  64,
-                    192,  64,   0,  64,  64,  64,  64,  64,
+                    96,  64,   0,  64,  64,  64,  64,  64,
                     64,  64,  64,  64,  64,  64,  64,  64,
-                    96,  96,  96,  96,  96,  96,  96,  96,
-                    96,  96,  64,  64,  64,  64,  64,  64,
+                    192, 192, 192, 192, 192, 192, 192, 192,
+                    192, 192,  64,  64,  64,  64,  64,  64,
                     64,  64,  64,  64,  64,  64,  64,  64,
                     64,  64,  64,  64,  64,  64,  64,  64,
                     64,  64,  64,  64,  64,  64,  64,  64,
@@ -2519,25 +2519,29 @@ class basic_json
                         {
                             if (yych <= 0x00)
                             {
-                                goto json_parser_3;
+                                goto json_parser_27;
                             }
                             if (yych <= 0x08)
                             {
-                                goto json_parser_5;
+                                goto json_parser_29;
                             }
-                            goto json_parser_7;
+                            if (yych <= '\t')
+                            {
+                                goto json_parser_3;
+                            }
+                            goto json_parser_4;
                         }
                         else
                         {
                             if (yych == '\r')
                             {
-                                goto json_parser_7;
+                                goto json_parser_3;
                             }
                             if (yych <= 0x1F)
                             {
-                                goto json_parser_5;
+                                goto json_parser_29;
                             }
-                            goto json_parser_7;
+                            goto json_parser_3;
                         }
                     }
                     else
@@ -2546,29 +2550,29 @@ class basic_json
                         {
                             if (yych == '"')
                             {
-                                goto json_parser_8;
+                                goto json_parser_26;
                             }
                             if (yych <= '+')
                             {
-                                goto json_parser_5;
+                                goto json_parser_29;
                             }
-                            goto json_parser_9;
+                            goto json_parser_14;
                         }
                         else
                         {
                             if (yych <= '-')
                             {
-                                goto json_parser_11;
+                                goto json_parser_22;
                             }
                             if (yych <= '/')
                             {
-                                goto json_parser_5;
+                                goto json_parser_29;
                             }
                             if (yych <= '0')
                             {
-                                goto json_parser_12;
+                                goto json_parser_23;
                             }
-                            goto json_parser_14;
+                            goto json_parser_25;
                         }
                     }
                 }
@@ -2580,25 +2584,25 @@ class basic_json
                         {
                             if (yych <= ':')
                             {
-                                goto json_parser_15;
+                                goto json_parser_16;
                             }
                             if (yych == '[')
                             {
-                                goto json_parser_17;
+                                goto json_parser_6;
                             }
-                            goto json_parser_5;
+                            goto json_parser_29;
                         }
                         else
                         {
                             if (yych <= ']')
                             {
-                                goto json_parser_19;
+                                goto json_parser_8;
                             }
                             if (yych == 'f')
                             {
                                 goto json_parser_21;
                             }
-                            goto json_parser_5;
+                            goto json_parser_29;
                         }
                     }
                     else
@@ -2607,25 +2611,25 @@ class basic_json
                         {
                             if (yych <= 'n')
                             {
-                                goto json_parser_22;
+                                goto json_parser_18;
                             }
                             if (yych == 't')
                             {
-                                goto json_parser_23;
+                                goto json_parser_20;
                             }
-                            goto json_parser_5;
+                            goto json_parser_29;
                         }
                         else
                         {
                             if (yych <= '{')
                             {
-                                goto json_parser_24;
+                                goto json_parser_10;
                             }
                             if (yych == '}')
                             {
-                                goto json_parser_26;
+                                goto json_parser_12;
                             }
-                            goto json_parser_5;
+                            goto json_parser_29;
                         }
                     }
                 }
@@ -2634,339 +2638,162 @@ json_parser_2:
                     return scan();
                 }
 json_parser_3:
+                yych = *++m_cursor;
+                goto json_parser_5;
+json_parser_4:
                 ++m_cursor;
-                {
-                    return token_type::end_of_input;
-                }
+                yych = *m_cursor;
 json_parser_5:
-                ++m_cursor;
+                if (yybm[0 + yych] & 32)
+                {
+                    goto json_parser_4;
+                }
+                goto json_parser_2;
 json_parser_6:
-                {
-                    return token_type::parse_error;
-                }
-json_parser_7:
-                yych = *++m_cursor;
-                goto json_parser_62;
-json_parser_8:
-                yyaccept = 0;
-                yych = *(m_marker = ++m_cursor);
-                if (yych <= 0x00)
-                {
-                    goto json_parser_6;
-                }
-                goto json_parser_53;
-json_parser_9:
-                ++m_cursor;
-                {
-                    return token_type::value_separator;
-                }
-json_parser_11:
-                yych = *++m_cursor;
-                if (yych <= '/')
-                {
-                    goto json_parser_6;
-                }
-                if (yych <= '0')
-                {
-                    goto json_parser_51;
-                }
-                if (yych <= '9')
-                {
-                    goto json_parser_42;
-                }
-                goto json_parser_6;
-json_parser_12:
-                yyaccept = 1;
-                yych = *(m_marker = ++m_cursor);
-                if (yych <= 'D')
-                {
-                    if (yych == '.')
-                    {
-                        goto json_parser_44;
-                    }
-                }
-                else
-                {
-                    if (yych <= 'E')
-                    {
-                        goto json_parser_45;
-                    }
-                    if (yych == 'e')
-                    {
-                        goto json_parser_45;
-                    }
-                }
-json_parser_13:
-                {
-                    return token_type::value_number;
-                }
-json_parser_14:
-                yyaccept = 1;
-                yych = *(m_marker = ++m_cursor);
-                goto json_parser_43;
-json_parser_15:
-                ++m_cursor;
-                {
-                    return token_type::name_separator;
-                }
-json_parser_17:
                 ++m_cursor;
                 {
                     return token_type::begin_array;
                 }
-json_parser_19:
+json_parser_8:
                 ++m_cursor;
                 {
                     return token_type::end_array;
                 }
+json_parser_10:
+                ++m_cursor;
+                {
+                    return token_type::begin_object;
+                }
+json_parser_12:
+                ++m_cursor;
+                {
+                    return token_type::end_object;
+                }
+json_parser_14:
+                ++m_cursor;
+                {
+                    return token_type::value_separator;
+                }
+json_parser_16:
+                ++m_cursor;
+                {
+                    return token_type::name_separator;
+                }
+json_parser_18:
+                yyaccept = 0;
+                yych = *(m_marker = ++m_cursor);
+                if (yych == 'u')
+                {
+                    goto json_parser_59;
+                }
+json_parser_19:
+                {
+                    return token_type::parse_error;
+                }
+json_parser_20:
+                yyaccept = 0;
+                yych = *(m_marker = ++m_cursor);
+                if (yych == 'r')
+                {
+                    goto json_parser_55;
+                }
+                goto json_parser_19;
 json_parser_21:
                 yyaccept = 0;
                 yych = *(m_marker = ++m_cursor);
                 if (yych == 'a')
                 {
-                    goto json_parser_37;
+                    goto json_parser_50;
                 }
-                goto json_parser_6;
+                goto json_parser_19;
 json_parser_22:
-                yyaccept = 0;
-                yych = *(m_marker = ++m_cursor);
-                if (yych == 'u')
-                {
-                    goto json_parser_33;
-                }
-                goto json_parser_6;
-json_parser_23:
-                yyaccept = 0;
-                yych = *(m_marker = ++m_cursor);
-                if (yych == 'r')
-                {
-                    goto json_parser_28;
-                }
-                goto json_parser_6;
-json_parser_24:
-                ++m_cursor;
-                {
-                    return token_type::begin_object;
-                }
-json_parser_26:
-                ++m_cursor;
-                {
-                    return token_type::end_object;
-                }
-json_parser_28:
-                yych = *++m_cursor;
-                if (yych == 'u')
-                {
-                    goto json_parser_30;
-                }
-json_parser_29:
-                m_cursor = m_marker;
-                if (yyaccept == 0)
-                {
-                    goto json_parser_6;
-                }
-                else
-                {
-                    goto json_parser_13;
-                }
-json_parser_30:
-                yych = *++m_cursor;
-                if (yych != 'e')
-                {
-                    goto json_parser_29;
-                }
-                ++m_cursor;
-                {
-                    return token_type::literal_true;
-                }
-json_parser_33:
-                yych = *++m_cursor;
-                if (yych != 'l')
-                {
-                    goto json_parser_29;
-                }
-                yych = *++m_cursor;
-                if (yych != 'l')
-                {
-                    goto json_parser_29;
-                }
-                ++m_cursor;
-                {
-                    return token_type::literal_null;
-                }
-json_parser_37:
-                yych = *++m_cursor;
-                if (yych != 'l')
-                {
-                    goto json_parser_29;
-                }
-                yych = *++m_cursor;
-                if (yych != 's')
-                {
-                    goto json_parser_29;
-                }
-                yych = *++m_cursor;
-                if (yych != 'e')
-                {
-                    goto json_parser_29;
-                }
-                ++m_cursor;
-                {
-                    return token_type::literal_false;
-                }
-json_parser_42:
-                yyaccept = 1;
-                m_marker = ++m_cursor;
-                yych = *m_cursor;
-json_parser_43:
-                if (yybm[0 + yych] & 32)
-                {
-                    goto json_parser_42;
-                }
-                if (yych <= 'D')
-                {
-                    if (yych != '.')
-                    {
-                        goto json_parser_13;
-                    }
-                }
-                else
-                {
-                    if (yych <= 'E')
-                    {
-                        goto json_parser_45;
-                    }
-                    if (yych == 'e')
-                    {
-                        goto json_parser_45;
-                    }
-                    goto json_parser_13;
-                }
-json_parser_44:
                 yych = *++m_cursor;
                 if (yych <= '/')
                 {
-                    goto json_parser_29;
+                    goto json_parser_19;
                 }
-                if (yych <= '9')
+                if (yych <= '0')
                 {
                     goto json_parser_49;
                 }
-                goto json_parser_29;
-json_parser_45:
-                yych = *++m_cursor;
-                if (yych <= ',')
-                {
-                    if (yych != '+')
-                    {
-                        goto json_parser_29;
-                    }
-                }
-                else
-                {
-                    if (yych <= '-')
-                    {
-                        goto json_parser_46;
-                    }
-                    if (yych <= '/')
-                    {
-                        goto json_parser_29;
-                    }
-                    if (yych <= '9')
-                    {
-                        goto json_parser_47;
-                    }
-                    goto json_parser_29;
-                }
-json_parser_46:
-                yych = *++m_cursor;
-                if (yych <= '/')
-                {
-                    goto json_parser_29;
-                }
-                if (yych >= ':')
-                {
-                    goto json_parser_29;
-                }
-json_parser_47:
-                ++m_cursor;
-                yych = *m_cursor;
-                if (yych <= '/')
-                {
-                    goto json_parser_13;
-                }
                 if (yych <= '9')
                 {
-                    goto json_parser_47;
+                    goto json_parser_40;
                 }
-                goto json_parser_13;
-json_parser_49:
-                yyaccept = 1;
-                m_marker = ++m_cursor;
-                yych = *m_cursor;
-                if (yych <= 'D')
-                {
-                    if (yych <= '/')
-                    {
-                        goto json_parser_13;
-                    }
-                    if (yych <= '9')
-                    {
-                        goto json_parser_49;
-                    }
-                    goto json_parser_13;
-                }
-                else
-                {
-                    if (yych <= 'E')
-                    {
-                        goto json_parser_45;
-                    }
-                    if (yych == 'e')
-                    {
-                        goto json_parser_45;
-                    }
-                    goto json_parser_13;
-                }
-json_parser_51:
+                goto json_parser_19;
+json_parser_23:
                 yyaccept = 1;
                 yych = *(m_marker = ++m_cursor);
                 if (yych <= 'D')
                 {
                     if (yych == '.')
                     {
-                        goto json_parser_44;
+                        goto json_parser_42;
                     }
-                    goto json_parser_13;
                 }
                 else
                 {
                     if (yych <= 'E')
                     {
-                        goto json_parser_45;
+                        goto json_parser_43;
                     }
                     if (yych == 'e')
                     {
-                        goto json_parser_45;
+                        goto json_parser_43;
                     }
-                    goto json_parser_13;
                 }
-json_parser_52:
+json_parser_24:
+                {
+                    return token_type::value_number;
+                }
+json_parser_25:
+                yyaccept = 1;
+                yych = *(m_marker = ++m_cursor);
+                goto json_parser_41;
+json_parser_26:
+                yyaccept = 0;
+                yych = *(m_marker = ++m_cursor);
+                if (yych <= 0x00)
+                {
+                    goto json_parser_19;
+                }
+                goto json_parser_31;
+json_parser_27:
+                ++m_cursor;
+                {
+                    return token_type::end_of_input;
+                }
+json_parser_29:
+                yych = *++m_cursor;
+                goto json_parser_19;
+json_parser_30:
                 ++m_cursor;
                 yych = *m_cursor;
-json_parser_53:
+json_parser_31:
                 if (yybm[0 + yych] & 64)
                 {
-                    goto json_parser_52;
+                    goto json_parser_30;
                 }
                 if (yych <= 0x00)
                 {
-                    goto json_parser_29;
+                    goto json_parser_32;
                 }
                 if (yych <= '"')
                 {
-                    goto json_parser_55;
+                    goto json_parser_34;
                 }
+                goto json_parser_33;
+json_parser_32:
+                m_cursor = m_marker;
+                if (yyaccept == 0)
+                {
+                    goto json_parser_19;
+                }
+                else
+                {
+                    goto json_parser_24;
+                }
+json_parser_33:
                 ++m_cursor;
                 yych = *m_cursor;
                 if (yych <= 'e')
@@ -2975,13 +2802,13 @@ json_parser_53:
                     {
                         if (yych == '"')
                         {
-                            goto json_parser_52;
+                            goto json_parser_30;
                         }
                         if (yych <= '.')
                         {
-                            goto json_parser_29;
+                            goto json_parser_32;
                         }
-                        goto json_parser_52;
+                        goto json_parser_30;
                     }
                     else
                     {
@@ -2989,17 +2816,17 @@ json_parser_53:
                         {
                             if (yych <= '[')
                             {
-                                goto json_parser_29;
+                                goto json_parser_32;
                             }
-                            goto json_parser_52;
+                            goto json_parser_30;
                         }
                         else
                         {
                             if (yych == 'b')
                             {
-                                goto json_parser_52;
+                                goto json_parser_30;
                             }
-                            goto json_parser_29;
+                            goto json_parser_32;
                         }
                     }
                 }
@@ -3009,13 +2836,13 @@ json_parser_53:
                     {
                         if (yych <= 'f')
                         {
-                            goto json_parser_52;
+                            goto json_parser_30;
                         }
                         if (yych == 'n')
                         {
-                            goto json_parser_52;
+                            goto json_parser_30;
                         }
-                        goto json_parser_29;
+                        goto json_parser_32;
                     }
                     else
                     {
@@ -3023,156 +2850,334 @@ json_parser_53:
                         {
                             if (yych <= 'r')
                             {
-                                goto json_parser_52;
+                                goto json_parser_30;
                             }
-                            goto json_parser_29;
+                            goto json_parser_32;
                         }
                         else
                         {
                             if (yych <= 't')
                             {
-                                goto json_parser_52;
+                                goto json_parser_30;
                             }
                             if (yych <= 'u')
                             {
-                                goto json_parser_57;
+                                goto json_parser_36;
                             }
-                            goto json_parser_29;
+                            goto json_parser_32;
                         }
                     }
                 }
-json_parser_55:
+json_parser_34:
                 ++m_cursor;
                 {
                     return token_type::value_string;
                 }
-json_parser_57:
+json_parser_36:
                 ++m_cursor;
                 yych = *m_cursor;
                 if (yych <= '@')
                 {
                     if (yych <= '/')
                     {
-                        goto json_parser_29;
+                        goto json_parser_32;
                     }
                     if (yych >= ':')
                     {
-                        goto json_parser_29;
+                        goto json_parser_32;
                     }
                 }
                 else
                 {
                     if (yych <= 'F')
                     {
-                        goto json_parser_58;
+                        goto json_parser_37;
                     }
                     if (yych <= '`')
                     {
-                        goto json_parser_29;
+                        goto json_parser_32;
                     }
                     if (yych >= 'g')
                     {
-                        goto json_parser_29;
+                        goto json_parser_32;
                     }
                 }
-json_parser_58:
+json_parser_37:
                 ++m_cursor;
                 yych = *m_cursor;
                 if (yych <= '@')
                 {
                     if (yych <= '/')
                     {
-                        goto json_parser_29;
+                        goto json_parser_32;
                     }
                     if (yych >= ':')
                     {
-                        goto json_parser_29;
+                        goto json_parser_32;
                     }
                 }
                 else
                 {
                     if (yych <= 'F')
                     {
-                        goto json_parser_59;
+                        goto json_parser_38;
                     }
                     if (yych <= '`')
                     {
-                        goto json_parser_29;
+                        goto json_parser_32;
                     }
                     if (yych >= 'g')
                     {
-                        goto json_parser_29;
+                        goto json_parser_32;
                     }
                 }
-json_parser_59:
+json_parser_38:
                 ++m_cursor;
                 yych = *m_cursor;
                 if (yych <= '@')
                 {
                     if (yych <= '/')
                     {
-                        goto json_parser_29;
+                        goto json_parser_32;
                     }
                     if (yych >= ':')
                     {
-                        goto json_parser_29;
+                        goto json_parser_32;
                     }
                 }
                 else
                 {
                     if (yych <= 'F')
                     {
-                        goto json_parser_60;
+                        goto json_parser_39;
                     }
                     if (yych <= '`')
                     {
-                        goto json_parser_29;
+                        goto json_parser_32;
                     }
                     if (yych >= 'g')
                     {
-                        goto json_parser_29;
+                        goto json_parser_32;
                     }
                 }
-json_parser_60:
+json_parser_39:
                 ++m_cursor;
                 yych = *m_cursor;
                 if (yych <= '@')
                 {
                     if (yych <= '/')
                     {
-                        goto json_parser_29;
+                        goto json_parser_32;
                     }
                     if (yych <= '9')
                     {
-                        goto json_parser_52;
+                        goto json_parser_30;
                     }
-                    goto json_parser_29;
+                    goto json_parser_32;
                 }
                 else
                 {
                     if (yych <= 'F')
                     {
-                        goto json_parser_52;
+                        goto json_parser_30;
                     }
                     if (yych <= '`')
                     {
-                        goto json_parser_29;
+                        goto json_parser_32;
                     }
                     if (yych <= 'f')
                     {
-                        goto json_parser_52;
+                        goto json_parser_30;
                     }
-                    goto json_parser_29;
+                    goto json_parser_32;
                 }
-json_parser_61:
-                ++m_cursor;
+json_parser_40:
+                yyaccept = 1;
+                m_marker = ++m_cursor;
                 yych = *m_cursor;
-json_parser_62:
+json_parser_41:
                 if (yybm[0 + yych] & 128)
                 {
-                    goto json_parser_61;
+                    goto json_parser_40;
+                }
+                if (yych <= 'D')
+                {
+                    if (yych != '.')
+                    {
+                        goto json_parser_24;
+                    }
+                }
+                else
+                {
+                    if (yych <= 'E')
+                    {
+                        goto json_parser_43;
+                    }
+                    if (yych == 'e')
+                    {
+                        goto json_parser_43;
+                    }
+                    goto json_parser_24;
+                }
+json_parser_42:
+                yych = *++m_cursor;
+                if (yych <= '/')
+                {
+                    goto json_parser_32;
+                }
+                if (yych <= '9')
+                {
+                    goto json_parser_47;
+                }
+                goto json_parser_32;
+json_parser_43:
+                yych = *++m_cursor;
+                if (yych <= ',')
+                {
+                    if (yych != '+')
+                    {
+                        goto json_parser_32;
+                    }
+                }
+                else
+                {
+                    if (yych <= '-')
+                    {
+                        goto json_parser_44;
+                    }
+                    if (yych <= '/')
+                    {
+                        goto json_parser_32;
+                    }
+                    if (yych <= '9')
+                    {
+                        goto json_parser_45;
+                    }
+                    goto json_parser_32;
+                }
+json_parser_44:
+                yych = *++m_cursor;
+                if (yych <= '/')
+                {
+                    goto json_parser_32;
+                }
+                if (yych >= ':')
+                {
+                    goto json_parser_32;
+                }
+json_parser_45:
+                ++m_cursor;
+                yych = *m_cursor;
+                if (yych <= '/')
+                {
+                    goto json_parser_24;
+                }
+                if (yych <= '9')
+                {
+                    goto json_parser_45;
+                }
+                goto json_parser_24;
+json_parser_47:
+                yyaccept = 1;
+                m_marker = ++m_cursor;
+                yych = *m_cursor;
+                if (yych <= 'D')
+                {
+                    if (yych <= '/')
+                    {
+                        goto json_parser_24;
+                    }
+                    if (yych <= '9')
+                    {
+                        goto json_parser_47;
+                    }
+                    goto json_parser_24;
+                }
+                else
+                {
+                    if (yych <= 'E')
+                    {
+                        goto json_parser_43;
+                    }
+                    if (yych == 'e')
+                    {
+                        goto json_parser_43;
+                    }
+                    goto json_parser_24;
+                }
+json_parser_49:
+                yyaccept = 1;
+                yych = *(m_marker = ++m_cursor);
+                if (yych <= 'D')
+                {
+                    if (yych == '.')
+                    {
+                        goto json_parser_42;
+                    }
+                    goto json_parser_24;
+                }
+                else
+                {
+                    if (yych <= 'E')
+                    {
+                        goto json_parser_43;
+                    }
+                    if (yych == 'e')
+                    {
+                        goto json_parser_43;
+                    }
+                    goto json_parser_24;
+                }
+json_parser_50:
+                yych = *++m_cursor;
+                if (yych != 'l')
+                {
+                    goto json_parser_32;
+                }
+                yych = *++m_cursor;
+                if (yych != 's')
+                {
+                    goto json_parser_32;
+                }
+                yych = *++m_cursor;
+                if (yych != 'e')
+                {
+                    goto json_parser_32;
+                }
+                ++m_cursor;
+                {
+                    return token_type::literal_false;
+                }
+json_parser_55:
+                yych = *++m_cursor;
+                if (yych != 'u')
+                {
+                    goto json_parser_32;
+                }
+                yych = *++m_cursor;
+                if (yych != 'e')
+                {
+                    goto json_parser_32;
+                }
+                ++m_cursor;
+                {
+                    return token_type::literal_true;
+                }
+json_parser_59:
+                yych = *++m_cursor;
+                if (yych != 'l')
+                {
+                    goto json_parser_32;
+                }
+                yych = *++m_cursor;
+                if (yych != 'l')
+                {
+                    goto json_parser_32;
+                }
+                ++m_cursor;
+                {
+                    return token_type::literal_null;
                 }
-                goto json_parser_2;
             }
 
         }
@@ -3261,7 +3266,19 @@ json_parser_62:
             get_token();
         }
 
+        /// public parser interface
         inline basic_json parse()
+        {
+            basic_json result = parse_internal();
+
+            expect(lexer::token_type::end_of_input);
+
+            return result;
+        }
+
+      private:
+        /// the actual parser
+        inline basic_json parse_internal()
         {
             switch (last_token)
             {
@@ -3276,12 +3293,19 @@ json_parser_62:
                     // closing } -> we are done
                     if (last_token == lexer::token_type::end_object)
                     {
+                        get_token();
                         return result;
                     }
 
                     // otherwise: parse key-value pairs
                     do
                     {
+                        // ugly, but could be fixed with loop reorganization
+                        if (last_token == lexer::token_type::value_separator)
+                        {
+                            get_token();
+                        }
+
                         // store key
                         expect(lexer::token_type::value_string);
                         const auto key = m_lexer.get_string();
@@ -3292,16 +3316,13 @@ json_parser_62:
 
                         // parse value
                         get_token();
-                        result[key] = parse();
-
-                        // read next character
-                        get_token();
+                        result[key] = parse_internal();
                     }
-                    while (last_token == lexer::token_type::value_separator
-                            and get_token() == last_token);
+                    while (last_token == lexer::token_type::value_separator);
 
                     // closing }
                     expect(lexer::token_type::end_object);
+                    get_token();
 
                     return result;
                 }
@@ -3317,44 +3338,53 @@ json_parser_62:
                     // closing ] -> we are done
                     if (last_token == lexer::token_type::end_array)
                     {
+                        get_token();
                         return result;
                     }
 
                     // otherwise: parse values
                     do
                     {
-                        // parse value
-                        result.push_back(parse());
+                        // ugly, but could be fixed with loop reorganization
+                        if (last_token == lexer::token_type::value_separator)
+                        {
+                            get_token();
+                        }
 
-                        // read next character
-                        get_token();
+                        // parse value
+                        result.push_back(parse_internal());
                     }
-                    while (last_token == lexer::token_type::value_separator
-                            and get_token() == last_token);
+                    while (last_token == lexer::token_type::value_separator);
 
                     // closing ]
                     expect(lexer::token_type::end_array);
+                    get_token();
 
                     return result;
                 }
 
                 case (lexer::token_type::literal_null):
                 {
+                    get_token();
                     return basic_json(nullptr);
                 }
 
                 case (lexer::token_type::value_string):
                 {
-                    return basic_json(m_lexer.get_string());
+                    const auto s = m_lexer.get_string();
+                    get_token();
+                    return basic_json(s);
                 }
 
                 case (lexer::token_type::literal_true):
                 {
+                    get_token();
                     return basic_json(true);
                 }
 
                 case (lexer::token_type::literal_false):
                 {
+                    get_token();
                     return basic_json(false);
                 }
 
@@ -3368,6 +3398,8 @@ json_parser_62:
                                                     m_lexer.get_string_value() + " is not a number");
                     }
 
+                    get_token();
+
                     // check if conversion loses precision
                     const auto int_val = static_cast<number_integer_t>(float_val);
                     if (float_val == int_val)
@@ -3393,7 +3425,6 @@ json_parser_62:
             }
         }
 
-      private:
         /// get next token from lexer
         inline typename lexer::token_type get_token()
         {
diff --git a/src/json.hpp.re2c b/src/json.hpp.re2c
index 596ddeee..24a9d45c 100644
--- a/src/json.hpp.re2c
+++ b/src/json.hpp.re2c
@@ -2524,7 +2524,7 @@ class basic_json
                 '\000'         { return token_type::end_of_input; }
 
                 // anything else is an error
-                *              { return token_type::parse_error; }
+                .              { return token_type::parse_error; }
              */
         }
 
@@ -2612,7 +2612,19 @@ class basic_json
             get_token();
         }
 
+        /// public parser interface
         inline basic_json parse()
+        {
+            basic_json result = parse_internal();
+
+            expect(lexer::token_type::end_of_input);
+
+            return result;
+        }
+
+      private:
+        /// the actual parser
+        inline basic_json parse_internal()
         {
             switch (last_token)
             {
@@ -2627,12 +2639,19 @@ class basic_json
                     // closing } -> we are done
                     if (last_token == lexer::token_type::end_object)
                     {
+                        get_token();
                         return result;
                     }
 
                     // otherwise: parse key-value pairs
                     do
                     {
+                        // ugly, but could be fixed with loop reorganization
+                        if (last_token == lexer::token_type::value_separator)
+                        {
+                            get_token();
+                        }
+
                         // store key
                         expect(lexer::token_type::value_string);
                         const auto key = m_lexer.get_string();
@@ -2643,16 +2662,13 @@ class basic_json
 
                         // parse value
                         get_token();
-                        result[key] = parse();
-
-                        // read next character
-                        get_token();
+                        result[key] = parse_internal();
                     }
-                    while (last_token == lexer::token_type::value_separator
-                            and get_token() == last_token);
+                    while (last_token == lexer::token_type::value_separator);
 
                     // closing }
                     expect(lexer::token_type::end_object);
+                    get_token();
 
                     return result;
                 }
@@ -2668,44 +2684,53 @@ class basic_json
                     // closing ] -> we are done
                     if (last_token == lexer::token_type::end_array)
                     {
+                        get_token();
                         return result;
                     }
 
                     // otherwise: parse values
                     do
                     {
-                        // parse value
-                        result.push_back(parse());
+                        // ugly, but could be fixed with loop reorganization
+                        if (last_token == lexer::token_type::value_separator)
+                        {
+                            get_token();
+                        }
 
-                        // read next character
-                        get_token();
+                        // parse value
+                        result.push_back(parse_internal());
                     }
-                    while (last_token == lexer::token_type::value_separator
-                            and get_token() == last_token);
+                    while (last_token == lexer::token_type::value_separator);
 
                     // closing ]
                     expect(lexer::token_type::end_array);
+                    get_token();
 
                     return result;
                 }
 
                 case (lexer::token_type::literal_null):
                 {
+                    get_token();
                     return basic_json(nullptr);
                 }
 
                 case (lexer::token_type::value_string):
                 {
-                    return basic_json(m_lexer.get_string());
+                    const auto s = m_lexer.get_string();
+                    get_token();
+                    return basic_json(s);
                 }
 
                 case (lexer::token_type::literal_true):
                 {
+                    get_token();
                     return basic_json(true);
                 }
 
                 case (lexer::token_type::literal_false):
                 {
+                    get_token();
                     return basic_json(false);
                 }
 
@@ -2719,6 +2744,8 @@ class basic_json
                                                     m_lexer.get_string_value() + " is not a number");
                     }
 
+                    get_token();
+
                     // check if conversion loses precision
                     const auto int_val = static_cast<number_integer_t>(float_val);
                     if (float_val == int_val)
@@ -2744,7 +2771,6 @@ class basic_json
             }
         }
 
-      private:
         /// get next token from lexer
         inline typename lexer::token_type get_token()
         {
diff --git a/test/unit.cpp b/test/unit.cpp
index e34bd5cb..37fcee55 100644
--- a/test/unit.cpp
+++ b/test/unit.cpp
@@ -5052,7 +5052,15 @@ TEST_CASE("parser class")
         CHECK_THROWS_AS(json::parser("--").parse(), std::invalid_argument);
         CHECK_THROWS_AS(json::parser("-0.").parse(), std::invalid_argument);
         CHECK_THROWS_AS(json::parser("-.").parse(), std::invalid_argument);
+        CHECK_THROWS_AS(json::parser("-:").parse(), std::invalid_argument);
         CHECK_THROWS_AS(json::parser("0.:").parse(), std::invalid_argument);
+        CHECK_THROWS_AS(json::parser("e.").parse(), std::invalid_argument);
+        CHECK_THROWS_AS(json::parser("1e.").parse(), std::invalid_argument);
+        CHECK_THROWS_AS(json::parser("1e/").parse(), std::invalid_argument);
+        CHECK_THROWS_AS(json::parser("1e:").parse(), std::invalid_argument);
+        CHECK_THROWS_AS(json::parser("1E.").parse(), std::invalid_argument);
+        CHECK_THROWS_AS(json::parser("1E/").parse(), std::invalid_argument);
+        CHECK_THROWS_AS(json::parser("1E:").parse(), std::invalid_argument);
 
         // unexpected end of null
         CHECK_THROWS_AS(json::parser("n").parse(), std::invalid_argument);