EBNF制作的预测解析器

时间:2014-09-28 16:59:19

标签: parsing recursive-descent

我正在尝试编写一个递归下降解析器而不需要回溯一种类似这样的EBNF:

<a> ::= b [c] | d

,其中

  • &LT a取代; =非终端

  • lower-case-string = identifier

  • [括号内] =括号中的术语是可选的

  • a | b是a和b之间通常的互斥选择。

目前,我只关心右手边。

按照http://en.wikipedia.org/wiki/Recursive_descent_parser的示例,我最终得到了以下程序(上面评论中的GNU bison语法规则):

/* expression: term optional_or_term */
void expression()
{
    term();
    if (sym == OR_SYM)
        optional_or_term();

}

/* optional_or_term: // empty
    | OR_SYM term optional_or_term
*/
void optional_or_term()
{
    while (sym == OR_SYM)
    {
        getsym();
        term();
    }
}

/* term: factor | factor term */
void term()
{
    factor();
    if (sym == EOF_SYM || sym == RIGHT_SQUAREB_SYM)
    {
        ;
    }
    else if (sym == IDENTIFIER_SYM || sym == LEFT_SQUAREB_SYM)
        term();
    else if (sym == OR_SYM)
        optional_or_term();
    else
    {
        error("term: syntax error");
        getsym();
    }

}

/*
factor: IDENTIFIER_SYM  
    | LEFT_SQUAREB_SYM expression RIGHT_SQUAREB_SYM
*/

void factor()
{
    if (accept(IDENTIFIER_SYM))
    {
        ;
    }
    else if (accept(LEFT_SQUAREB_SYM))
    {
        expression();
        expect(RIGHT_SQUAREB_SYM);
    }
    else
    {
        error("factor: syntax error");
        getsym();
    }

}

它似乎有效,但我的期望是每个程序都会与相应的规则密切对应。你会注意到term()没有。

我的问题是:在编写程序之前语法是否需要更多转换?

1 个答案:

答案 0 :(得分:0)

我不认为你的问题是缺少连接操作符。我认为它不是使用Kleene星(和加号)来列出事物。 Kleene星允许您在实现语法规则的过程中实际编写循环。

我会把你的语法写成:

expression = term (OR_SYM term)*;
term = factor+;
factor = IDENTIFIER_SYM | LEFT_SQUAREB_SYM expression RIGHT_SQUAREB_SYM ;

(这是一种非常经典的语法语法)。

解析器代码如下所示:

 boolean function expression()
 {   if term()
     {   loop
         { if OR_SYM()
           {  if term()
              {}
              else syntax_error();
           }
           else return true;
         }
     else return false;
 }

 boolean term()
 {  if factor()
    {  loop
       {  if factor()
          {}
          else return true;
       }
    }
    else return false;
 }

 boolean factor()
 {  if IDENTIFIER(SYM)
    return true;
    else 
    { if LEFT_SQUAREB_SYM()
      {  if expression()
         {   if RIGHT_SQUAREB_SYM()
             return true;
             else syntax_error();
         }
         else syntax_error();
      else return false;
    }
 }

我尝试以绝对机械的方式生成这个,你可以做得很好。我的职业生涯早就做了很多。

你不会得到的是每天150条工作规则。首先,对于一门大语言,很难使语法正确;你将反复调整它以获得一个抽象的语法,然后你必须调整你编写的代码。接下来你会发现写词法分析器也有麻烦;试着为Java编写词法分析器。最后,您会发现解析器规则不是整个游戏,甚至不是您努力的最重要部分;你需要很多来处理真正的代码。我称之为“解析后的生活”;看我的生物 了解更多信息。

如果您希望每天获得150个工作规则,请切换到GLR解析器并手动停止编码解析器。这不会解决其他问题,但它确实让你在获得可用的语法方面非常高效。这就是我现在所做的。没有例外。 (我们的DMS软件重组工具包使用了这个,we parse a lot of things that people claim are hard.