
本文详解如何在 javacc 中定义仅匹配偶数的 token,并通过编写主程序调用词法分析器进行精准测试,涵盖语法定义、java 调用逻辑、匹配优先级注意事项及更健壮的实践建议。
本文详解如何在 javacc 中定义仅匹配偶数的 token,并通过编写主程序调用词法分析器进行精准测试,涵盖语法定义、java 调用逻辑、匹配优先级注意事项及更健壮的实践建议。
在 JavaCC 中,Token 的识别完全由词法规则(TOKEN 部分)驱动,其匹配行为遵循最长匹配(Longest Match) 和定义顺序优先(Order-of-Definition Priority) 原则。要实现“仅接受偶数数字”的 Token,直观思路是让正则匹配以偶数结尾(如 "0"|"2"|"4"|"6"|"8"),但需特别注意:JavaCC 的 Token 规则本质是字符串模式匹配,不进行数值解析或语义校验——它只关心字符序列是否符合正则,而非该序列是否为数学意义上的偶数。
以下是一个可直接运行的完整示例:
// parser.jj
options {
STATIC = false;
}
PARSER_BEGIN(Parser)
package example;
public class Parser {
}
PARSER_END(Parser)
TOKEN: {
<EVEN: (["0"-"9"])+ ("0"|"2"|"4"|"6"|"8") >
| <ODD: (["0"-"9"])+ ("1"|"3"|"5"|"7"|"9") >
| <SKIP: [" "] > // 忽略空格,便于测试
}✅ 关键修正说明:
- 使用 (["0"-"9"])+(至少一位数字)替代 (["0"-"9"])*,避免匹配空字符串;
- 显式添加 <SKIP> 规则跳过空白,防止输入含空格时报错;
- EVEN 与 ODD 并列定义,利用 JavaCC 的“先定义者优先”机制确保无歧义(例如 "24" 会整体匹配 EVEN,而非拆成 "2"+"4")。
生成解析器后,在 Java 主类中调用词法分析器进行测试:
立即学习“Java免费学习笔记(深入)”;
// TestParser.java
package example;
import java.io.StringReader;
public class TestParser {
public static void main(String[] args) {
String input = "123456"; // 测试偶数
Parser parser = new Parser(new StringReader(input));
try {
Token token = parser.getNextToken();
if (token.kind == Parser.EVEN) {
System.out.println("✅ Even number matched: \"" + token.image + "\"");
} else if (token.kind == Parser.ODD) {
System.out.println("❌ Odd number matched: \"" + token.image + "\"");
} else {
System.out.println("⚠️ Unmatched token: kind=" + token.kind + ", image=\"" + token.image + "\"");
}
} catch (Exception e) {
System.err.println("Parsing error: " + e.getMessage());
}
}
}? 重要注意事项:
- 前导零问题:"0042" 会被匹配为 EVEN(因以 '2' 结尾),但它在 Java 中解析为整数 42(仍是偶数)。若需严格校验数值合法性(如禁止前导零),应在 Java 动作中解析 token.image 并做 Integer.parseInt() + % 2 == 0 判断,而非依赖正则;
- 匹配完整性:JavaCC 默认贪婪匹配最长有效序列。输入 "123456789" 将整体匹配 ODD(因以 '9' 结尾),而非截取 "12345678" 作为 EVEN —— 这是正确行为;
- 推荐进阶方案:定义统一 <NUMBER: (["0"-"9"])+> Token,在语法动作或后续 Java 逻辑中判断奇偶性,既提升可维护性,又避免正则过度复杂化:
void numberWithParity() : { Token t; } {
t = <NUMBER> {
int value = Integer.parseInt(t.image);
System.out.println(value + " is " + (value % 2 == 0 ? "even" : "odd"));
}
}综上,测试 JavaCC Token 的核心在于:明确 Token 定义意图 → 生成解析器 → 在 Java 主程序中调用 getNextToken() 获取并检查 token.kind 与 token.image。避免在 Token 规则中嵌入复杂逻辑,优先保证词法层简洁可靠,将语义判断移交至解析器或应用层处理。


















