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();
|
nextChar();
|
||||||
char c = getchar();
|
char c = getchar();
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'x':
|
case 'x': case 'X':
|
||||||
num.token.push_back(c);
|
num.token.push_back(c);
|
||||||
num.base = 16;
|
num.base = 16;
|
||||||
|
nextChar();
|
||||||
break;
|
break;
|
||||||
case 'b':
|
case 'b': case 'B':
|
||||||
num.token.push_back(c);
|
num.token.push_back(c);
|
||||||
num.base = 2;
|
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;
|
break;
|
||||||
default:
|
default:
|
||||||
if (c != '.') {
|
// Just "0" — stop here
|
||||||
num.token.push_back(c);
|
num.end = getLastPosition();
|
||||||
num.base = 8;
|
return num;
|
||||||
} else {
|
|
||||||
num.token.push_back(c);
|
|
||||||
num.base = 10;
|
|
||||||
nextDot = true;
|
|
||||||
num.isFloat = true;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
nextChar();
|
|
||||||
} else {
|
} else {
|
||||||
num.base = 10;
|
num.base = 10;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -397,7 +397,15 @@ inline ASTNode* Parser::parseContinueStatement() {
|
||||||
inline ASTNode* Parser::parseExpressionStatement() {
|
inline ASTNode* Parser::parseExpressionStatement() {
|
||||||
ExpressionStatementNode* es = new ExpressionStatementNode();
|
ExpressionStatementNode* es = new ExpressionStatementNode();
|
||||||
es->expression = parseExpression();
|
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)
|
if (currentToken().type == TokenType::SEMICOLON)
|
||||||
nextToken();
|
nextToken();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -82,14 +82,26 @@ inline constexpr std::string_view delimiters[] = {
|
||||||
};
|
};
|
||||||
|
|
||||||
inline constexpr std::string_view keywords[] = {
|
inline constexpr std::string_view keywords[] = {
|
||||||
"implements", "protected", "interface", "continue",
|
// Control flow
|
||||||
"private", "finally", "extends", "default",
|
"if", "else", "for", "while", "do",
|
||||||
"throws", "switch", "return", "public",
|
"switch", "case", "default", "break", "continue",
|
||||||
"assert", "false", "while", "throw",
|
"return", "try", "catch", "finally", "throw",
|
||||||
"class", "catch", "break", "null",
|
"throws", "assert",
|
||||||
"true", "enum", "else", "case",
|
// Types
|
||||||
"new", "try", "for", "if",
|
"void", "int", "float", "double", "char",
|
||||||
"do"
|
"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;
|
return nt;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Keywords
|
// Keywords (check boundary: keyword must not be prefix of longer identifier)
|
||||||
for (const auto& kw : keywords) {
|
for (const auto& kw : keywords) {
|
||||||
if (hmx.include(std::string(kw), false)) {
|
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();
|
KeywordToken* kt = new KeywordToken();
|
||||||
kt->start = hmx.getOffset();
|
kt->start = hmx.getOffset();
|
||||||
hmx.toChar(static_cast<int>(kw.size()));
|
hmx.toChar(static_cast<int>(kw.size()));
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue