使用括号在Antlr中的优先级

时间:2013-02-27 14:14:46

标签: antlr antlr3 lexer

我们正在开发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();}
;

2 个答案:

答案 0 :(得分:2)

这类似于根本没有运营商优先权。

expr
  : funcExpr
    ( ('+' funcExpr)*
    | ('-' funcExpr)*
    | ('*' funcExpr)*
    | ('/' funcExpr)*
    )
  ;

答案 1 :(得分: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

如果只有一个类型的运算符在括号外面,则唯一的*规则匹配表达式。 * Expr规则匹配具有适当类型的运算符的行或转到下一个运算符。

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