Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/325.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java Antlr4:如何避免过多的语义谓词?_Java_Antlr4 - Fatal编程技术网

Java Antlr4:如何避免过多的语义谓词?

Java Antlr4:如何避免过多的语义谓词?,java,antlr4,Java,Antlr4,以下是我的lexer规则的开始: F_TEXT_START : {! matchingFText}? 'f"' {matchingFText = true;} ; F_TEXT_PH_ESCAPE : {matchingFText && ! matchingFTextPh}? '{=/' ; F_TEXT_PH_START : {matchingFText && ! matchingFTextPh}? '{='

以下是我的lexer规则的开始:

F_TEXT_START
    : {! matchingFText}? 'f"' {matchingFText = true;}
    ;

F_TEXT_PH_ESCAPE
    : {matchingFText && ! matchingFTextPh}? '{=/'
    ;

F_TEXT_PH_START
    : {matchingFText && ! matchingFTextPh}? '{=' {matchingFTextPh = true;}
    ;

F_TEXT_PH_END
    : {matchingFText && matchingFTextPh}? '}' {matchingFTextPh = false;}
    ;

F_TEXT_CHAR
    : {matchingFText && ! matchingFTextPh}? (~('"' | '{')+ | '""' | '{' ~'=')
    ;

F_TEXT_END
    : {matchingFText && ! matchingFTextPh}? '"' {matchingFText = false;}
    ;


IF
    : {! matchingFText || matchingFTextPh}? 'if'
    ;

ELIF
    : {! matchingFText || matchingFTextPh}? 'elif'
    ;

// Lots of other keywords

fragment LETTER
    : ('A' .. 'Z' | 'a' .. 'z' | '_')
    ;
    
VARIABLE
    : {! matchingFText || matchingFTextPh}? LETTER (LETTER | DIGIT)*
    ;
我所做的是将格式化文本不仅仅像普通文本标记一样放在前面,而是将其添加到解析树中,以便能够在解析时判断是否有错误(仅使用
parser.start()
)。因此,格式化文本以
f“
开头,以
结尾,任何
都必须替换为
,并且可以包含以
{=/code>开头和以
}
结尾的占位符,但如果您想实际编写
{
,则必须将其替换为
{
。 问题是,在一个普通的格式化文本内容(不是占位符)中,lexer不仅开始处理
F_text\u CHAR
,而且还处理其他lexer规则,比如变量。我所做的事情看起来相当愚蠢,我只是为每一个其他规则添加语义谓词,以避免它们在格式化文本的内容中匹配(但仍然在占位符中)


没有更好的方法吗?

我会使用词法模式。要使用词法模式,您必须定义单独的词法分析器和语法分析器。下面是一个快速演示:

lexer grammar TestLexer;

F_TEXT_START
 : 'f"' -> pushMode(F_TEXT)
 ;

VARIABLE
 : LETTER (LETTER | DIGIT)*
 ;

F_TEXT_PH_ESCAPE
 : '{=/'
 ;

F_TEXT_PH_END
 : '}' -> popMode
 ;

SPACES
 : [ \t\r\n]+ -> skip
 ;

fragment LETTER
 : [a-zA-Z_]
 ;

fragment DIGIT
 : [0-9]
 ;

mode F_TEXT;

  F_TEXT_CHAR
   : ~["{]+ | '""' | '{' ~'='
   ;

  F_TEXT_PH_START
    : '{=' -> pushMode(DEFAULT_MODE)
    ;

  F_TEXT_END
   : '"' -> popMode
   ;
在解析器中使用lexer,如下所示:

parser grammar TestParser;

options {
  tokenVocab=TestLexer;
}

// ...
如果您现在标记化输入
f“mu{=mu}”mu
,您将获得以下标记:

F_TEXT_START              `f"`
F_TEXT_CHAR               `mu `
F_TEXT_PH_START           `{=`
VARIABLE                  `mu`
F_TEXT_PH_END             `}`
F_TEXT_END                `"`
VARIABLE                  `mu`

谢谢!但我不明白:你为什么不把
F_TEXT\u PH_START
置于
F_TEXT
模式?顺便说一句,谢谢你的GitHub repo“mu”“,它帮助很大!我认为
F_TEXT_PH_START
只能出现在格式化的字符串中。如果不是这样,请相应地调整我的示例语法。是的,确实如此!而且,它可以合并成
F_TEXT_CHAR
如下:
F_TEXT_CHAR:~[“{]+|”“'{'~'='{='{=/'
而且,我已经在使用
{
}
在我的默认语法中(但它不能在
表达式中),我在解析器中要求占位符。它的语义谓词是什么?我在阅读antlr的代码时发现语义pretate:
\u modeStack.contains(1)