Javacc无法访问的声明

问题描述:

在我的语法中,有一些原始包含间接左递归的表达式和片段的生成规则。这是我从他们删除递归后的规则。Javacc无法访问的声明

String expression() #Expression : {String number; Token t;} 
{ 
    number = fragment() 
    (
     (t = <Mult_Sign> number = fragment()) 
    ) 
    {return number;} 
} 

String fragment() #void : {String t;} 
{ 
    t = identifier() {return t;} 
    | t = number() {return t;} 
    | (<PLUS> | <MINUS>) fragment() 
    | <LBR> expression() <RBR> 
} 

这些生产规则在尝试解析语法中的条件时使用。然而,生产规则的排序或者只有表达式才被接受。但它应该接受像while(x < = 10)。如果我有相反的顺序生产规则,正如原来在语法中所述。当我尝试使用javac编译java文件时。我收到一个错误,告诉我identifier()是不可达的语句。 这是条件产生式规则:

void condition() #void : {Token t;} 
{ 
    <NOT> expression() 
    | expression (<EQUALS>|<NOTEQUALS>|<LT>|<GT>|<LTE>|<GTE>|<AND>|<OR>) expression() 
    | identifier() 
} 

如果有人可以帮告诉我,为什么这个问题发生,将是非常有益的。

你有

​​

如果分析器正在寻找一个条件,将努力使根据输入的下一个标记三个方案之间进行选择。如果该标记是标识符,则存在问题,因为替代方案(b)或替代方案(c)都可以工作。面对选择冲突,JavaCC更喜欢第一个,所以(b)将被选中。如果下一个标记不是标识符,则不会选择替代(c)。所以无论哪种方式都不会选择(c)。


这就是你的问题。应该做些什么呢?这是通常的解决方案。

如果要在表达式中允许其他运算符,请使更多非终止符表示更高级别的优先级。例如

condition --> expression 
expression --> disjunct (OR expression)? 
disjunct --> conjunct (AND disjunct)? 
conjunct --> comparand ((EQ|NEQ|LT|GT|LE|GE) comparand)? 
comparand --> term ((PLUS|MINUS) term)* 
term --> fragment ((TIMES | DIVIDE) fragment)* 
fragment --> identifier | number | LBR expression RBR | (PLUS|MINUS|NOT) fragment 

这个语法将接受你想要的一切,可能更多。例如,如果您有

statement --> WHILE condition DO statement 

解析器将接受例如“WHILE a + b DO a:= b”。在许多语言中,这通过类型检查来处理; Java是这样做的。在其他语言中,它通过允许各种事情作为条件来处理; LISP这样做。


上不

大多数语言的优先级的说明治疗的不作为非常高的优先地位,因为在这个答案的第二部分。当语法为LL(1)时,这具有消除所有选择警告的良好效果。

但是,如果您希望一元运算符具有较低的优先级,那么如果您使用JavaCC,那么确实没有什么能够阻止您。例如。你可以改变片段到

fragment --> identifier | number | LBR expression RBR | (PLUS|MINUS) fragment | NOT conjunct 

现在语法不是LL(1)(它甚至不明确)。所以JavaCC会给出一些选择冲突警告。但它实际上会解析“不是LT B”为“NOT(一LT B)”


什么几乎没有语言的作用是什么,我认为你正在尝试做的,哪些是限制的语法,以便只有像表情条件允许成为条件。如果这真的是你想要的,那么你可以用JavaCC来使用语法预测。这是你如何做到的。

从这样的文法开始。 (这基本上是支付给优先级的更多关注你的想法。)

condition --> disjunct (OR condition)? 
disjunct --> conjunct (AND disjunct)? 
conjunct --> expression (EQ|NEQ|LT|GT|LE|GE) expression 
      | LBR condition RBR 
      | NOT conjunct 
      | identifier 

expression --> term ((PLUS|MINUS) term)* 
term --> fragment ((TIMES | DIVIDE) fragment)* 
fragment --> identifier | number | LBR expression RBR | (PLUS|MINUS) fragment 

这是条件明确语法。但是,当下一个标记是标识符或LBR时,它会有选择冲突。要解决你向前看使用句法先行比较运算符这种选择冲突从而

void conjunct() : { } { 
    LOOKAHEAD(expression() (<EQ>|<NEQ>|<LT>|<GT>|<LE>|<GE>)) 
    expression() (<EQ>|<NEQ>|<LT>|<GT>|<LE>|<GE>) expression() 
| LBR condition() RBR 
| NOT conjunct() 
| identifier() { 

那么,为什么(几乎)没有任何编程语言做这种方式?大多数语言都有布尔类型的变量,所以像你一样,允许标识符作为条件。所以你仍然需要进行类型检查来排除“WHILE I DO ...”,其中“i”不是布尔类型。另外,您应该如何使用赋值语法?你需要

statement --> identifier := (expression | condition) | ... 

即使语法预测也不会告诉你哪个选项适合“x:= y”。这是一个模棱两可的语法。

如果在两种选择都解析的情况下,任何一种选择都可以接受,那么在这里也可以使用语法预测。

void statement() : {} { 
    identifier <BECOMES> (LOOKAHEAD(condition()) condition()) | expression()) 
| ... 
} 

这将解析在 “Y”, “X:= Y” 定义为即使是数字的条件。如果你意识到这一点并设计编译器的其余部分,那么一切仍然有效,不会造成任何损害。

这种方法的另一个缺点是解析现在在理论上是二次的。我不认为这是一个严重的问题。