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:
parent
40579ca508
commit
438bc0e200
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
||||
|
|
|
|||
|
|
@ -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()));
|
||||
|
|
|
|||
Loading…
Reference in New Issue