终止 PEG.js 中的表达式列表

问题描述

我还有一个关于 How to extend default PEG.js arithmetic example to allow multiple expressions not single one?

的问题

我有这个语法:

start = code:statements {
    return {
      "type": "Program","body": code
    };
 }

statements = head:(if / expression_statement) tail:(_ (if / expression_statement))* {
    return [head].concat(tail.map(function(element) {
      return element[1];
    })); 
  }

expression_statement = expression:expression {
    return  {
      "type": "ExpressionStatement","expression": expression
    };
}


if = "if" _ expression:(comparison / expression) _ "then" body:(statements / _) "end" {
   return {
     "type": "IfStatement","test": expression,"consequent": {
        "type": "BlockStatement","body": body
     },"alternate": null
   };
}

expression = expression:(arithmetic / literal) { return expression; }

literal = value:(string / Integer) {
   return {"type": "Literal","value": value };
}

variable = variable:name {
  return {
    "type": "Identifier","name": variable
  }
}

name = [A-Z_a-z][A-Z_a-z0-9]* { return text(); }

comparison = _ left:expression _ "==" _ right:expression _ {
   return {
        "type": "BinaryExpression","operator": "==","left": left,"right": right
   };
}

string = "\"" ([^"] / "\\\\\"")*  "\"" {
  return JSON.parse(text());
}

arithmetic
  = head:term tail:(_ ("+" / "-") _ term)* {
      return tail.reduce(function(result,element) {
          return {
            "type": "BinaryExpression","operator": element[1],"left": result,"right": element[3]
          };
      },head);
    }

term
  = head:factor tail:(_ ("*" / "/") _ factor)* {
      return tail.reduce(function(result,head);
    }

factor
  = "(" _ expr:arithmetic _ ")" { return expr; }
  / literal

Integer "integer"
  = _ [0-9]+ { return parseInt(text(),10); }

_ "whitespace"
  = [ \t\n\r]* {
   return [];
}

解析器用于创建 JavaScript AST(使用 esprima 对象结构)。

我试图解析 ruby​​ 之类的 if 语句:

这很好用,它创建了空的 if

if "foo" == "bar" then

end

但这无法解析:

if "foo" == "bar" then
10 + 10
end

它因错误而失败:

Parse Error: Expected "(","*","+","-","/","\"","if",or integer but "e" found.

Error in line 3
end
^

我还希望它可以处理多行:

if "foo" == "bar" then
10 + 10
10 * 10
end

我认为我应该在前面输入“end”,但我不确定在哪里。

编辑:我正在尝试这个:

statements = head:(if / expression_statement)  tail:(_ &"end" / (if / expression_statement)*) {
    return [head].concat(tail.map(function(element) {
      if (element) {
        return element[2];
      }
    }).filter(Boolean)); 
  }

但它不适用于两个表达式行,如果我在最后使用 *

tail:(_ &"end" / (if / expression_statement))*

我遇到了无限循环解析器错误。我也尝试了 &"end" 的多种组合,但它们不起作用。我也在 GitHub pegjs/pegjs#57 上发现了这个问题,但它没有任何帮助。

解决方法

我已经用这段代码解决了这个问题:

statements = head:(if / expression_statement)  tail:( (!"end" _  (if / expression_statement) .)*) {
    return [head].concat(tail.map(function(element) {
      if (element) {
        return element[2];
      }
    }).filter(Boolean)); 
  }