我正在尝试为IntelliJ语言插件编写一个词法分析器。在 JFLex 手册中,有一个示例可以对字符串文字进行词法化。但是,在此示例中,他们使用 StringBuffer 插入词法字符的每个部分,并不断构建单个字符串。我对这种方法的问题是它创建了正在读取的字符的副本,我不知道如何将该示例与 IntelliJ 集成。在IntelliJ中,总是返回一个IElementType,然后使用函数getTokenStart()
和getTokenEnd()
从yytext()中获取关联的文本,使得整个令牌的开始和结束直接映射到输入字符串。
因此,我希望能够返回一个令牌,并且关联的yytext()
应该跨越自上次返回另一个令牌以来的整个文本。例如,在字符串文本示例中,我将读取标记文本开始的"
,然后更改为状态STRING
,当我再次读取"
时,我变回另一个状态并返回字符串文本标记。在这一点上,我希望yytext()包含整个字符串文字。
这在JFlex中可能吗?如果不是,建议为什么要在匹配跨多个操作的令牌后将内容从 StringBuffer 传递到 IntelliJ API。
您可以编写一个与整个字符串文本匹配的正则表达式,以便在一次 yytext() 调用中获取它,但此匹配将包含未处理的转义序列。
从 JFlex java 示例:
<STRING> {
" { yybegin(YYINITIAL); return symbol(STRING_LITERAL, string.toString()); }
{StringCharacter}+ { string.append( yytext() ); }
/* escape sequences */
"\b" { string.append( 'b' ); }
"\t" { string.append( 't' ); }
"\n" { string.append( 'n' ); }
"\f" { string.append( 'f' ); }
"\r" { string.append( 'r' ); }
"\"" { string.append( '"' ); }
"\'" { string.append( ''' ); }
"\\" { string.append( '\' ); }
\[0-3]?{OctDigit}?{OctDigit} { char val = (char) Integer.parseInt(yytext().substring(1),8);
string.append( val ); }
/* error cases */
\. { throw new RuntimeException("Illegal escape sequence ""+yytext()+"""); }
{LineTerminator} { throw new RuntimeException("Unterminated string at end of line"); }
}
此代码不仅匹配像 "\t"
这样的转义序列,而且将它们转换为单个字符't'
。您可以在这样的表达式中的一个表达式中匹配整个字符串
" ({StringCharacter} | \[0-3]?{OctDigit}?{OctDigit} | "\b" | "\t" | .. | "\\") * "
但是 yytext 随后将包含未处理的序列\t
而不是字符't'
。
如果这是可以接受的,那么这就是简单的解决方案。如果令牌应该是输入的实际子字符串,那么听起来这就是您想要的。
如果不是,您将需要更复杂的东西,例如一个中间接口函数,它不是yytext()
,但当最后一个匹配是字符串匹配时返回StringBuffer
内容(您可以在字符串操作中设置的标志),否则返回yytext()
。