diff --git a/saqut b/saqut index d863054..49c73e8 100755 Binary files a/saqut and b/saqut differ diff --git a/src/lexer/lexer.hpp b/src/lexer/lexer.hpp index c97fa73..dadb815 100644 --- a/src/lexer/lexer.hpp +++ b/src/lexer/lexer.hpp @@ -201,27 +201,33 @@ INumber Lexer::readNumeric() { nextChar(); char c = getchar(); switch (c) { - case 'x': + case 'x': case 'X': num.token.push_back(c); num.base = 16; + nextChar(); break; - case 'b': + case 'b': case 'B': num.token.push_back(c); num.base = 2; + nextChar(); + break; + case '.': + num.token.push_back(c); + num.base = 10; + nextDot = true; + num.isFloat = true; + nextChar(); + break; + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': + // Octal: continue reading in the main loop + num.base = 8; break; default: - if (c != '.') { - num.token.push_back(c); - num.base = 8; - } else { - num.token.push_back(c); - num.base = 10; - nextDot = true; - num.isFloat = true; - } - break; + // Just "0" — stop here + num.end = getLastPosition(); + return num; } - nextChar(); } else { num.base = 10; } diff --git a/src/parser/parser.hpp b/src/parser/parser.hpp index aa74e34..1412af8 100644 --- a/src/parser/parser.hpp +++ b/src/parser/parser.hpp @@ -397,7 +397,15 @@ inline ASTNode* Parser::parseContinueStatement() { inline ASTNode* Parser::parseExpressionStatement() { ExpressionStatementNode* es = new ExpressionStatementNode(); es->expression = parseExpression(); - + if (!es->expression) { + // Parsing failed — skip to next statement boundary + while (currentToken().type != TokenType::SEMICOLON && + currentToken().type != TokenType::RBRACE && + currentToken().type != TokenType::SVR_VOID) + nextToken(); + if (currentToken().type == TokenType::SEMICOLON) + nextToken(); + } if (currentToken().type == TokenType::SEMICOLON) nextToken(); diff --git a/src/tokenizer/tokenizer.hpp b/src/tokenizer/tokenizer.hpp index 80f35fd..83a37e1 100644 --- a/src/tokenizer/tokenizer.hpp +++ b/src/tokenizer/tokenizer.hpp @@ -82,14 +82,26 @@ inline constexpr std::string_view delimiters[] = { }; inline constexpr std::string_view keywords[] = { - "implements", "protected", "interface", "continue", - "private", "finally", "extends", "default", - "throws", "switch", "return", "public", - "assert", "false", "while", "throw", - "class", "catch", "break", "null", - "true", "enum", "else", "case", - "new", "try", "for", "if", - "do" + // Control flow + "if", "else", "for", "while", "do", + "switch", "case", "default", "break", "continue", + "return", "try", "catch", "finally", "throw", + "throws", "assert", + // Types + "void", "int", "float", "double", "char", + "string", "bool", + // Literals + "true", "false", "null", + // OOP + "class", "interface","enum", "extends", "implements", + "new", "public", "private", "protected", + "static", "final", "abstract", + // Modules + "import", "package", + // C/C++ + "const", "extern", "typedef", "sizeof", + "auto", "constexpr","noexcept", + "native", "synchronized", "volatile", "transient" }; // ============================================================ @@ -155,9 +167,14 @@ inline Token* Tokenizer::scope() { return nt; } - // Keywords + // Keywords (check boundary: keyword must not be prefix of longer identifier) for (const auto& kw : keywords) { if (hmx.include(std::string(kw), false)) { + char next = hmx.getchar(static_cast(kw.size())); + if ((next >= 'a' && next <= 'z') || (next >= 'A' && next <= 'Z') || + (next >= '0' && next <= '9') || next == '_' || next == '$') { + continue; // part of longer identifier, not a real keyword + } KeywordToken* kt = new KeywordToken(); kt->start = hmx.getOffset(); hmx.toChar(static_cast(kw.size()));