我是Antlr的新手
由于要迁移到Java 8,因此我必须将antlrv3代码从3.2迁移到3.5.2。
我的antlr语法没有任何变化,可以完美地与3.2版和Java 7(目标Java 6)一起使用
对于3.tl maven版本3.5.2,生成如下编译错误:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.7.0:compile (default-compile) on project ccff-sql2xpath: Compilation failure: Compilation failure:
[ERROR] /C:/ProjectSVN/JSR170/ccff-sql2xpath/target/generated-sources/antlr3/sql2xpath/query/compiler/TParser.java:[262,73] cannot find symbol
[ERROR] symbol: variable props
[ERROR] location: variable p of type org.antlr.runtime.ParserRuleReturnScope
我认为antlr v3.5.2生成代码的方式已经发生了一些变化,因为在生成的TParser.java
中,我有超过77600行,而旧版本的antlr只有'3181行'文件
你能帮我吗?
这是解析器语法:
parser grammar TParser;
options {
language = Java;
output = AST;
superClass = AbstractTParser;
tokenVocab = TLexer;
}
@header {
package sql2xpath.query.compiler;
import sql2xpath.query.xpath.XPathException;
import sql2xpath.query.xpath.constraint.TemporaryPathConstraint;
}
//=============================================================================
query
: s=select (f=from)? (w=where)? (o=orderby)? EOF;
//=============================================================================
select
: SELECT^ p=proplist {
for (String o: ((List<String>) p.props)) {
composer.getColumnSpecifier().addProperty(o);
}
};
//=============================================================================
from returns[String res = "unknown"]
: FROM^ n=ntlist {
if (n.nodetypes.size() > 1)
throw new XPathException("Unable to deal with joined tables in FROM clause");
composer.getPathConstraint().setTypeName(toCompactStringTree(n.nodetypes.get(0)));
};
//=============================================================================
where returns[String res = "unknown"]
: WHERE^ o=orexpression[true] {
if (o.res != null) {
// System.out.println("add constraint: " + o.res);
composer.getPropertyConstraint().addConstraint(o.res);
}
};
//=============================================================================
orderby returns[String res = "unknown"]
: (ORDER BY)^ p=propname d=(DESC | ASC)? {
if (d == null)
composer.getOrderingSpecifier().addProperty(p.res, null);
else if (d.getType() == ASC)
composer.getOrderingSpecifier().addProperty(p.res, "ascending");
else
composer.getOrderingSpecifier().addProperty(p.res, "descending");
} (COMA q=propname e=(DESC | ASC)? {
if (e == null)
composer.getOrderingSpecifier().addProperty(q.res, null);
else if (e.getType() == ASC)
composer.getOrderingSpecifier().addProperty(q.res, "ascending");
else
composer.getOrderingSpecifier().addProperty(q.res, "descending");
})* ;
//=============================================================================
proplist returns[Object props]
@init{
List<String> l = new ArrayList<String>();
}
: a=propname { l.add(a.res); } (COMA b=propname { l.add(b.res); })* { $props = l; };
//=============================================================================
ntlist returns[List nodetypes]
: c+=complexpropname (COMA c+=complexpropname)* { $nodetypes = $c; };
//=============================================================================
orexpression[boolean b] returns[String res = null]
@init{
List<String> l = new ArrayList<String>();
List<Object> p = new ArrayList<Object>();
}
: a=andexpression[b] {
p.addAll(((List<Object>)(((Object []) a.res)[1])));
l.add((String)(((Object []) a.res)[0]));
} (OR^ c=andexpression[b] {
p.addAll(((List<Object>)(((Object []) c.res)[1])));
l.add((String)(((Object []) c.res)[0]));
})* {
StringBuffer sb = new StringBuffer();
for (String s: l)
if (s!=null)
sb.append(s + " or ");
if (sb.length() > 0)
$res = sb.substring(0,sb.length()-4);
if (p.size() > 2)
throw new XPathException("Unable to deal with more than two path constraints");
else if (p.size() == 2) {
if (!$b)
throw new XPathException("Cannot deal with negated or clauses");
TemporaryPathConstraint pc1 = (TemporaryPathConstraint) p.get(0);
TemporaryPathConstraint pc2 = (TemporaryPathConstraint) p.get(1);
//LOGGER.debug("Found or-ed constraints on jcr:path = " + pc1.path + " OR " + pc2.path);
if (pc1.b && pc2.b) {
composer.getPathConstraint().orConstraint(pc1.path, pc2.path);
} else
throw new XPathException("Only positive path constraints can be in the same or clause");
}else if (p.size() == 1) {
if (!$b)
throw new XPathException("Cannot deal with single negated path constraint");
TemporaryPathConstraint pc1 = (TemporaryPathConstraint) p.get(0);
//LOGGER.debug("Found single constraint on jcr:path = " + pc1.path);
if (pc1.b) {
composer.getPathConstraint().singleConstraint(pc1.path);
} else {
throw new XPathException("Cannot deal with negative single path constraints");
}
}
};
//=============================================================================
andexpression[boolean b] returns[Object res = null]
@init{
List<String> l = new ArrayList<String>();
List<Object> p = new ArrayList<Object>();
String k = null;
}
: a=notexpression[b] { if (a.res instanceof TemporaryPathConstraint) p.add(a.res); else l.add((String)a.res); } (AND^ c=notexpression[b] { if (c.res instanceof TemporaryPathConstr
StringBuffer sb = new StringBuffer();
for (String s: l)
if (s!=null)
sb.append(s + " and ");
if (sb.length() > 0)
k = sb.substring(0,sb.length()-5);
if (p.size() > 2)
throw new XPathException("Unable to deal with more than two path constraints");
else if (p.size() == 2) {
if (!$b)
throw new XPathException("Cannot deal with negated and clauses");
TemporaryPathConstraint pc1 = (TemporaryPathConstraint) p.get(0);
TemporaryPathConstraint pc2 = (TemporaryPathConstraint) p.get(1);
//LOGGER.debug("Found and-ed constraints on jcr:path = " + pc1.path + " AND " + pc2.path);
if (pc1.b && !pc2.b) {
composer.getPathConstraint().andNotConstraint(pc1.path, pc2.path);
} else if (pc2.b && !pc1.b) {
composer.getPathConstraint().andNotConstraint(pc2.path, pc1.path);
} else
throw new XPathException("Only one positive and one negative path constraint can be in the same and clause");
p.clear();
}
$res = new Object [] {k, p};
};
//=============================================================================
notexpression[boolean b] returns[Object res = null]
: NOT^ d=containsexpression[false] { if (!$b) throw new XPathException("Impossible to parse nested NOT operators"); $res = d.res;}
| c=containsexpression[b] {$res = c.res; };
//=============================================================================
containsexpression[boolean b] returns[Object res = null]
: c=containsfun[b] { $res = c.res; }
| v=value IN p=propname { $res = composer.getPropertyConstraint().getComparingConstraint(p.res, "=", v.res, b); }
| o=operatorexpression[b] { $res = o.res; };
//=============================================================================
operatorexpression[boolean b] returns[Object res = null]
: p=propname o=op v=value {
if ("jcr:path".equals(p.res))
if (!"=".equals(o.res))
throw new XPathException("Impossible to use other operator than \"=\" or \"LIKE\" with jcr:xpath property");
else {
TemporaryPathConstraint tpc = new TemporaryPathConstraint(TemporaryPathConstraint.EQUAL);
tpc.path = v.res;
tpc.b = $b;
$res = tpc;
}
//composer.getPathConstraint().addConstraintAndProcess(v.res, b, false);
else
$res = composer.getPropertyConstraint().getComparingConstraint(p.res, o.res, v.res, b);
}
| p=propname IS NULL { $res = composer.getPropertyConstraint().getIsNullConstraint(p.res, b); }
| p=propname IS NOT NULL { $res = composer.getPropertyConstraint().getIsNotNullConstraint(p.res, b); }
| l=like[b] { $res = l.res; }
| t=parentexpression[b] { $res = t.res; };
//=============================================================================
op returns[String res = "unknown"]
: EQ { $res = "="; }
| NEQ { $res = "!="; }
| LEQ { $res = "<="; }
| LES { $res = "<"; }
| GEQ { $res = ">="; }
| GRE { $res = ">"; };
//=============================================================================
parentexpression[boolean b] returns[String res = "unknown"]
: LEFT_PAREN o=orexpression[b] RIGHT_PAREN { $res = "(" + o.res + ")"; };
//=============================================================================
propname returns[String res = "unknown"]
: QUOT c=complexpropname QUOT { $res = $c.res; }
| c=complexpropname { $res = $c.res; };
//=============================================================================
complexpropname returns[String res = "unknown"]
: a=simplepropname (DOT b=simplepropname)? {$res = a.res; if (b != null) $res += "." + b.res;};
//=============================================================================
simplepropname returns[String res = "unknown"]
: a=identifier (COLON b=identifier)? {$res = a.res; if (b != null) $res += ":" + b.res;};
//=============================================================================
identifier returns[String res = "unknown"]
: nq=NonQuotedIdentifier { $res = $nq.getText(); }
| q=QuotedIdentifier { $res = q.getText(); }
| l=Letter { $res = l.getText(); }
| STAR { $res = "*"; };
//=============================================================================
value returns[String res = "value"]
: x=complexpropname { $res = x.res; }
| c=constant { $res = c.res; };
//=============================================================================
like[boolean b] returns[Object res = null]
: p=propname LIKE e=expression (c = escape)? {
if ("jcr:path".equals(p.res)) {
TemporaryPathConstraint tpc = new TemporaryPathConstraint(TemporaryPathConstraint.LIKE);
tpc.path = e.res;
tpc.b = $b;
$res = tpc;
// composer.getPathConstraint().addConstraintAndProcess(((c == null) ? e.res : e.res.replaceAll(c.res, "\\" + c.res)), $b, false);
} else
$res = composer.getPropertyConstraint().getLikeConstraint(p.res, ((c == null) ? e.res : e.res.replaceAll(c.res, "\\" + c.res)), $b);
};
//=============================================================================
escape returns[String res = "escape"]
: ESCAPE e=expression { $res = e.res; };
//=============================================================================
expression returns[String res = "expression"]
: (u=unaryOperator)? c=constant { $res = ((u!=null)?u.res:"") + c.res; };
//=============================================================================
unaryOperator returns[String res = "unaryOperator"]
: MINUS { $res = "-"; };
//=============================================================================
constant returns[String res = "constant"]
: Number { $res = $Number.getText(); }
| NULL { $res = $NULL.getText(); }
| s=stringLiteral { $res = s.res; }
| Currency { $res = $Currency.getText(); }
| ODBCDateTime { $res = $ODBCDateTime.getText(); };
//=============================================================================
stringLiteral returns[String res = "stringLiteral"]
: UnicodeStringLiteral { $res = $UnicodeStringLiteral.getText(); }
| ASCIIStringLiteral { $res = $ASCIIStringLiteral.getText(); };
//=============================================================================
containsfun[boolean b] returns[String res = "containsfun"]
: CONTAINS_FUN c=containscope COMA e=expression RIGHT_PAREN {
$res = composer.getPropertyConstraint().getContainsConstraint(c.res, e.res, b);
};
//=============================================================================
containscope returns[String res = "containscope"]
: c=complexpropname { $res = c.res; }
| DOT { $res = "."; };
这是方法的代码,错误在哪里:
// $ANTLR start "select"
// be\\fgov\\minfin\\ccff\\jcr2\\sql2xpath\\query\\compiler\\TParser.g:27:4: select : SELECT ^p= proplist ;
public final TParser.select_return select() throws RecognitionException {
TParser.select_return retval = new TParser.select_return();
retval.start = input.LT(1);
Object root_0 = null;
Token SELECT2=null;
ParserRuleReturnScope p =null;
Object SELECT2_tree=null;
try {
// sql2xpath\\query\\compiler\\TParser.g:28:5: ( SELECT ^p= proplist )
// sql2xpath\\query\\compiler\\TParser.g:28:7: SELECT ^p= proplist
{
root_0 = (Object)adaptor.nil();
SELECT2=(Token)match(input,SELECT,FOLLOW_SELECT_in_select186);
SELECT2_tree = (Object)adaptor.create(SELECT2);
root_0 = (Object)adaptor.becomeRoot(SELECT2_tree, root_0);
pushFollow(FOLLOW_proplist_in_select191);
p=proplist();
state._fsp--;
adaptor.addChild(root_0, p.getTree());
for (String o: ((List<String>) p.props)) { // <=====[ERROR]
composer.getColumnSpecifier().addProperty(o);
}
}
retval.stop = input.LT(-1);
retval.tree = (Object)adaptor.rulePostProcessing(root_0);
adaptor.setTokenBoundaries(retval.tree, retval.start, retval.stop);
}
catch (RecognitionException re) {
reportError(re);
recover(input,re);
retval.tree = (Object)adaptor.errorNode(input, retval.start, input.LT(-1), re);
}
finally {
// do for sure before leaving
}
return retval;
}
// $ANTLR end "select"
答案 0 :(得分:0)
我想我理解编译错误:
ParserRuleReturnScope类型的p属性使用一种方法初始化,该方法返回proplist_return类型的类并扩展ParserRuleReturnScope类。
ParserRuleReturnScope p =null;
...
p=proplist(); // (proplist_return extend ParserRuleReturnScope)
...
for (String o: ((List<String>) p.props)) { // <=====[COMPILATION ERROR]
由于类prolist_return是ParserRuleReturnScope的子类,因此必须在搜索子类中包含的属性之前将p强制转换,此处为props属性 像这样:
proplist_return castP = (proplist_return) p;
for (String o: ((List<String>) castP.props)) {
对于3.2版,该插件会生成无错误代码。在3.5.2版中,它会产生这些错误!
我了解导致编译错误的原因。
实际上ANTLR的3.5.2版更加严格,在语法antlr中规则“ select”的操作部分,我忘记了引用变量p并在前面加上了$。这就是为什么生成器不转换我的类的原因(请参见上面的评论) 错误的语法是:
select
: SELECT^ p=proplist {
for (String o: ((List<String>) p.props)) {
composer.getColumnSpecifier().addProperty(o);
}
};
解决方案是:
select
: SELECT^ p=proplist {
for (String o: ((List<String>) $p.props)) {
composer.getColumnSpecifier().addProperty(o);
}
};