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-),但此语法没有冲突。