递归下降解析器应该在重复字母终端上出错

时间:2019-03-07 19:57:53

标签: javascript parsing recursive-descent propositional-calculus

主要问题:如何为命题逻辑(用JavaScript编写)更新递归下降解析器,以便使诸如“ p〜”和“ pp”之类的字符串返回“无效”消息?

我对HTML,JavaScript和解析非常陌生。我想看看我是否能够制作一个可以从命题逻辑中解析简单公式的简单网页。这是语法:

<formula> ::= <unaryconnective> <formula>
            | "(" <formula> <binaryconnective> <formula> ")"
            | <proposition>

<unaryconnective> ::= "~"

<binaryconnective> ::= "&"

<proposition> ::= "p"
                | "q"
                | "r"

我是刚开始写这样的语法,所以希望这种语法有意义。据我了解维基百科对左递归语法的理解,我不认为这种语法是左递归的,也不是模棱两可的。

然后,我尝试创建一个简单的网页,该网页允许某人在文本框中输入公式,单击“验证”按钮,并返回一条简单消息,指出该公式有效或无效。我试图编写一个可以进行解析的递归下降解析器。这是我根据维基百科,堆栈溢出以及我发现的有关该主题(jsfiddle)的其他资源得出的:

<!DOCTYPE html>
<html lang='en'>
  <head>
    <meta charset='UTF-8'>
    <title>Logic App</title>

    <script type="text/javascript">

    var sentence;
    var len;
    var i;
    var sym;

    function validate() {
      var result;

      sentence = document.getElementById('formulaentry').value;
      len = sentence.length;
      i = -1;

      if (sentence == "") {
        document.getElementById('formulaentry').value = "There's no formula!";
      } else {
        nextSym();
        result = formula();
        if(result == 0) {
          document.getElementById('formulaentry').value = "Invalid";
        } else {
        document.getElementById('formulaentry').value = "Valid";
        }
      }
    }

    function nextSym() {
      i++;
      if (i <= (len-1)) {
        sym = sentence.charAt(i);
      } else {
        sym = "";
      }
      //console.log("Current Sym:" + sym);
    }

    function accept(s) {
      if (sym == s) {
        nextSym();
        return 1;
      }
      return 0;
    }

    function expect(s) {
      if (accept(s)) {
        return 1;
      }
      return 0;
    }

    function formula() {
      if (unaryconn(sym)) {
        nextSym();
        if (formula() == 0) return 0;
        return 1;
      } else if (accept("(")) {
        if (formula() == 0) return 0;
        if (binaryconn(sym) == 0) return 0;
        nextSym();
        if (formula() == 0) return 0;
        if (!expect(")")) return 0;
        return 1;
      } else if (proposition(sym)) {
        nextSym();
        return 1;
      } else {
        return 0;
      }
    }

    function unaryconn(s) {
      if (s == "~") {
        return 1;
      } else {
        return 0;
      }

    }

    function binaryconn(s) {
      if (s == "&") {
        return 1;
      } else {
        return 0;
      }
    }

    function proposition(s) {
      if (s == "p" || s == "q" || s == "r") {
        return 1;
      } else {
        return 0;
      }
    }
    </script>
  </head>

  <body>
    <h1>Logic App</h1>

    <h2>Check if formula is well-formed:</h2>
    <p>Enter a formula into the text box and click "Validate" to see if it is a
    wff.</p>

    <form id='frmValidateFormula'>
      <p>
        <input
          type='text'
          id='formulaentry'
          placeholder='Input formula here'>
      </p>
      <p>
        <input
          type='button'
          id='btnValidate'
          value='Validate'
          onclick='validate()'>
      </p>
    </form>
  </body>
</html>

解析器似乎可以正常工作。它正确地将以下字符串解析为有效公式:

p
~p
(p&p)
~(p&p)
(~(p&~~p)&(~p&~p))

但是,当它们应返回“无效”时,会错误地为这些字符串返回“有效”:

p~
pp
~p~
p&
p(
p)
ppqqpqpq

在这些情况下,解析器似乎不检查整个字符串,仅检查导致第一个字母的字符和字母本身,因此认为它很好。我尝试在“ else if(proposition(sym)”部分中的Formula()中添加某种形式的验证,以确保字母后面的字符是有效的字符,但这没有用,因为有效字符取决于什么更改语法可能会有所帮助。我不太了解我在创建这些语法时应该考虑的事项,除了左递归会给递归下降解析器带来麻烦。我查看了有关Stack Overflow递归下降的几个问题解析器,但似乎没有一个可以帮助我解决我的问题。

如何更新解析器,使此类字符串返回“ Invalid”作为结果?我并不一定要找到完整的答案,而只是要指出一些要考虑的事情或要看的资源。如果您还知道在构造语法时要考虑什么的好资源(尤其是在解析器方面),那将是很棒的事情。

注意:我的解析器当前不处理空格。我现在对此表示满意,因为我主要关心的是在更新内容以处理空白之前正确地进行其他解析。

1 个答案:

答案 0 :(得分:1)

我还没有对您的代码进行过彻底的研究,但这是我的印象:

您的解析器正在检查以查看它看到的第一组字符是否形成有效公式,然后停止。如果之后发生垃圾,没关系,则解析器仍然很高兴,因为它找到了有效的公式。

我在语法中看到了两种处理方法:

  • 要求公式以“流的结尾”元字符结尾

  • 添加与一系列公式匹配的新规则。例如

<document> ::= <formula> |
               <formula> <document>

(当然,这是左递归的,但是您应该可以解决此问题而没有太多麻烦。)

也:

} else if (proposition(sym)) {
    nextSym();
}

我怀疑该分支没有返回任何内容。