使用 setText 更改 antlr4 中的规则文本
changing text of rule in antlr4 using setText
我想将 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,还有其他替代文本的方法吗?
tl;dr:
给定以下语法(源自原始 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
测试数据(刚刚重命名的 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 下面的评论:如果语法定义正确,setText()
将在 lexer java 模块中生成。不幸的是,为像我这样的业余爱好者调试 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" 不是必需的,而只是调试 hack)。
并引用 http://www.antlr.org/support.html :
ANTLR 讨论
Please do not start discussions at Whosebug. They have asked us to
steer discussions (i.e., non-questions/answers) away from Whosebug; 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.
希望对您有所帮助。
这里有几个问题:
首先,要识别接收者的setText
方法。大概想要
field : TEXT { $TEXT.setText("BlahBlah"); }
| STRING
;
其次是setText
没有在Token
class中定义。
通常,创建您自己的令牌 class 扩展 CommonToken
和相应的令牌工厂 class。将 TokenLableType
(在选项块中)设置为您的令牌 class 名称。 CommonToken
中的 setText
方法将可见。
我想将 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,还有其他替代文本的方法吗?
tl;dr:
给定以下语法(源自原始 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
测试数据(刚刚重命名的 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 下面的评论:如果语法定义正确,setText()
将在 lexer java 模块中生成。不幸的是,为像我这样的业余爱好者调试 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" 不是必需的,而只是调试 hack)。
并引用 http://www.antlr.org/support.html :
ANTLR 讨论
Please do not start discussions at Whosebug. They have asked us to
steer discussions (i.e., non-questions/answers) away from Whosebug; 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.
希望对您有所帮助。
这里有几个问题:
首先,要识别接收者的setText
方法。大概想要
field : TEXT { $TEXT.setText("BlahBlah"); }
| STRING
;
其次是setText
没有在Token
class中定义。
通常,创建您自己的令牌 class 扩展 CommonToken
和相应的令牌工厂 class。将 TokenLableType
(在选项块中)设置为您的令牌 class 名称。 CommonToken
中的 setText
方法将可见。