1

我们正在开发 DSL,我们面临一些问题:

问题 1:
在我们的 DSL 中,允许这样做:
A + B + C

但不是这个:
A + B - C

如果用户需要使用两个或更多不同的运算符,他需要插入括号:
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,我不知道从哪里开始。

感谢您帮助找到第一个问题的更好解决方案和解决第二个问题的方向。(对不起,我的英语不好)

下面是我们开发的语法:

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* 规则匹配一个表达式,如果它在括号外只有一种类型的运算符。*Expr 规则匹配具有适当类型运算符的行或转到下一个运算符。

如果您有多种类型的运算符,那么它们将被强制放在括号内,因为匹配将通过 atom。

于 2013-02-27T18:47:00.207 回答