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

antlr语法:Lexer匹配“不可能”规则

杜哲彦
2023-03-14

我得到了这个解析器语法,我还想用它来使用类似于Javascript模板的东西-字符串。

parser grammar Test;

options {
  tokenVocab = TestLexer;
}

definition: sourceElements? EOF ;

sourceElements: sourceElement+ ;

sourceElement: mapping ;


templateString: '`' TemplateStringCharacter* ('${' variable '}' TemplateStringCharacter*)+ '`' ;
fieldName: varname | ('[' value ']') ;
mapping: fieldName ':' ( '{' sourceElements '}'
      | variable ( '{' sourceElements '}' )? '?'?
      | value
      | array )
      ;

funParameter: '(' value? (',' value)*  ')' ;
array: '[' value? (',' value)* ']';
variable: (varname | '{' value '}' | '[' boolEx ']' | templateString) funParameter? ('.' variable)* ;
value: INT | BOOL | FLOAT | STRING | variable ;
varname: VAR ;

这个lexer语法

lexer grammar TestLexer;

WS : [ \t\r\n\u000C]+ -> skip ;
NEWLINE : [\r\n] ;
BOOL : ('true'|'false') ;
TemplateStringLiteral : TemplateStringCharacter*;
VAR : [$]?[a-zA-Z0-9_]+|[@] ;
INT : '-'?[0-9]+ ;
FLOAT : '-'?[0-9]+'.'[0-9]+ ;
STRING : '"' DoubleStringCharacter* '"' | '\'' SingleStringCharacter* '\'' ;
TEMPSTART : '${' ;
TEMPEND : '}' ;

TemplateStart : '`' -> pushMode(template) ;

/// Comments
MultiLineComment : '/*' .*? '*/' -> channel(HIDDEN) ;
SingleLineComment : '//' ~[\r\n\u2028\u2029]* -> channel(HIDDEN) ;

mode template;
TemplateVariableStart: TEMPSTART -> pushMode(templateVariable);
TemplateStringLiteral : TemplateStringCharacter* ;
TemplateEnd : '`' -> popMode;

mode templateVariable;
WS : [ \t\r\n\u000C]+ -> skip ;
All : [^}]+ ;
TemplateVariableEnd : TEMPEND -> popMode;

fragment DoubleStringCharacter : ~["\r\n] ;
fragment SingleStringCharacter : ~['\r\n] ;
fragment TemplateStringCharacter : ~[`] ;
fragment DecimalDigit : [0-9] ;
test: {
  abc: `Hello World`
}
(definition 
  (sourceElements 
    (sourceElement 
      (statement 
        (mapping 
          (fieldName 
            (varname test)
          ) : { 
          (sourceElements
            (sourceElement
              (statement mapping)
            ) 
            (sourceElement
              (statement
                (mapping abc : `)
              )
            ) 
            (sourceElement 
              (statement mapping)
            ) 
            (sourceElement 
              (statement 
                (mapping Hello)
              )
            ) 
            (sourceElement 
              (statement
                (mapping World `)
              )
            )
          ) 
          }
        )
      )
    )
  ) 
  <EOF>
)

我不明白,为什么甚至可以匹配一些像空映射或像“world`”这样的映射,因为映射需要在中间有一个“:”。并且为什么规则模板字符串不匹配整个“Hello World”从一个滴答到另一个滴答?

编辑:

当我注意到Lexer没有被重新生成时,我得到了这样的错误:“不能为string literal innon-combined grammark:']'创建隐式标记”。所以我不得不将所有隐式声明移到Lexer语法中。所以我将代码更改为:

parser grammar Test;

options {
  tokenVocab = TestLexer;
}

definition: sourceElements? EOF ;

sourceElements: sourceElement+ ;

sourceElement: mapping ;

templateString: OpenBackTick TemplateStringLiteral* (TemplateVariableStart variable CloseBrace TemplateStringLiteral*)+ CloseBackTick ;
fieldName: varname | OpenBracket value CloseBracket ;
mapping: fieldName Colon (
      OpenBrace sourceElements CloseBrace
      | variable ( OpenBrace sourceElements CloseBrace )? IF?
      | value
      | array
    )
    ;

funParameter: OpenParen value? (Comma value)* CloseParen ;
array: OpenBracket value? (Comma value)* CloseBracket;
variable: (varname | OpenBrace value CloseBrace | templateString) funParameter? (Dot variable)* ;
value: INT | BOOL | FLOAT | STRING | variable ;
varname: VAR ;
lexer grammar TestLexer;

OpenBracket: '[';
CloseBracket: ']';
OpenParen: '(';
CloseParen: ')';
OpenBrace: '{' ;
CloseBrace: '}' ;
IF: '?' ;
AND: 'AND' ;
OR: 'OR';
LessThan: '<';
MoreThan: '>';
LessThanEquals:   '<=';
GreaterThanEquals:   '>=';
Equals: '=';
NotEquals: '!=';
IN: 'IN';
NOT: '!';
Colon: ':';
Dot: '.' ;
Comma: ',' ;
OpenBackTick : '`' -> pushMode(template) ;

WS : [ \t\r\n\u000C]+ -> skip ;
NEWLINE : [\r\n] ;
BOOL : ('true'|'false') ;
VAR : [$]?[a-zA-Z0-9_]+|[@] ;
INT : '-'?[0-9]+ ;
FLOAT : '-'?[0-9]+'.'[0-9]+ ;
STRING : '"' DoubleStringCharacter* '"' | '\'' SingleStringCharacter* '\'' ;

/// Comments
MultiLineComment : '/*' .*? '*/' -> channel(HIDDEN) ;
SingleLineComment : '//' ~[\r\n\u2028\u2029]* -> channel(HIDDEN) ;

mode template;
TemplateVariableStart: '${' -> pushMode(templateVariable);
CloseBackTick : '`' -> popMode;
TemplateStringLiteral: TemplateStringCharacter ;

mode templateVariable;
WHS : [ \t\r\n\u000C]+ -> skip ;
All : [^}]+ ;
TemplateVariableEnd : CloseBrace -> popMode;

fragment DoubleStringCharacter : ~["\r\n] ;
fragment SingleStringCharacter : ~['\r\n] ;
fragment TemplateStringCharacter : ~[`] ;
fragment DecimalDigit : [0-9] ;

共有1个答案

宗政鸿志
2023-03-14

默认模式下有两个lexer规则可以匹配backtick:bticktemplatestarttemplatestart将切换到template模式,但btick不会。因为btick在语法中是第一位的,所以它具有优先级。这意味着当lexer看到一个backtick时,它将生成一个btick令牌,而不切换模式。

要解决这个问题,每个模式应该只有一个lexer规则与一个backtick匹配,并且该规则应该改变模式。

我不明白,为什么甚至可以匹配一些像空映射或像“world`”这样的映射,因为映射需要在中间有一个“:”。

当输入包含语法错误时,生成的解析树可能包含实际上也无效的构造。当您的输入解析没有错误时,您将得到一个有意义的树。

 类似资料:
  • 我正在重新学习一些基本的Antlr,并尝试编写一个生成todo项的语法: 我遇到的问题是,有三个lexer规则特别“不匹配”,这取决于它们使用的上下文: 以下是我的完整语法以求清晰: 旁白:我知道还有其他奇怪的地方,比如一个事件的名称只能是一个单词,但我是在一次处理一个问题。

  • 我有一个antlr语法,它有多个与同一个单词匹配的词法规则。在词法分析过程中无法解决这个问题,但通过语法,它就变得毫不含糊了。 示例: 输入:<代码>1英寸(米) 单词“in”与lexer规则和匹配。 如何在保持语法文件可读性的同时解决此问题?

  • 现在我得到了:错误。 我知道我的输入被AND和TERM lexer规则匹配,但我希望能够指定TERM是除与AND规则匹配的内容之外的任何内容。

  • 查看文档,ANTLR2过去有一种叫做谓词法的东西,下面的例子是这样的(灵感来自Pascal): 在我看来,这实际上是规则开头的一个积极的前瞻性断言:如果前瞻性与匹配,那么第一个规则将被应用(并与该输入的部分匹配),依此类推。 我还没有在ANTLR4中找到这样的东西。2到3迁移指南似乎没有提到这一点,而3到4更改文档指出: ANTLR3和4之间最大的区别是ANTLR4接受您给出的任何语法,除非该语法

  • 我需要以下令牌: 允许的字符包括大写、小写、数字、空格和连字符 长度不固定(长度必须至少为两个字符) 标记必须至少包含一个空格或连字符 令牌必须以大写、小写、数字、空格或连字符开头和结尾(不能以空格开头或结尾) 下面语法中的ANTLR lexer规则“alphanumericspacehyphen”除了一个情况外几乎都起作用。使用解析器规则“sic”进行测试,以下输入将解析(不带引号): 以下输入