JavaCC 词法规范被组织成一组词法状态,每个词法状态都用一个唯一的标识符命名。有一个标准的词汇状态称为 DEFAULT。生成的令牌管理器随时处于这些词法状态之一。默认情况下,初始化令牌管理器时,它将在状态中启动。在构造令牌管理器对象时,也可以将起始词法状态指定为参数。
每个词法状态都包含一个正则表达式的有序列表 - 顺序派生自输入文件中的出现顺序。有四种类型的正则表达式:
在语法中作为扩展单元出现的所有正则表达式都被视为处于 DEFAULT 词法状态,其出现顺序由它们在语法文件中的位置确定。
当前词法状态中的所有正则表达式都被视为潜在的匹配候选项。Token 管理器使用输入流中与这些正则表达式之一匹配的最大字符数。也就是说,Token 管理器首选尽可能长的匹配。如果有多个长度相同的最长匹配项,则匹配的正则表达式是语法文件中出现顺序最早的正则表达式。
如上所述,Token 管理器在任何时候都处于一种状态。此时,Token 管理器仅考虑在此状态下定义的正则表达式以进行匹配。匹配后,可以指定要执行的操作以及要移动到的新词汇状态。如果未指定新的词法状态,则Token 管理器将保持当前状态。
TOKEN: {
|
|
…
…
|
}
扫描器扫描符合正则表达式模式的字符串并生成对应的token。并且TOKEN命令的块在一个文件中可以出现任意多次,因此按照逻辑上的相关性分开记载TOKEN命令比较好。
选择匹配规则
正则表达式类型指定成功匹配正则表达式时要执行的操作:
SKIP 只需丢弃匹配的字符串(在执行任何词法操作后)。
MORE 继续下一个状态,带走匹配的字符串。此字符串将是新匹配字符串的前缀。
TOKEN 使用匹配的字符串创建令牌,并将其发送到解析器(或任何调用方)。
SPECIAL_TOKEN 创建不参与分析的特殊令牌。前面已经描述过了。
注:注:访问特殊令牌的机制位于本页末尾。
每当检测到文件末尾 时,无论词法分析器的当前状态如何,都会导致创建 token。但是,如果 token在正则表达式的匹配过程中检测到 -(或在匹配 MORE 正则表达式后立即检测到 -),则会报告错误。
匹配正则表达式后,将执行词法操作。在 TOKEN_MGR_DECLS region 中声明的所有变量和方法(见下文)都可以在此处使用。此外,下面列出的变量和方法也可供使用。
在此之后,Token 管理器将状态立即更改为指定的状态(如果有)。
之后,执行由正则表达式类型指定的操作(SKIP, MORE 等)。如果类型为 TOKEN,则返回匹配的TOKEN。如果类型为 SPECIAL_TOKEN,则保存匹配的令牌,以便与匹配的下一个一起返回。
不使用TOKEN命令而使用SKIP命令的话就不会生成token,因此使用SKIP命令可以省略token名。还可以用SPECIAL_TOKEN命令(SPECIAL_TOKEN directive)来跳过token。SKIP命令和SPECIAL_TOKEN命令的区别在于是否保存跳过的token。使用SKIP命令无法访问跳过的字符串,使用SPECIAL_TOKEN命令就可以借助下面被扫描的TOKEN对象来取得跳过的字符串
SKIP: {
|
…
…
|
}
下面的变量可以在词法操作中使用:
MORE : { "a" : S1 }
MORE :
{
"b"
{ int l = image.length()-1; image.setCharAt(l, image.charAt(l).toUpperCase()); }
^1 ^2
: S2
}
TOKEN :
{
"cd" { x = image; } : DEFAULT
^3
}
上面的例子,3处的 image 值:
At ^1: “ab”
At ^2: “aB”
At ^3: “aBcd”
At ^1: 1 (the size of “b”)
At ^2: 1 (does not change due to lexical actions)
At ^3: 2 (the size of “cd”)
int curLexState (READ ONLY)
这是当前词法状态的索引。你不应该修改这个变量。整型常量的名字是那些词汇生成状态进入…Constant常量文件,因此您可以参考词汇而不用担心实际索引值。
inputStream (READ ONLY)
输入流是以下的一种:
ASCII_CharStream
ASCII_UCodeESC_CharStream
UCode_CharStream
UCode_UCodeESC_CharStream
Token matchedToken (READ/WRITE)
void SwitchTo(int)
特殊token就像token,除了他们被允许出现在输入文件(任何两个token之间)。特殊token可以指定输入文件的语法使用保留字SPECIAL_TOKEN 而不是 token ,例如:
SPECIAL_TOKEN :
{
}
任何定义为 SPECIAL_TOKEN 的正则表达式,可能以特殊的方式从词法和语法的用户操作规范访问。这允许将这些 token 在解析时恢复,同时这些 token 不参与解析。
从输入语法文件复制到生成的文件,JavaCC一直引导使用此功能会自动复制相关comments 。
类令牌现在有一个额外的字段:
Token specialToken;
这个字段指向 SPECIAL_TOKEN 在当前令牌之前(特殊或其他)。如果在当前 token 之前的 token 是一个常规的token (而不是一个特殊的token ),那么这个字段被设置为null。常规token的下一个字段具有相同的意义,即他们指向下一个常规token除了EOF token。EOF token next字段为空。下一个字段特殊标记的特殊令牌后立即当前令牌。如果跟随当前令牌之后是一个常规的token ,next字段被设置为null。
例:
// if there are no special tokens return control to the caller
if (t.specialToken == null) {
return;
}
// walk back the special token chain until it reaches the first special token after the previous regular token
Token tmp_t = t.specialToken;
while (tmp_t.specialToken != null) {
tmp_t = tmp_t.specialToken;
}
// now walk the special token chain forward and print them in the process
while (tmp_t != null) {
System.out.println(tmp_t.image);
tmp_t = tmp_t.next;
}