C初始化语句无效词法单元识别异常问题求助
修复C初始化语句词法单元识别的两个核心问题
问题根源分析
- 空白字符未过滤:代码中定义了
isValidLexeme但未实际调用,导致空白lexeme被送入标识符检查逻辑,触发无意义的Invalid identifier:错误。 - 状态变量逻辑完全错误:
isInvalidIdentifier的逻辑颠倒,一旦标记为true,后续有效元素会被错误加入无效列表;同时未区分=、;、,等语法符号,将其当作标识符检查。 - 无上下文的遍历逻辑:没有遵循C初始化语句的语法结构(
类型 → 标识符 → [= 常量] → [, 标识符 → ...] → ;),所有非类型的lexeme都被当作标识符验证,忽略了不同位置的元素类型要求。
修复后的完整代码
import java.util.ArrayList; import java.util.Arrays; import java.util.regex.Matcher; import java.util.regex.Pattern; public class LexemeValidator { private static ArrayList<String> findInvalidLexemes(String[] lexemes) { ArrayList<String> invalidLexemes = new ArrayList<>(); if (lexemes == null || lexemes.length == 0) { return invalidLexemes; } // 跟踪当前语法状态 enum LexState { EXPECT_TYPE, EXPECT_IDENTIFIER, EXPECT_ASSIGN, EXPECT_CONSTANT, EXPECT_SEPARATOR } LexState currentState = LexState.EXPECT_TYPE; for (String lexeme : lexemes) { // 先过滤空白lexeme if (!isValidLexeme(lexeme)) { continue; } switch (currentState) { case EXPECT_TYPE: if (lexeme.equals("int") || lexeme.equals("float")) { currentState = LexState.EXPECT_IDENTIFIER; } else { invalidLexemes.add("Invalid data type: " + lexeme); // 类型错误后继续处理后续元素 currentState = LexState.EXPECT_IDENTIFIER; } break; case EXPECT_IDENTIFIER: if (isValidIdentifier(lexeme)) { currentState = LexState.EXPECT_ASSIGN; } else { invalidLexemes.add("Invalid identifier: " + lexeme); // 标识符错误后,等待分隔符切换状态 currentState = LexState.EXPECT_SEPARATOR; } break; case EXPECT_ASSIGN: if (lexeme.equals("=")) { currentState = LexState.EXPECT_CONSTANT; } else if (lexeme.equals(",")) { currentState = LexState.EXPECT_IDENTIFIER; } else if (lexeme.equals(";")) { currentState = LexState.EXPECT_TYPE; } else { // 省略赋值符号的情况,直接进入分隔符状态 currentState = LexState.EXPECT_SEPARATOR; } break; case EXPECT_CONSTANT: if (lexeme.matches("\\d+(\\.\\d+)?")) { if (!isValidInt(lexeme) && !isValidFloat(lexeme)) { invalidLexemes.add("Invalid constant value: " + lexeme); } } else { invalidLexemes.add("Invalid constant value: " + lexeme); } currentState = LexState.EXPECT_SEPARATOR; break; case EXPECT_SEPARATOR: if (lexeme.equals(",")) { currentState = LexState.EXPECT_IDENTIFIER; } else if (lexeme.equals(";")) { currentState = LexState.EXPECT_TYPE; } // 其他符号直接跳过,不报错 break; } } return invalidLexemes; } private static boolean isValidLexeme(String lexeme) { return lexeme != null && !lexeme.isBlank(); } private static boolean isValidIdentifier(String identifier) { if (identifier == null) { return false; } String regex = "^([a-zA-Z_$][a-zA-Z\\d_$]*)$"; Pattern p = Pattern.compile(regex); Matcher m = p.matcher(identifier); if (!m.matches()) { return false; } String[] reservedKeywords = {"int", "float", "double", "char", "short", "long", "unsigned", "signed", "void", "for", "while", "do", "if", "else", "switch", "case", "break", "continue", "return", "goto", "struct", "union", "typedef", "enum", "static", "extern", "const", "volatile", "register", "auto"}; return !Arrays.asList(reservedKeywords).contains(identifier); } private static boolean isValidFloat(String lexeme) { try { float floatValue = Float.parseFloat(lexeme); return floatValue >= 0 && floatValue <= 3.4028235E38; } catch (NumberFormatException e) { return false; } } private static boolean isValidInt(String lexeme) { try { int intValue = Integer.parseInt(lexeme); return intValue >= 0 && intValue <= 2147483647; } catch (NumberFormatException e) { return false; } } // 测试方法 public static void main(String[] args) { String input = "int 2323 = 23. y = notvalid, z;"; String[] lexemes = input.split("(?<=\\W)|(?=\\W)"); // 按非单词字符分割,保留符号 ArrayList<String> result = findInvalidLexemes(lexemes); for (String error : result) { System.out.println(error); } } }
关键改动说明
- 过滤空白单元:遍历前调用
isValidLexeme跳过空白字符,解决空白被当作无效标识符的问题。 - 语法状态跟踪:新增
LexState枚举,严格按照C初始化语句的语法流程切换状态,确保只在正确阶段检查对应类型的lexeme。 - 区分语法符号:
=、;、,仅作为状态切换触发条件,不进行标识符或常量验证,避免错误标记。 - 修正状态逻辑:移除错误的
isInvalidIdentifier变量,改为基于语法状态的精准检查,解决第一个无效标识符后后续元素错误标记的问题。 - 完善常量检查:仅在
EXPECT_CONSTANT状态下验证常量,合并int和float有效性判断,避免重复检查。
测试结果
输入"int 2323 = 23. y = notvalid, z;",输出与预期一致:
Invalid identifier: 2323 Invalid identifier: notvalid
内容的提问来源于stack exchange,提问作者BRENDAN
相关产品推荐
相关产品推荐

