使用setText

时间:2016-05-30 12:20:54

标签: parsing grammar antlr4

我想将csv文件中的每个条目都更改为“BlahBlah” 为此,我有antlr语法

grammar CSV;

file : hdr row* row1;
hdr : row;

row :  field (',' value1=field)* '\r'? '\n'; // '\r' is optional at the end of a row of CSV file ..

row1 :  field (',' field)* '\r'? '\n'?;

field 
      :  TEXT
    {
        $setText("BlahBlah");
    }
      |  STRING 
      | 
      ;
TEXT : ~[,\n\r"]+ ;
STRING : '"' ('""' | ~'"')* '"' ;

但是当我在antlr4上运行时

error(63): CSV.g4:13:3: unknown attribute reference setText in $setText
make: *** [run] Error 1

为什么antlr4不支持setText,还有其他替换文本吗?

2 个答案:

答案 0 :(得分:2)

<强> TL;博士

鉴于以下语法(源自原始CSV.g4样本和OP的语法尝试(参见问题)):

grammar CSVBlindText;

@header {
import java.util.*;
}

/** Derived from rule "file : hdr row+ ;" */
file
locals [int i=0]
     : hdr ( rows+=row[$hdr.text.split(",")] {$i++;} )+
       {
       System.out.println($i+" rows");
       for (RowContext r : $rows) {
           System.out.println("row token interval: "+r.getSourceInterval());
       }
       }
     ;

hdr : row[null] {System.out.println("header: '"+$text.trim()+"'");} ;

/** Derived from rule "row : field (',' field)* '\r'? '\n' ;" */
row[String[] columns] returns [Map<String,String> values]
locals [int col=0]
@init {
    $values = new HashMap<String,String>();
}
@after {
    if ($values!=null && $values.size()>0) {
        System.out.println("values = "+$values);
    }
}
// rule row cont'd...
    :   field
        {
        if ($columns!=null) {
            $values.put($columns[$col++].trim(), $field.text.trim());
        }
        }
        (   ',' field
            {
            if ($columns!=null) {
                $values.put($columns[$col++].trim(), $field.text.trim());
            }
            }
        )* '\r'? '\n'
    ;

field
    : TEXT
    | STRING
    |
    ;

TEXT : ~[',\n\r"]+ {setText( "BlahBlah" );} ;
STRING : '"' ('""'|~'"')* '"' ; // quote-quote is an escaped quote

一个人:

$> antlr4 -no-listener CSVBlindText.g4
$> grep setText CSVBlindText*java
CSVBlindTextLexer.java:         setText( "BlahBlah" );

编译它完美无瑕:

$> javac CSVBlindText*.java

Testdata(刚重命名的users.csv文件):

$> cat blinded_by_grammar.csv 
User,  Name,    Dept
parrt, Terence, 101
tombu, Tom,     020
bke, Kevin,     008

测试中的收益率:

$> grun CSVBlindText file blinded_by_grammar.csv 
header: 'BlahBlah,BlahBlah,BlahBlah'
values = {BlahBlah=BlahBlah}
values = {BlahBlah=BlahBlah}
values = {BlahBlah=BlahBlah}
3 rows
row token interval: 6..11
row token interval: 12..17
row token interval: 18..23

所以看起来setText()应该在生产的分号之前注入,而不是在替代品之间注入(在这里疯狂猜测; - )

以前的迭代

只是猜测,因为我1)目前没有可用的antlr4和2)现在没有写ANTLR4语法很长一段时间 - 也许没有美元($)?

grammar CSV;

file : hdr row* row1;
hdr : row;

row :  field (',' value1=field)* '\r'? '\n'; // '\r' is optional at the end of a row of CSV file ..

row1 :  field (',' field)* '\r'? '\n'?;

field 
      :  TEXT
    {
        setText("BlahBlah");
    }
      |  STRING 
      | 
      ;
TEXT : ~[,\n\r"]+ ;
STRING : '"' ('""' | ~'"')* '"' ;

更新:现在有一个antlr 4.5.2(至少通过brew)而不是4.5.3可用,我深入研究并回答了OP下面的一些评论:如果语法定义良好,将在lexer java模块中生成setText()。不幸的是,像我一样调试antlr4语法是......但是非常好的语言构建工具包IMO。

示例会话:

$> antlr4 -no-listener CSV.g4 
$> grep setText CSVLexer.java 
            setText( String.valueOf(getText().charAt(1)) );

使用的语法: (通过以下方式检索的示例代码中被攻击:

curl -O http://media.pragprog.com/titles/tpantlr2/code/tpantlr2-code.tgz

grammar CSV;

@header {
import java.util.*;
}

/** Derived from rule "file : hdr row+ ;" */
file
locals [int i=0]
     : hdr ( rows+=row[$hdr.text.split(",")] {$i++;} )+
       {
       System.out.println($i+" rows");
       for (RowContext r : $rows) {
           System.out.println("row token interval: "+r.getSourceInterval());
       }
       }
     ;

hdr : row[null] {System.out.println("header: '"+$text.trim()+"'");} ;

/** Derived from rule "row : field (',' field)* '\r'? '\n' ;" */
row[String[] columns] returns [Map<String,String> values]
locals [int col=0]
@init {
    $values = new HashMap<String,String>();
}
@after {
    if ($values!=null && $values.size()>0) {
        System.out.println("values = "+$values);
    }
}
// rule row cont'd...
    :   field
        {
        if ($columns!=null) {
            $values.put($columns[$col++].trim(), $field.text.trim());
        }
        }
        (   ',' field
            {
            if ($columns!=null) {
                $values.put($columns[$col++].trim(), $field.text.trim());
            }
            }
        )* '\r'? '\n'
    ;

field
    : TEXT
    | STRING
    | CHAR
    |
    ;

TEXT : ~[',\n\r"]+ ;
STRING : '"' ('""'|~'"')* '"' ; // quote-quote is an escaped quote

/** Convert 3-char 'x' input sequence to string x */
CHAR:   '\'' . '\'' {setText( String.valueOf(getText().charAt(1)) );} ;

编译工作:

$> javac CSV*.java

现在使用匹配的奇怪csv文件进行测试:

a,b
"y",'4'

如:

$> grun CSV file foo.csv
line 1:0 no viable alternative at input 'a'
line 1:2 no viable alternative at input 'b'
header: 'a,b'
values = {a="y", b=4}
1 rows
row token interval: 4..7

总而言之,我建议重写语法的逻辑(我认为插入“BlahBlahBlah”不是必要的,而只是调试黑客)。

并引用http://www.antlr.org/support.html

ANTLR讨论

Please do not start discussions at stackoverflow. They have asked us to 
steer discussions (i.e., non-questions/answers) away from Stackoverflow; we 
have a discussion forum at Google specifically for that:

https://groups.google.com/forum/#!forum/antlr-discussion

We can discuss ANTLR project features, direction, and generally argue about 
whatever we want at the google discussion forum.

我希望这会有所帮助。

答案 1 :(得分:2)

这里有几个问题:

首先,必须识别field : TEXT { $TEXT.setText("BlahBlah"); } | STRING ; 方法的接收者。可能想要

setText

其次,Token类中未定义CommonToken

通常,创建自己的扩展TokenLableType和相应令牌工厂类的令牌类。将setText(在选项块中)设置为您的令牌类名称。然后,CommonToken中的AssignFile(myFile, 'Test.txt'); Reset(myFile); while not Eof(myFile) do begin ReadLn(myFile, text); Richedit.lines.add(myFile); end; CloseFile(myFile); end; 方法将可见。