1

私たちは DSL を開発していますが、いくつかの問題に直面しています:

問題 1:
私たちの DSL では、これを行うことが許可されています:
A + B + C

しかし、これではありません:
A + B - C

ユーザーが 2 つ以上の異なる演算子を使用する必要がある場合は、括弧を挿入する必要があります:
A + (B - C)
または
(A + B) - C.

問題 2: この DSL では、最も先行する演算子を括弧で囲む必要があります。

たとえば、この方法を使用する代わりに: A + B * C

ユーザーはこれを使用する必要があります: A + (B * C)

問題 1を解決するには、動作する ANTLR のスニペットがありますが、それが解決する最善の方法であるかどうかはわかりません。

sumExpr
@init {boolean isSum=false;boolean isSub=false;}
    : {isSum(input.LT(2).getText()) && !isSub}? multExpr('+'^{isSum=true;} sumExpr)+
    | {isSub(input.LT(2).getText()) && !isSum}? multExpr('-'^{isSub=true;} sumExpr)+
    | multExpr;

問題 2を解決するには、どこから始めればよいかわかりません。

最初の問題に対するより良い解決策と、2 番目の問題を解決するための方向性を見つけるために、あなたの助けに感謝します。(下手な英語でごめんなさい)

以下は、私たちが開発した文​​法です。

grammar TclGrammar;

options {
    output=AST;
    ASTLabelType=CommonTree;
}

@members {
    public boolean isSum(String type) {
    System.out.println("Tipo: " + type);
    return "+".equals(type);
}

public boolean isSub(String type) {
    System.out.println("Tipo: " + type);
    return "-".equals(type);
}
}

prog    
: exprMain ';' {System.out.println( 
    $exprMain.tree == null ? "null" : $exprMain.tree.toStringTree());}
;

exprMain
:   exprQuando? (exprDeveSatis | exprDeveFalharCaso)
;

exprDeveSatis
: 'DEVE SATISFAZER' '{'! expr '}'!
;

exprDeveFalharCaso
: 'DEVE FALHAR CASO' '{'! expr '}'! 
;

exprQuando
: 'QUANDO' '{'! expr '}'!
;

expr    
: logicExpr
;

logicExpr
:   boolExpr (('E'|'OU')^ boolExpr)*
;

boolExpr
: comparatorExpr
| emExpr
| 'VERDADE'
| 'FALSO'
;

emExpr
: FIELD 'EM' '[' (variable_lista | field_lista) comCruzamentoExpr? ']'
-> ^('EM' FIELD (variable_lista+)? (field_lista+)? comCruzamentoExpr?)
;

comCruzamentoExpr
: 'COM CRUZAMENTO' '('  FIELD ';' FIELD (';' FIELD)* ')' -> ^('COM CRUZAMENTO' FIELD+)
;

comparatorExpr
: sumExpr (('<'^|'<='^|'>'^|'>='^|'='^|'<>'^) sumExpr)?
| naoPreenchidoExpr
| preenchidoExpr
;

naoPreenchidoExpr
: FIELD 'NAO PREENCHIDO' -> ^('NAO PREENCHIDO' FIELD)
;

preenchidoExpr
: FIELD 'PREENCHIDO' -> ^('PREENCHIDO' FIELD)
;

sumExpr
@init {boolean isSum=false;boolean isSub=false;}
: {isSum(input.LT(2).getText()) && !isSub}? multExpr('+'^{isSum=true;} sumExpr)+
| {isSub(input.LT(2).getText()) && !isSum}? multExpr('-'^{isSub=true;} sumExpr)+
| multExpr
;

multExpr
: funcExpr(('*'^|'/'^) funcExpr)?
;

funcExpr
: 'QUANTIDADE'^ '('! FIELD ')'!
| 'EXTRAI_TEXTO'^ '('! FIELD ';' INTEGER ';' INTEGER ')'! 
| cruzaExpr
| 'COMBINACAO_UNICA' '(' FIELD ';' FIELD (';' FIELD)* ')' -> ^('COMBINACAO_UNICA' FIELD+)
| 'EXISTE'^ '('! FIELD ')'!
| 'UNICO'^ '('! FIELD ')'!
| atom
;

cruzaExpr
:   operadorCruzaExpr ('CRUZA COM'^|'CRUZA AMBOS'^) operadorCruzaExpr ondeExpr?
;

operadorCruzaExpr
:   FIELD('('!field_lista')'!)?
;

ondeExpr
:   ('ONDE'^ '('!expr')'!)
;

atom
: FIELD 
| VARIABLE
| '('! expr ')'!
;

field_lista
: FIELD(';' field_lista)?
;

variable_lista
: VARIABLE(';' variable_lista)?
;

FIELD  
:   NONCONTROL_CHAR+
    ;

NUMBER
:   INTEGER | FLOAT
;

VARIABLE
: '\'' NONCONTROL_CHAR+ '\''
;

fragment SIGN: '+' | '-';   
fragment NONCONTROL_CHAR: LETTER | DIGIT | SYMBOL;
fragment LETTER: LOWER | UPPER;
fragment LOWER: 'a'..'z';
fragment UPPER: 'A'..'Z';
fragment DIGIT: '0'..'9';
fragment SYMBOL: '_' | '.' | ',';
fragment FLOAT: INTEGER '.' '0'..'9'*;
fragment INTEGER: '0' | SIGN? '1'..'9' '0'..'9'*;

WS  :   ( ' '
    | '\t'
    | '\r'
    | '\n'
    ) {skip();}
;
4

2 に答える 2

2

これは、演算子の優先順位がまったくないことに似ています。

expr
  : funcExpr
    ( ('+' funcExpr)*
    | ('-' funcExpr)*
    | ('*' funcExpr)*
    | ('/' funcExpr)*
    )
  ;
于 2013-02-27T20:04:55.540 に答える
0

以下がうまくいくはずだと思います。明らかな名前を持ついくつかのレクサートークンを想定しています。

expr: sumExpr;

sumExpr: onlySum | subExpr;

onlySum: atom ( PLUS onlySum )?;

subExpr: onlySub | multExpr;

onlySub: atom ( MINUS onlySub )? ;

multExpr: atom ( STAR atomic )? ;

parenExpr: OPEN_PAREN expr CLOSE_PAREN;

atom: FIELD | VARIABLE | parenExpr

only* ルールは、括弧の外側に 1 種類の演算子しかない場合に式に一致します。*Expr ルールは、適切なタイプの演算子を含む行に一致するか、次の演算子に進みます。

複数のタイプの演算子がある場合は、一致がアトムを通過するため、強制的に括弧内に配置されます。

于 2013-02-27T18:47:00.207 に答える