ANTLR API问题;提供示例+解决方法;需要解释说明。

3

我使用ANTLRWorks创建了以下Lexer。(另见http://bkiers.blogspot.com/2011/03/2-introduction-to-antlr.html#intro)

 // CSVLexer.g
 lexer grammar CSVLexer;

 @lexer::header {
   package graphica.parsers;
 }

 Comma   
   :  ','  
   ;  

 LineBreak  
  :  '\r'? '\n'  
  |  '\r'  
  ;  

 SimpleValue  
   :  ~(',' | '\r' | '\n' | '"')+  
   ;  

 QuotedValue  
   :  '"' ('""' | ~'"')* '"'  
   ;  

我使用以下Java类来测试Lexer。

 /**
  *
  * @author Nilo
  */
 import org.antlr.runtime.*;

 public class CSVLexerTest {

 public static void main(String[] args) throws Exception {
    // the input source  
    String source =
            "val1, value2, value3, value3.2" + "\n"
            + "\"line\nbreak\",ABAbb,end";

    // create an instance of the lexer  
    CSVLexer lexer = new CSVLexer(new ANTLRStringStream(source));
    // wrap a token-stream around the lexer  
    CommonTokenStream tokens = new CommonTokenStream(lexer);


    // traverse the tokens and print them to see if the correct tokens are created
    // tokens.toString();
    int n = 1;
    for (Object o : tokens.getTokens()) {
        CommonToken token = (CommonToken) o;
        System.out.println("token(" + n + ") = " + token.getText().replace("\n",    "\\n"));
        n++;
    }
 }
 }

上面的类(来自同一教程)不会产生任何输出。但是,如果我在令牌循环之前插入tokens.toString(),则可以按预期打印输出。

注意:我在Windows 7上使用ANTLRWorks 1.4.3、ANTLR 3.4和JDK 1.7/64位。

问题:我不明白这个。请解释一下。应该有一种方法可以使它正常工作而不需要tokens.toString()


自ANTLR 3.2以来发生了变化(它与ANTLR 3.2一起工作)。请参见教程的下一部分中的注释:http://bkiers.blogspot.com/2011/03/3-lexical-analysis-of-tl.html 如果我找到了变化的内容,我会在这里发布(不过不要抱太大希望!:))。 - Bart Kiers
@BartKiers - 这个解决方法虽然可行,但感觉不太好。非常感谢您的教程,它是最好的。(我也有Terence Parr的两本书) - nilo de roock
1
我完全同意这种感觉不对。这就是为什么我想深入源代码,看看自从3.3版本以来为什么会出现这种情况。但每当我有几个空闲小时时,总会有更重要的事情要做... :)。正如我所说,无论何时我找到答案,我都会在这里报告。谢谢你的好话! - Bart Kiers
当然,我不能就此罢休!:) 请看我的回答。 - Bart Kiers
1个回答

3

CommonTokenStream继承自BufferedTokenStream,它有一个List<Token> tokens,当调用getTokens()时返回。但是这个List<Token> tokens只会在特定的时间填充。在3.3和3.4版本中,在调用getTokens()后不会发生这种情况,而在3.2版本中,tokens列表会被填充。

ANTLR 3.2(及以前版本)

public List getTokens() {
    if ( p == -1 ) {
        fillBuffer();
    }
    return tokens;
}

protected void fillBuffer() {
    // fill `tokens`
}

ANTLR 3.3 (and after)

public List getTokens() { 
    return tokens; 
}

public void fill() {
    // fill `tokens`
}

请注意,3.2版本的fill方法是受保护的,而在3.3及以上版本中是公共的,因此以下代码可以正常工作:
import org.antlr.runtime.*;

public class CSVLexerTest {

  public static void main(String[] args) throws Exception {

    // the input source  
    String source =
        "val1, value2, value3, value3.2" + "\n" + 
        "\"line\nbreak\",ABAbb,end";

    // create an instance of the lexer  
    CSVLexer lexer = new CSVLexer(new ANTLRStringStream(source));

    // wrap a token-stream around the lexer and fill the tokens-list 
    CommonTokenStream tokens = new CommonTokenStream(lexer);
    tokens.fill();

    // traverse the tokens and print them to see if the correct tokens are created
    // tokens.toString();
    int n = 1;
    for (Object o : tokens.getTokens()) {
      CommonToken token = (CommonToken) o;
      System.out.println("token(" + n + ") = " + token.getText().replace("\n",    "\\n"));
      n++;
    }
  }
}

生成输出:
token(1) = val1
token(2) = ,
token(3) =  value2
token(4) = ,
token(5) =  value3
token(6) = ,
token(7) =  value3.2
token(8) = \n
token(9) = "line\nbreak"
token(10) = ,
token(11) = ABAbb
token(12) = ,
token(13) = end
token(14) = <EOF>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接