当前位置: 首页 > 知识库问答 >
问题:

antlr语法:仅允许在模板字符串中进行空格匹配

唐泳
2023-03-14

我要分析模板字符串:

`Some text ${variable.name} and so on ... ${otherVariable.function(parameter)} ...`

这是我的语法:

varname: VAR ;
variable: varname funParameter? ('.' variable)* ;
templateString: '`' (TemplateStringLiteral* '${' variable '}' TemplateStringLiteral*)+ '`' ;
funParameter: '(' variable? (',' variable)*  ')' ;

WS      : [ \t\r\n\u000C]+ -> skip ;
TemplateStringLiteral: ('\\`' | ~'`') ;
VAR : [$]?[a-zA-Z0-9_]+|[$] ;

当语法的输入被解析时,模板字符串不再有空格,因为WS-

无关输入''期望{"'}

如何允许解析空格而不是仅在模板字符串中跳过?

共有1个答案

郭和硕
2023-03-14

当针对显示生成标记的当前语法测试您的示例时,词法分析器会给出以下信息:

[@0,0:0='`',<'`'>,1:0]
[@1,1:4='Some',<VAR>,1:1]
[@2,6:9='text',<VAR>,1:6]
[@3,11:12='${',<'${'>,1:11]
[@4,13:20='variable',<VAR>,1:13]
[@5,21:21='.',<'.'>,1:21]
[@6,22:25='name',<VAR>,1:22]
[@7,26:26='}',<'}'>,1:26]
... shortened ...
[@26,85:84='<EOF>',<EOF>,2:0]

这告诉您,您打算成为模板字符串文字*的一些实际上被lexed为VAR。为什么会这样?

如本答案所述,antlr使用尽可能长的匹配来创建令牌。由于您的TemplateStringLitald规则只匹配单个字符,但您的VAR规则匹配无限多,lexer显然使用后者来匹配一些

您可以尝试如下方式修改规则:

TemplateStringLiteral: ('\\`' | ~'`')+ ;

因此,它可以捕获多个字符,因此是首选。这有两个不起作用的原因:

>

  • lexer如何将任何内容与VAR规则匹配?

    TemplateStringLiteral规则现在也与${匹配,因此禁止正确识别模板块的开头。

    可能还有另一种解决方案,但这种方法有效:

    归档MartinCup。g4:

    parser grammar MartinCup;
    
    options { tokenVocab=MartinCupLexer; }
    
    templateString
        : BackTick TemplateStringLiteral* (template TemplateStringLiteral*)+ BackTick
        ;
    
    template
        : TemplateStart variable TemplateEnd
        ;
    
    variable
        : varname funParameter? (Dot variable)*
        ;
    
    varname
        : VAR
        ;
    
    funParameter
        : OpenPar variable? (Comma variable)* ClosedPar
        ;
    

    文件MartinCupLemus. g4:

    lexer grammar MartinCupLexer;
    
    BackTick : '`' ;
    
    TemplateStart
        : '${' -> pushMode(templateMode)
        ;
    
    TemplateStringLiteral
        : '\\`'
        | ~'`'
        ;
    
    mode templateMode;
    
    VAR
        : [$]?[a-zA-Z0-9_]+
        | [$]
        ;
    
    OpenPar : '(' ;
    ClosedPar : ')' ;
    Comma : ',' ;
    Dot : '.' ;
    
    TemplateEnd
        : '}' -> popMode;
    

    此语法使用lexer模式来区分花括号的内部和外部。VAR规则现在仅在遇到${之后处于活动状态,并且仅在读取}之前保持活动状态。因此,它不会捕获非模板文本,例如一些

    请注意,lexer模式的使用需要html" target="_blank">拆分语法(解析器和lexer语法的单独文件)。因为解析器语法中不允许使用lexer规则,所以我不得不为括号、逗号、点和反勾号引入标记。

    我假设您希望在“普通文本”中保留空格,但不允许模板中出现空格。因此,我简单地删除了WS规则。如果您愿意,您可以随时重新添加它。

    我测试了您的替代语法,您将TemplateStringLiteral置于WS之上,但与您的观察相反,这给了我:

    第1:1行无关输入“一些”,期待 {'${', TemplateStringLitald}

    原因与上述相同,Some被lexed为VAR

  •  类似资料:
    • 我正在使用拆分一个字符串。我收到的字符串有这样的结构: 其中<代码> 除非是空字符串,否则这可以正常工作。在这种情况下,只会跳过数据。 我想要一个字符串,如<代码>[数据] 我该怎么做?

    • 问题内容: 我刚刚开始探索Elasticsearch。我创建了一个文档,如下所示: 我现在尝试对Levenshtein距离为5的名称字段进行模糊搜索,如下所示: 但是它没有返回任何匹配。我希望圣路易斯的记录能归还。我该如何解决我的查询? 谢谢。 问题答案: 您的查询存在的问题是,最大编辑距离为2。 在上述情况下,您可能想要做的是将St.改为Saint 的同义词,这将与您匹配。当然,这将取决于您的数

    • 问题内容: 我在这里的研究中得到了不同的答案。 有人可以验证Redis服务器只能存储任何数值的表示吗? 例如,如果我在lpush中使用具有双重类型的Java客户端(Jedis),在发送给Redis之前是否需要将其转换为等效于字符串类型的内容? 还是有一种方法可以发送诸如double之类的实际数字类型?如果是这样,是否有任何示例代码说明了如何实现此目的? 谢谢 问题答案: Redis将所有内容存储在

    • Kotlin有一个很好的特性,叫做字符串模板。我真的很喜欢。 但是否可以在模板中设置任何格式?例如,我想在kotlin中设置字符串模板中的Double格式,至少要在小数分隔符后设置一些位数:

    • 问题内容: 我正在处理长度为25的DNA序列(请参见下面的示例)。我有一个230,000的列表,需要查找整个基因组中的每个序列(弓形虫寄生虫)。我不确定基因组有多大,但是比230,000个序列长得多。 我需要查找25个字符的每个序列,例如()。 基因组被格式化为连续字符串,即() 我不在乎它在哪里或被发现多少次,无论它是否存在。 我认为这很简单- 但是我也要找到一个在任何位置(只有一个位置)被定义

    • 我一直在捕捉非数字时遇到问题。 我试过了,但抓不住。如果我让它捕获非数字,但不让用户再次尝试输入。。。它完全停止了我的代码。 这是我的密码: