0

我有一个 AngularJS 网络应用程序。

我想在我的应用程序中使用 peg.js。我刚刚写了一个 peg.js 语法: CriteriaValue.pegjs 并使用命令行生成了解析器: pegjs CriteriaValue.pegjs,它生成了 CriteriaValue.js。

有人可以向我解释如何使用解析器吗?

var result = parser.parse('我的字符串'); 不起作用。

我创建了一个 plunker: http ://plnkr.co/edit/Ae05SeZAjKOQ75B3lvLc?p=preview

4

1 回答 1

4

简答

  • 在 CriteriaValue.jsmodule.exports中,将第一行更改为parser
  • 在 index.html 中,交换<script>标签,以便 CriteriaValue.js 出现在第一位
  • (可选)在 script.js 中,将解析结果输出为格式化的 JSON 字符串,以便查看实际值

这是 plunker:http ://plnkr.co/edit/kiBp2Na9s4PXpenCzQjx?p=preview

长答案

运行你原来的 plunker 并检查控制台日志;你会注意到 2 个错误:

  • ReferenceError: Can't find variable: parser (script.js:3)
  • ReferenceError: Can't find variable: error (CriteriaValue.js:1)

第一个错误是由于parserscript.js 或 CriteriaValue.js 在全局范围内没有创建任何对象。

查看 CriteriaValue.js,您可以看到它实际上是将生成的解析器对象分配给不存在的modules.export. 这是 PEG.js 的默认行为,因为它假定您将解析器与 node.js 一起使用。您看到错误的原因是没有module对象,所以我们不能分配给这个不存在的对象的export属性。将分配更改为parser,这是我们可以分配的(因为 PEG.js 不使用严格模式),避免了这个错误并可以parser在 script.js 中使用。

最后,需要先创建解析器,script.js 才能使用它;<script>因此交换的原因。

为了将来创建 CriteriaValue.js,请这样做:

pegjs --export-var parser CriteriaValue.pegjs

这将生成文件,以便将对象分配给变量parser而不是module.exports.

AngularJS 的用武之地

正如@dirkk 在评论中所说,将解析器定义为全局变量是不好的做法,当然也不是 AngularJS 的方式,即将解析器实现为服务。

最快(但不一定是最好)的方法是获取您已经生成的 CriteriaValue.js 代码并围绕它包装一个服务。例如:

angular.module('yourApp.services', [])
.factory('Parser', function() {
  // The generated code, except replace "parser = " with "return "
});

另一种选择是获取 .pegjs 文件并使用以下命令在客户端生成解析器PEG.buildParser()

angular.module('yourApp.services', [])
.factory('Parser', ['$http', '$q', function($http, $q) {
  var deferred = $q.defer();
  $http.get('path/to/CriteriaValue.pegjs')
  .success(function(grammar) {
    try {
      deferred.resolve(PEG.buildParser(grammar));
    } catch (e) {
      deferred.reject(e);
    }
  })
  .error(function(message) {
    deferred.reject('Unable to load grammar: ' + message);
  });

  return deferred.promise;
}]);

这使得更新语法更容易,因为您不必每次都重写您的服务,但它增加了加载应用程序的延迟。这样做的可行性取决于您的语法有多复杂以及它实际需要更改的频率。

不管你如何构建你的解析器,你不一定需要将生成的解析器对象直接暴露给你的 Angular 应用程序的其余部分。相反,您可以为您的应用程序使用此解析器实际执行的操作实现更高级别的 API(例如validate(input),getAST(input)等...)。这样,如果您决定在将来切换到不同的解析器(例如 Jison),您需要更改的代码就会少得多。

于 2015-06-12T08:00:27.273 回答