feat: 支持数字字面量中的下划线分隔符
- 增加了对数字中下划线的处理逻辑 - 添加了防止下划线连续出现、以下划线开头或结尾的校验 - 优化了小数部分的下划线检查 - 修复了数字后紧跟下划线的错误处理 - 最后返回的数字字面量中将移除所有的下划线
This commit is contained in:
parent
ac5b73e320
commit
d0e8cee6bd
@ -80,6 +80,9 @@ public class NumberTokenScanner extends AbstractTokenScanner {
|
||||
StringBuilder literal = new StringBuilder();
|
||||
State state = State.INT_PART;
|
||||
|
||||
boolean lastWasUnderscore = false; // 记录前一个是否是下划线
|
||||
boolean sawDigit = false; // 当前段落是否有数字(防止以下划线开头)
|
||||
|
||||
/* ───── 1. 主体扫描 —— 整数 / 小数 ───── */
|
||||
mainLoop:
|
||||
while (!ctx.isAtEnd() && state != State.END) {
|
||||
@ -89,10 +92,25 @@ public class NumberTokenScanner extends AbstractTokenScanner {
|
||||
case INT_PART:
|
||||
if (Character.isDigit(ch)) {
|
||||
literal.append(ctx.advance());
|
||||
lastWasUnderscore = false;
|
||||
sawDigit = true;
|
||||
} else if (ch == '_') {
|
||||
if (!sawDigit)
|
||||
throw new LexicalException("数字不能以下划线开头", line, col);
|
||||
if (lastWasUnderscore)
|
||||
throw new LexicalException("数字中下划线不能连续出现", line, col);
|
||||
literal.append(ctx.advance());
|
||||
lastWasUnderscore = true;
|
||||
} else if (ch == '.') {
|
||||
if (lastWasUnderscore)
|
||||
throw new LexicalException("下划线不能出现在小数点前", line, col);
|
||||
state = State.DEC_POINT;
|
||||
literal.append(ctx.advance());
|
||||
// 不要重置sawDigit!
|
||||
// sawDigit = false; // 移除此句
|
||||
} else {
|
||||
if (lastWasUnderscore)
|
||||
throw new LexicalException("数字不能以下划线结尾", line, col);
|
||||
state = State.END;
|
||||
}
|
||||
break;
|
||||
@ -100,18 +118,30 @@ public class NumberTokenScanner extends AbstractTokenScanner {
|
||||
/* 已读到小数点,下一字符必须是数字 */
|
||||
case DEC_POINT:
|
||||
if (Character.isDigit(ch)) {
|
||||
state = State.FRAC_PART;
|
||||
literal.append(ctx.advance());
|
||||
state = State.FRAC_PART;
|
||||
sawDigit = true;
|
||||
} else if (ch == '_') { // 防止小数点后直接跟下划线
|
||||
throw new LexicalException("小数点后不能直接跟下划线", line, col);
|
||||
} else {
|
||||
throw new LexicalException("小数点后必须跟数字", line, col);
|
||||
}
|
||||
break;
|
||||
|
||||
/* 小数部分 */
|
||||
|
||||
case FRAC_PART:
|
||||
if (Character.isDigit(ch)) {
|
||||
literal.append(ctx.advance());
|
||||
lastWasUnderscore = false;
|
||||
} else if (ch == '_') { // 小数部分下划线检查
|
||||
if (lastWasUnderscore)
|
||||
throw new LexicalException("数字中下划线不能连续出现", line, col);
|
||||
literal.append(ctx.advance());
|
||||
lastWasUnderscore = true;
|
||||
} else {
|
||||
if (lastWasUnderscore)
|
||||
throw new LexicalException("数字不能以下划线结尾", line, col);
|
||||
state = State.END;
|
||||
}
|
||||
break;
|
||||
@ -121,6 +151,10 @@ public class NumberTokenScanner extends AbstractTokenScanner {
|
||||
}
|
||||
}
|
||||
|
||||
// 主体结束后,下划线不能在末尾
|
||||
if (lastWasUnderscore)
|
||||
throw new LexicalException("数字不能以下划线结尾", line, col);
|
||||
|
||||
/* ───── 2. 后缀及非法尾随字符检查 ───── */
|
||||
if (!ctx.isAtEnd()) {
|
||||
char next = ctx.peek();
|
||||
@ -154,7 +188,7 @@ public class NumberTokenScanner extends AbstractTokenScanner {
|
||||
}
|
||||
|
||||
/* ───── 3. 生成并返回 Token ───── */
|
||||
return new Token(TokenType.NUMBER_LITERAL, literal.toString(), line, col);
|
||||
return new Token(TokenType.NUMBER_LITERAL, literal.toString().replace("_", ""), line, col);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user