2012-02-15 34 views
3

我写了这个语法:如何解决这个模糊的语法?

expr  : multExpr (('+' | '-') multExpr)*; 
multExpr : atom (('*' | '/') atom)*; 
atom : INT | FLOAT | ID | '(' expr ')'; 
condition : cond ('or' cond)*; 
cond : c1 ('and' c1)*; 
c1  : ('not')? c2; 
c2  : '(' condition ')' | boolean; 
boolean : expr (relop expr | ²) | 'true' | 'false'; 
relop : '<' | '<=' | '>' | '>=' | '==' | '!='; 

我已经省略了INT,FLOAT,ID的词法规则,因为它是显而易见的。

问题是C2规则,它是模糊的,因为“(”,我找不到解决方案,你可以给我一个解决方案吗?

+1

什么是超级脚本'2'在'boolean'做什么? – 2012-02-15 20:21:44

回答

5

为什么不能简单地做:

expr  : orExpr; 
orExpr : andExpr ('or' andExpr)*; 
andExpr : relExpr ('and' relExpr)*; 
relExpr : addExpr (relop addExpr)?; 
relop  : '<' | '<=' | '>' | '>=' | '==' | '!='; 
addExpr : multExpr (('+' | '-') multExpr)*; 
multExpr : unaryExpr (('*' | '/') unaryExpr)*; 
unaryExpr : 'not'? atom; 
atom  : INT | FLOAT | ID | 'true' | 'false' | '(' expr ')'; 

单数not通常比您现在要做的要高。

这将允许使用像42 > true这样的表达式,但在走AST /树时检查这样的语义会出现。

编辑

输入"not(a+b >= 2 * foo/3.14159) == false"现在将解析像这样(忽略空格):

enter image description here

如果你设置输出到AST和一些树改写运营商混合( ^!):

options { 
    output=AST; 
} 

// ... 

expr  : orExpr; 
orExpr : andExpr ('or'^ andExpr)*; 
andExpr : relExpr ('and'^ relExpr)*; 
relExpr : addExpr (relop^ addExpr)?; 
relop  : '<' | '<=' | '>' | '>=' | '==' | '!='; 
addExpr : multExpr (('+' | '-')^ multExpr)*; 
multExpr : unaryExpr (('*' | '/')^ unaryExpr)*; 
unaryExpr : 'not'^ atom | atom; 
atom  : INT | FLOAT | ID | 'true' | 'false' | '('! expr ')'!; 

你会得到:

enter image description here

+0

这适用于条件表达式,但我使用expr(在你的语法中:addExpr)作为数学的东西,那么我应该定义一个单独的expr,我认为这个。另一件事,你已经定义了unaryExpr,但没有使用它。 – nafiseh 2012-02-15 20:36:45

+0

,谢谢你的解决方案是正确的,我认为,但我在想,使用句法谓词是这样明智的:c2:('('atom''''atom)*(('+'|' - ')atom ('*'atom)*)*')')=> boolean | '('condition')' – nafiseh 2012-02-15 21:09:59

+0

@nafiseh,我的观点是:如果可以,尽可能避免谓词。我知道,有时候你需要它们,但我更倾向于更宽松地构造AST,然后在稍后阶段验证AST的语义结构:它使语法对眼睛更加友好! :) – 2012-02-15 21:13:08

0

无法定义C1作为以下?

要解决这个问题
('not')? (('(' condition ')') | boolean) 
+0

这对于'atom'规则来说还是不明确吗? – Bill 2012-02-15 20:00:34

+0

不,问题依然存在,如果布尔变为expr,则expr转到multExpr,然后是atom,然后是'('expr')'。 – nafiseh 2012-02-15 20:07:53

0

一种方法是将它拆分成两套词法规则和顺序将其应用到输入(一个用于数学的东西,其他的布尔)

+0

所以你的意思是我不应该从布尔再去expr? – nafiseh 2012-02-15 20:10:27

+0

取决于您试图实现的目标。你可以将它们分开并创建一个booleanexpr,而不是重用expr。如果你能列出一些有效的输入样本,这将是有帮助的。例如,“true和(4 + 3)/ 4”是否是一个有效的表达式? – Bill 2012-02-15 20:26:56

+0

是的,那么它就像Bart所说的那样,我需要定义两种类型的表达式。实际上我对整个语言都有语法,我也有数学表达式。 – nafiseh 2012-02-15 20:40:14

2

您的问题从一个事实,即“(”可无论是c2第一选择或​​最后的选择开始茎。举例来说,给定像((x+y) > (a+b))这样的输入,第一个开放参数是c2的开始,但第二个是​​的开始。 [编辑:而解析器没有指示要走哪个路,直到稍后的任意点 - 例如,它不知道第一个开放paren是c2的开始,直到它遇到>。例如,如果这是一个*代替,那么无论是开括号将是​​开始的时候也。]

一种可能的方式来处理这将是统一的算术和布尔表达式的规则,所以你只有一个规则为'(' expression '),而expression可能是算术或布尔值。然而,这经常会产生相当松散的输入的副作用,算术和布尔表达式之间相对自由的转换(至少在解析器级别 - 然后您可以在语义中尽可能严格地执行类型)。

编辑:帕斯卡,例如,规则运行像这样(简化一点点):

expression: simple_expression (rel_op simple_expression)* 

simple_expression: ('+' | '-')? term (('+' | '-' | 'or') term)* 

term: factor (('/' | '*' | 'div' | 'mod' | 'and') factor)* 

factor: constant | variable | function_call | '(' expression ')' | 'not' factor 
+0

是的,我认为我必须这样做,并且有一个问题,一些知名的语言如java,pascal等如何解决这个问题?他们的语法是否像这样行事?还是他们使用不同的方法,如回溯和这样的东西? – nafiseh 2012-02-15 20:51:03

+0

取决于语言。 Fortran使用宽松的规则和回溯。 Pascal使用了我上面概述的内容 - 所有表达式的一组规则,布尔或其他。大多数人都喜欢帕斯卡。请参阅编辑答案 - 我已经添加了来自Pascal的规则。 – 2012-02-15 21:04:41