0

当我使用这些规则获得令牌时

STRINGA :   '"' (options {greedy=false;}: ESC | .)* '"';
STRINGB :   '\'' (options {greedy=false;}: ESC | .)* '\'';

它最终抓住'text'而不是仅仅text。我可以很容易地删除'and'我自己但想知道如何让 ANTLR 删除它?

4

2 回答 2

1

一种方法是将字符串内容定义为单独的类别,例如

STRINGA : '"' STRINGCONTENTS '"';
STRINGB : '\'' STRINGCONTENTS '\'';

然后捕获 STRINGCONTENTS 值。

于 2012-07-10T03:32:06.607 回答
1

您将需要一些自定义代码。此外,您不应该在规则中使用.(点):您应该明确定义要匹配反斜杠(假设这是您的ESQ开头)、引号换行符之外的所有内容。

这样的事情会做到这一点:

grammar T;

parse
 : STRING EOF {System.out.println($STRING.text);}
 ;

STRING
 : '"' (ESQ | ~('"' | '\\' | '\r' | '\n'))* '"'
   {
     String matched = getText();
     StringBuilder builder = new StringBuilder();

     for(int i = 1; i < matched.length() - 1; i++) {
       char ch = matched.charAt(i);
       if(ch == '\\') {
         i++;
         ch = matched.charAt(i);
         switch(ch) {
           case 'n': builder.append('\n'); break;
           case 't': builder.append('\t'); break;
           default: builder.append(ch); break;
         }
       }
       else {
         builder.append(ch);
       }
     }

     setText(builder.toString());
   }
 ;

fragment ESQ
 : '\\' ('n' | 't' | '"' | '\\')
 ;

如果您现在解析 input "tabs:'\t\t\t'\nquote:\"\nbackslash:\\",控制台将打印以下内容:

标签:''
引用:”
反斜杠:\

为了保持语法简洁,您当然可以在自定义方法中移动代码:

grammar T;

@lexer::members {
  private String fix(String str) {
    ...
  }
}

parse
 : STRING EOF {System.out.println($STRING.text);}
 ;

STRING
 : '"' (ESQ | ~('"' | '\\' | '\r' | '\n'))* '"' {setText(fix(getText()));}
 ;

fragment ESQ
 : '\\' ('n' | 't' | '"' | '\\')
 ;
于 2012-07-10T06:47:26.293 回答