【问题标题】:Is this EBNF method correct?这种 EBNF 方法正确吗?
【发布时间】:2014-03-11 23:33:29
【问题描述】:

我不确定我是否将 EBNF 转换为正确的代码,所以如果有人可以看看我很难做到的其中一种方法,那就太好了。

这是 EBNF 语法:

   program ::= P {declare} B {statemt} ;
   declare ::= ident {, ident} : V ;
   statemt ::= assnmt | ifstmt | doloop | read | output
   assnmt  ::= ident ~ exprsn ;
   ifstmt  ::= I comprsn @ {statemt} [% {statemt}] &
   doloop  ::= D {statemt} U comprsn T
   read    ::= R ident {, ident } ;
   output  ::= O ident {, ident } ;
   comprsn ::= ( oprnd opratr oprnd )
   exprsn  ::= factor {+ factor}
   factor  ::= oprnd {* oprnd}
   oprnd   ::= integer | ident | ( exprsn )
   opratr  ::= < | = | > | !
   ident   ::= letter {char}
   char    ::= letter | digit
   integer ::= digit {digit}
   letter  ::= X | Y | Z
   digit   ::= 0 | 1

标记是:P B ; , : V ~ I @ % & D U T R O ( ) + * ! X Y Z 0 1

private void statemt(){
    if((token() == 'X') || (token() == 'Y') || (token() == 'Z')){
      assnmt();
    }else if(token() == 'I'){
      ifstmt();
    }else if(token() == 'D'){
      doloop();
    }else if(token() == 'R'){
      read();
    }else if(token() == 'O'){
      output();
    }
}

如果stmt方法正确,这是否正确?

   private void ifstmt(){
     match('I');
     comprsn();
     match('@');
     while((token() == 'X') || (token() == 'Y') || (token() == 'Z')){
       statemt();
     }
     if(token() == '%'){
         match('%');
         statemt();
     }
     match('&');
   }

【问题讨论】:

    标签: java parsing ebnf


    【解决方案1】:

    最好先测试以关键字开头的语句,如果没有关键字匹配则进入赋值情况。这样你就不需要 X,Y,Z 作为关键字:

    private void statemt(){
        if(token() == 'I'){
          ifstmt();
        }else if(token() == 'D'){
          doloop();
        }else if(token() == 'R'){
          read();
        }else if(token() == 'O'){
          output();
        } else {
          assnmt();
        }
    }
    

    在当今时代和语言中,我认为这些缩写没有任何充分的理由。

    回答您关于if 声明的问题:

    private void ifstatement() {
        match('I');
        comprsn();
        match('@');
        statement();
        if (token() == '%') {
            statement();
        }
        if (token() != '&') {
            syntax_error("'&' expected");
        }
    }
    

    回答关于{语句的第二个扩展...},这在语法中表示为

    statement ::= '{' statement ... '}'
    

    这是在statement() 中实现的,因此:

    private void statement(){
        if (token == '{') {
            do {
                statement();
            } while (token() != '}');
        } else if(token() == 'I'){
          ifstmt();
        }else if(token() == 'D'){
          doloop();
        }else if(token() == 'R'){
          read();
        }else if(token() == 'O'){
          output();
        } else {
          assnmt();
        }
    }
    

    请注意,我完全忽略了令牌何时被消耗的问题,因为您没有告诉我们您的 token()match() 方法是如何工作的。

    【讨论】:

    • “opratr”、“oprnd”、“statemt”、“assnmt”等。让我回到 30 年前。可怕。我不知道您所说的[A | B] 是什么意思。它没有出现在语法中。
    • 好吧,如果输入的token是'%',调用statement()。无论哪种方式,下一个标记都应该是 '&'。
    • 以 '%' 开头的部分是可选的。如果“%”不存在,则下一个标记应该是“&”。如果存在,则解析一个语句,then 下一个标记应该是 '&'。你的最后一句话没有意义。如果没有以下语句,处理 '%' 是没有意义的。你也不需要一个while循环。您已经有statement(): 使用它!见编辑。
    • @user2318083 NO! statement() 有责任处理 {} 以及多个语句,因为这可能发生在任何可能出现单个语句的地方.致电statement() 只是ifstatement() 的责任。这就是递归下降解析的本质。这简单。不要把东西写两次。如果你这样做,那你就错了。本质上,您的语法缺少stmt ::= '{' stmnt ... '}' 的产生式,而该产生式在statement(). 内部实现,请参见第二次编辑。
    • 好吧,无论语句列表的正确语法是什么,您都必须按照所示进行适当的调整来实现它。但鉴于您的原始语法中没有语句列表产生式,您是否必须实现它是值得怀疑的。如果你这样做,这就是如何做到这一点。不是在所有错误的地方乱扔while 循环。您需要了解递归:这就是它的全部意义所在,也是这里所教授的内容。
    猜你喜欢
    • 2010-11-21
    • 2016-07-30
    • 1970-01-01
    • 1970-01-01
    • 2021-07-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多