xtext 生成器表达式 getLeft 和 getRight
xtext generator expression getLeft and getRight
我正在尝试通过 Xtext 编写一个 DSL,我可以用它来自定义 SQL。
首先,我想要一个字符串表示形式来表示我的查询。
在那里,我陷入了表情。我在这个例子之后创建了它们:https://typefox.io/parsing-expressions-with-xtext.
Expression returns Expression:
OrExpression;
OrExpression returns Expression:
AndExpression ({OrExpression.left=current} name="OR" right=AndExpression)*;
AndExpression returns Expression:
NotExpression({AndExpression.left=current} name="AND" right=NotExpression)*;
NotExpression returns Expression:
ComparisonExpression({NotExpression.left=current} name='NOT' right=ComparisonExpression)*;
ComparisonExpression returns Expression:
BitwiseOR({ComparisonExpression.left=current} name=cmpop right=BitwiseOR)*;
BitwiseOR returns Expression:
BitwiseAND ({BitwiseOR.left=current} name='|' right=BitwiseAND)*;
BitwiseAND returns Expression:
BitwiseXOR ({BitwiseAND.left=current} name='&' right=BitwiseXOR)*;
BitwiseXOR returns Expression:
Addition ({BitwiseXOR.left=current} name='^' right=Addition)*;
Addition returns Expression:
Substraction ({Addition.left=current} name='+' right=Substraction)*;
Substraction returns Expression:
Multiplication ({Substraction.left=current} name='-' right=Multiplication)*;
Multiplication returns Expression:
Division ({Multiplication.left=current} name='*' right=Division)*;
Division returns Expression:
Modulo ({Division.left=current} name='/' right=Modulo)*;
Modulo returns Expression:
Primary ({Modulo.left=current} name='%' right=Primary)*;
Primary returns Expression:
=> count=count
| => func=funccall
| {Bracket} '(' inner=Expression ')'
| (name=unop) expr=Expression
| (name=unop)? ID=Literal ('IS' 'NOT'? 'NULL')?;
/*Values that a Expression can have */
Literal returns Expression:
value=values;
我可以设法获取单个值,但我无法获取表达式的左侧或右侧。
我的生成器(未完成,我的测试看起来像这样)
class TsqlGenerator extends AbstractGenerator {
StringBuilder st = new StringBuilder();
TimeConditionHandler tch = new TimeConditionHandler
ExpressionHandler exprH = new ExpressionHandler
String expression = ""
int fromIndex = 0;
int whereIndex
def clear() {
st.delete(0, st.length);
fromIndex = 0;
whereIndex =0;
}
override beforeGenerate(Resource input, IFileSystemAccess2 fsa, IGeneratorContext context) { clear() }
override void doGenerate(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) {
for (e : resource.allContents.toIterable.filter(ComplexSelect)) {
/*SELECT */
// TODO: String Value ohne Anführungszeichen?
st.append("SELECT ");
for (selectArgument : e.left.selectArguments.arguments) {
if (selectArgument.expr.name == null) {
//hier später in eine Liste speichern?
st.append(" " + selectArgument.expr.ID.value.name);
}else {
// TODO: Generate a Sting of the Expression!
}
}
/*FROM */
st.append(" FROM ")
//Hier ebenso in eine Liste speichern?
for (fromSource : e.left.from.sources) {
st.append(e.left.from.sources.get(fromIndex).name);
}
/*WHERE */
if (e.left.where !== null || e.left.timedef !== null) {
st.append(" WHERE");
if (e.left.where !== null) {
for (whereArgument : e.left.where.predicates.expr) {
if (whereIndex == 0) {
st.append(" " + whereArgument.ID.value.name);
} else {
st.append("AND " + whereArgument.ID.value.name);
}
whereIndex++;
}
}
/*TIMEINTERVALL
*TODO: timestamp as columname hardcoded*/
if (e.left.timedef !== null) {
if (whereIndex > 0) {
st.append(" AND")
}
st.append(tch.toIso8601(e.left.timedef))
//if (e.left.timedef.name != null) {
//st.append(" ").append(e.left.where.name);
}
}
fsa.generateFile("query.txt", st.toString());
}
}
给定以下简化语法
grammar org.xtext.example.mydsl1.MyDsl with org.eclipse.xtext.common.Terminals
generate myDsl "http://www.xtext.org/example/mydsl1/MyDsl"
Model:
(expressions+=Expression ";")*;
Expression returns Expression:
OrExpression;
OrExpression returns Expression:
PrimaryExpression ({OrExpression.left=current} name="OR" right=PrimaryExpression)*;
PrimaryExpression returns Expression:
'(' Expression ')'
| {Negation} "NOT" expr=Expression
| {IntLiteral} value=INT
| {StringLiteral} value=STRING
| {Variable} name=ID;
输入 NOT x or y
可以用两种方式解析:或者作为
Or(Negation(Variable("x")), Variable("y"))
或
Negation(Or(Variable("x"), Variable("y")))
在编译 Xtext 语法时,它会告诉您(有点含糊),并带有如下警告:
warning(200): ../org.xtext.example.mydsl1/src-gen/org/xtext/example/mydsl1/parser/antlr/internal/InternalMyDsl.g:195:3: Decision can match input such as "'OR'" using multiple alternatives: 1, 2
As a result, alternative(s) 2 were disabled for that input
这里的重要部分是:[...]alternative(s) 2 were disabled for that input
。所以你的部分语法是死代码,实际上被忽略了。
解决方案:将所有运算符正确放入优先级层次。 不要 将任何复杂的东西放入 PrimaryExpression
。事实上 ( Expression )
应该是 only 在层次结构中调用更高规则的地方。结果是这样的无冲突语法:
OrExpression returns Expression:
IsNullExpression ({OrExpression.left=current} name="OR" right=IsNullExpression)*;
IsNullExpression returns Expression:
CompareExpression ({IsNullExpression.expr=current} 'IS' not?='NOT'? 'NULL')?;
CompareExpression returns Expression:
NegationExpression ({CompareExpression.left=current} name=("NOT"| "=" | "!=") right=NegationExpression)*;
NegationExpression returns Expression:
{NegationExpression} name=("NOT" | "-") expr=PrimaryExpression
| PrimaryExpression;
PrimaryExpression returns Expression:
'(' Expression ')'
| {IntLiteral} name=INT
| {StringLiteral} name=STRING
| {Variable} name=ID;
请注意,尽管在不同的地方多次使用了几个关键字(例如 NOT
、-
),但此语法没有冲突。
我正在尝试通过 Xtext 编写一个 DSL,我可以用它来自定义 SQL。 首先,我想要一个字符串表示形式来表示我的查询。 在那里,我陷入了表情。我在这个例子之后创建了它们:https://typefox.io/parsing-expressions-with-xtext.
Expression returns Expression:
OrExpression;
OrExpression returns Expression:
AndExpression ({OrExpression.left=current} name="OR" right=AndExpression)*;
AndExpression returns Expression:
NotExpression({AndExpression.left=current} name="AND" right=NotExpression)*;
NotExpression returns Expression:
ComparisonExpression({NotExpression.left=current} name='NOT' right=ComparisonExpression)*;
ComparisonExpression returns Expression:
BitwiseOR({ComparisonExpression.left=current} name=cmpop right=BitwiseOR)*;
BitwiseOR returns Expression:
BitwiseAND ({BitwiseOR.left=current} name='|' right=BitwiseAND)*;
BitwiseAND returns Expression:
BitwiseXOR ({BitwiseAND.left=current} name='&' right=BitwiseXOR)*;
BitwiseXOR returns Expression:
Addition ({BitwiseXOR.left=current} name='^' right=Addition)*;
Addition returns Expression:
Substraction ({Addition.left=current} name='+' right=Substraction)*;
Substraction returns Expression:
Multiplication ({Substraction.left=current} name='-' right=Multiplication)*;
Multiplication returns Expression:
Division ({Multiplication.left=current} name='*' right=Division)*;
Division returns Expression:
Modulo ({Division.left=current} name='/' right=Modulo)*;
Modulo returns Expression:
Primary ({Modulo.left=current} name='%' right=Primary)*;
Primary returns Expression:
=> count=count
| => func=funccall
| {Bracket} '(' inner=Expression ')'
| (name=unop) expr=Expression
| (name=unop)? ID=Literal ('IS' 'NOT'? 'NULL')?;
/*Values that a Expression can have */
Literal returns Expression:
value=values;
我可以设法获取单个值,但我无法获取表达式的左侧或右侧。
我的生成器(未完成,我的测试看起来像这样)
class TsqlGenerator extends AbstractGenerator {
StringBuilder st = new StringBuilder();
TimeConditionHandler tch = new TimeConditionHandler
ExpressionHandler exprH = new ExpressionHandler
String expression = ""
int fromIndex = 0;
int whereIndex
def clear() {
st.delete(0, st.length);
fromIndex = 0;
whereIndex =0;
}
override beforeGenerate(Resource input, IFileSystemAccess2 fsa, IGeneratorContext context) { clear() }
override void doGenerate(Resource resource, IFileSystemAccess2 fsa, IGeneratorContext context) {
for (e : resource.allContents.toIterable.filter(ComplexSelect)) {
/*SELECT */
// TODO: String Value ohne Anführungszeichen?
st.append("SELECT ");
for (selectArgument : e.left.selectArguments.arguments) {
if (selectArgument.expr.name == null) {
//hier später in eine Liste speichern?
st.append(" " + selectArgument.expr.ID.value.name);
}else {
// TODO: Generate a Sting of the Expression!
}
}
/*FROM */
st.append(" FROM ")
//Hier ebenso in eine Liste speichern?
for (fromSource : e.left.from.sources) {
st.append(e.left.from.sources.get(fromIndex).name);
}
/*WHERE */
if (e.left.where !== null || e.left.timedef !== null) {
st.append(" WHERE");
if (e.left.where !== null) {
for (whereArgument : e.left.where.predicates.expr) {
if (whereIndex == 0) {
st.append(" " + whereArgument.ID.value.name);
} else {
st.append("AND " + whereArgument.ID.value.name);
}
whereIndex++;
}
}
/*TIMEINTERVALL
*TODO: timestamp as columname hardcoded*/
if (e.left.timedef !== null) {
if (whereIndex > 0) {
st.append(" AND")
}
st.append(tch.toIso8601(e.left.timedef))
//if (e.left.timedef.name != null) {
//st.append(" ").append(e.left.where.name);
}
}
fsa.generateFile("query.txt", st.toString());
}
}
给定以下简化语法
grammar org.xtext.example.mydsl1.MyDsl with org.eclipse.xtext.common.Terminals
generate myDsl "http://www.xtext.org/example/mydsl1/MyDsl"
Model:
(expressions+=Expression ";")*;
Expression returns Expression:
OrExpression;
OrExpression returns Expression:
PrimaryExpression ({OrExpression.left=current} name="OR" right=PrimaryExpression)*;
PrimaryExpression returns Expression:
'(' Expression ')'
| {Negation} "NOT" expr=Expression
| {IntLiteral} value=INT
| {StringLiteral} value=STRING
| {Variable} name=ID;
输入 NOT x or y
可以用两种方式解析:或者作为
Or(Negation(Variable("x")), Variable("y"))
或
Negation(Or(Variable("x"), Variable("y")))
在编译 Xtext 语法时,它会告诉您(有点含糊),并带有如下警告:
warning(200): ../org.xtext.example.mydsl1/src-gen/org/xtext/example/mydsl1/parser/antlr/internal/InternalMyDsl.g:195:3: Decision can match input such as "'OR'" using multiple alternatives: 1, 2
As a result, alternative(s) 2 were disabled for that input
这里的重要部分是:[...]alternative(s) 2 were disabled for that input
。所以你的部分语法是死代码,实际上被忽略了。
解决方案:将所有运算符正确放入优先级层次。 不要 将任何复杂的东西放入 PrimaryExpression
。事实上 ( Expression )
应该是 only 在层次结构中调用更高规则的地方。结果是这样的无冲突语法:
OrExpression returns Expression:
IsNullExpression ({OrExpression.left=current} name="OR" right=IsNullExpression)*;
IsNullExpression returns Expression:
CompareExpression ({IsNullExpression.expr=current} 'IS' not?='NOT'? 'NULL')?;
CompareExpression returns Expression:
NegationExpression ({CompareExpression.left=current} name=("NOT"| "=" | "!=") right=NegationExpression)*;
NegationExpression returns Expression:
{NegationExpression} name=("NOT" | "-") expr=PrimaryExpression
| PrimaryExpression;
PrimaryExpression returns Expression:
'(' Expression ')'
| {IntLiteral} name=INT
| {StringLiteral} name=STRING
| {Variable} name=ID;
请注意,尽管在不同的地方多次使用了几个关键字(例如 NOT
、-
),但此语法没有冲突。