выражение генератора xtext getLeft и getRight - PullRequest
0 голосов
/ 19 февраля 2019

Я пытаюсь написать DSL через Xtext, с помощью которого я могу настроить 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());

    }

}

1 Ответ

0 голосов
/ 20 февраля 2019

С учетом следующей упрощенной грамматики

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, -).

...