我正在尝试为IntelliJ语言插件编写词法分析器。在JFLex manual中有一个例子可以说明字符串文字。但是在这个例子中,他们使用StringBuffer插入lexed字符的每个部分,并不断构建一个字符串。我对这个方法的问题是它创建了正在读取的字符的副本,我不知道如何将该示例与IntelliJ集成。在IntelliJ中,总是返回一个IElementType,然后使用函数getTokenStart()
和getTokenEnd()
从yytext()中获取相关文本,这样整个令牌的开头和结尾都直接映射到输入字符串
所以我希望能够返回一个令牌,并且自上次返回另一个令牌以来,关联的yytext()
应该跨越整个文本。例如,在字符串文字示例中,我会读取标记字面开头的\"
,然后我将更改为状态STRING
,当我再次阅读\"
时,我会更改回另一个状态并返回字符串文字标记。那时我想让yytext()包含整个字符串文字。
JFlex可以实现吗?如果不是,那么为什么在匹配跨越多个操作的令牌后将内容从StringBuffer传递到IntelliJ API的原因是什么。
答案 0 :(得分:0)
您可以编写一个与整个String字面值匹配的正则表达式,以便在一次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()
。