Java Lexer中Switch语句无法识别空格与"+"运算符的问题求助
词法分析器空格与运算符识别问题排查
实现的词法分析器通过cursor跟踪处理位置,输入"10 + 15 * (10 + 3 * 3 - 2)"时,能正常处理数字,但cursor到达位置2(对应空格字符)时,Switch语句无法识别空格与"+"运算符,抛出错误"Expected a valid token at position: 2",无法推进到"+"运算符。
相关代码
Main类
import Class.Parser; import Class.Lexer; import Model.Token; import java.util.List; public class Main { public static void main(String[] args) throws Exception { Lexer lexer = new Lexer("10 + 15 * (10 + 3 * 3 - 2)"); List <Token> tokens = lexer.getTokens(); } }
Lexer类
package Class; import Model.Spec; import Model.Token; import Model.TokenType; import java.util.ArrayList; import java.util.List; import java.util.Objects; import java.util.function.ToIntFunction; import java.util.regex.Matcher; import java.util.regex.Pattern; public class Lexer { private String _input; private int _cursor; public Lexer() { this._cursor = 0; } public Lexer(String _Input) { this._input = _Input; this._cursor = 0; } public List<Token> getTokens() throws Exception { List<Token> tokens = new ArrayList<>(); if (this._cursor < this._input.length() != true) { return null; } String input = this._input.substring(this._cursor); while (this._cursor < this._input.length()) { switch (input) { case "": case "\n": case "\t": case "\s": break; case "+": tokens.add(new Token(TokenType.PLUS, "+")); break; case "-": tokens.add(new Token(TokenType.MINUS, "-")); break; case "*": tokens.add(new Token(TokenType.MULTIPLY, "*")); break; case "/": tokens.add(new Token(TokenType.DIVIDE, "/")); break; case "(": tokens.add(new Token(TokenType.HAAKJEOPEN, "(")); break; case ")": tokens.add(new Token(TokenType.HAAKJESLUIT, ")")); break; default: if (Character.isDigit(this._input.charAt(this._cursor))) { StringBuilder number = new StringBuilder(); while (this._cursor < this._input.length() && Character.isDigit(this._input.charAt(this._cursor))) { number.append(this._input.charAt(this._cursor)); this._cursor++; } tokens.add(new Token(TokenType.NUMERICAL, number.toString())); this._cursor--; } else { throw new Exception("Expected a valid token at position:" + " " + this._cursor); } } this._cursor++; } tokens.add(new Token(TokenType.EOF, "EOF")); return tokens; } }
问题原因
- Switch判断对象错误:代码中
switch (input)的input是从当前cursor到末尾的完整子串(比如cursor在位置2时,input是" + 15 * (10 + 3 * 3 - 2)"),而非当前cursor指向的单个字符,导致无法匹配case中定义的单个空格、运算符等字符,直接进入default分支抛出错误。 - 空格匹配错误:Java中普通字符串匹配空格需用
" ",代码中使用的"\s"是正则表达式的空格写法,实际会被解析为ASCII换页符(\u000C),无法匹配输入中的空格。 - 冗余变量与cursor操作问题:
String input = this._input.substring(this._cursor);是冗余变量,且数字处理后_cursor--会抵消循环末尾的_cursor++,逻辑冗余。
修复方案
修改Lexer类的getTokens方法,核心调整如下:
- 将Switch判断对象改为当前cursor指向的单个字符
_input.charAt(_cursor) - 修正空格匹配为
" " - 移除冗余的
input变量 - 调整数字处理的cursor逻辑,避免重复递减
修改后的Lexer类代码
package Class; import Model.Token; import Model.TokenType; import java.util.ArrayList; import java.util.List; public class Lexer { private String _input; private int _cursor; public Lexer() { this._cursor = 0; } public Lexer(String _Input) { this._input = _Input; this._cursor = 0; } public List<Token> getTokens() throws Exception { List<Token> tokens = new ArrayList<>(); if (_cursor >= _input.length()) { return tokens; } while (_cursor < _input.length()) { char currentChar = _input.charAt(_cursor); switch (currentChar) { case ' ': case '\n': case '\t': // 跳过空白字符,不生成token break; case '+': tokens.add(new Token(TokenType.PLUS, "+")); break; case '-': tokens.add(new Token(TokenType.MINUS, "-")); break; case '*': tokens.add(new Token(TokenType.MULTIPLY, "*")); break; case '/': tokens.add(new Token(TokenType.DIVIDE, "/")); break; case '(': tokens.add(new Token(TokenType.HAAKJEOPEN, "(")); break; case ')': tokens.add(new Token(TokenType.HAAKJESLUIT, ")")); break; default: if (Character.isDigit(currentChar)) { StringBuilder number = new StringBuilder(); while (_cursor < _input.length() && Character.isDigit(_input.charAt(_cursor))) { number.append(_input.charAt(_cursor)); _cursor++; } tokens.add(new Token(TokenType.NUMERICAL, number.toString())); // 回退cursor,避免循环末尾的cursor++跳过下一个字符 _cursor--; } else { throw new Exception("Expected a valid token at position:" + " " + _cursor); } } _cursor++; } tokens.add(new Token(TokenType.EOF, "EOF")); return tokens; } }
内容的提问来源于stack exchange,提问作者Cezar P
相关产品推荐
相关产品推荐

