feat: statement parser (if/for/while/do-while/return), keyword tokenizer düzeltmeleri

- Tokenizer: tüm keyword'ler eklendi (int, void, float, vb)
- Keyword boundary check: kısa keyword uzun identifier'la karışmıyor
- Lexer: '0' sonrası karakter kontrolü düzeltildi (0; token sorunu)
- Parser: if/else, for, while, do-while, return, break, continue desteği
- FunctionDecl, VariableDecl, Block, ExpressionStatement tam destek
- null expression koruması (sonsuz döngü engellendi)
This commit is contained in:
abdussamedulutas 2026-05-26 00:05:52 +03:00
parent 40579ca508
commit 438bc0e200
4 changed files with 54 additions and 23 deletions

BIN
saqut

Binary file not shown.

View File

@ -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;
default:
if (c != '.') {
num.token.push_back(c);
num.base = 8;
} else {
case '.':
num.token.push_back(c);
num.base = 10;
nextDot = true;
num.isFloat = true;
}
break;
}
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:
// Just "0" — stop here
num.end = getLastPosition();
return num;
}
} else {
num.base = 10;
}

View File

@ -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();

View File

@ -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<int>(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<int>(kw.size()));