当前位置: 首页 > 知识库问答 >
问题:

如何使用Jison lexer返回多个令牌

魏波娃
2023-03-14

我不熟悉词法分析,如果标题不够清晰,我很抱歉。

基本上,我使用Jison来解析一些文本,并试图让lexer理解缩进。这里有一点值得商榷:

(\r\n|\r|\n)+\s*      %{
                        parser.indentCount = parser.indentCount || [0];

                        var indentation = yytext.replace(/^(\r\n|\r|\n)+/, '').length;

                        if (indentation > parser.indentCount[0]) {
                           parser.indentCount.unshift(indentation);
                           return 'INDENT';
                        }

                        var tokens = [];

                        while (indentation < parser.indentCount[0]) {
                          tokens.push('DEDENT');
                          parser.indentCount.shift();
                        }

                        if (tokens.length) {
                           return tokens;
                        }

                        if (!indentation.length) {
                          return 'NEWLINE';
                        }
                      %}

到目前为止,几乎所有这些都像预期的那样工作。一个问题是我试图返回一个DEDENT令牌数组的行。看来Jison只是将该数组转换成一个字符串,这导致我得到一个解析错误,如期待......,得到了DEDENT,DEDENT

我希望我能做的是手动将一些DEDENT令牌推到堆栈上。也许有一个像这样的函数。pushToken('DEDENT')或类似的东西。但是Jison的文档不是很好,我需要一些帮助。

有什么想法吗?

编辑:

在查看了生成的解析器代码后,我似乎已经能够破解这个问题。以下是似乎有效的方法...

if (tokens.length) {
  var args = arguments;

  tokens.slice(1).forEach(function () {
    lexer.performAction.apply(this, args);
  }.bind(this));

  return 'DEDENT';
}

这会诱使lexer对堆栈中的每个DEDENT使用完全相同的输入执行另一个操作,从而允许它添加正确的DEDENT。然而,感觉很恶心,我担心可能会有不可预见的问题。

如果有人对更好的方法有任何想法,我仍然会喜欢它。

共有1个答案

周墨一
2023-03-14

几天后,我终于想出了一个更好的答案。下面是它的样子:

(\r\n|\r|\n)+[ \t]*   %{
                        parser.indentCount = parser.indentCount || [0];
                        parser.forceDedent = parser.forceDedent || 0;

                        if (parser.forceDedent) {
                          parser.forceDedent -= 1;
                          this.unput(yytext);
                          return 'DEDENT';
                        }

                        var indentation = yytext.replace(/^(\r\n|\r|\n)+/, '').length;

                        if (indentation > parser.indentCount[0]) {
                           parser.indentCount.unshift(indentation);
                           return 'INDENT';
                        }

                        var dedents = [];

                        while (indentation < parser.indentCount[0]) {
                          dedents.push('DEDENT');
                          parser.indentCount.shift();
                        }

                        if (dedents.length) {
                           parser.forceDedent = dedents.length - 1;
                           this.unput(yytext);
                           return 'DEDENT';
                        }

                        return `NEWLINE`;
                      %}

首先,我修改了捕获正则表达式,以确保在一系列非换行符空格之后不会无意中捕获额外的换行符。

接下来,我们要确保有两个“全局”变量<代码>缩进计数将跟踪我们当前的缩进长度forcedDent将强制我们返回DEDENT,如果它的值大于0。

接下来,我们有一个条件来测试forceDedent上的真实值。如果我们有一个,我们将把它递减1,并使用unput函数来确保我们至少在同一个模式上迭代一次,但是对于这个迭代,我们将返回一个DEDENT

如果我们没有返回,我们将得到当前缩进的长度。

如果当前缩进大于最近的缩进,我们将在indentCount变量上跟踪它,并返回INDENT

如果我们还没有回来,是时候准备可能的情况了。我们会组成一个阵列来跟踪他们。

当我们检测到dedent时,用户可能试图同时关闭一个或多个块。因此,我们需要在用户关闭时包含一个DEDENT。我们设置了一个循环,只要当前缩进小于我们最近的缩进,我们就会在列表中添加一个DEDENT,并从indentCount中删除一个项目。

如果我们追踪到任何Dedent,我们需要确保lexer返回所有Dedent。因为lexer一次只能返回1个令牌,所以我们将在这里返回1,但我们还将设置forceDedent变量,以确保我们也返回其余的令牌。为了确保我们再次迭代这个模式,并且可以插入这些dedent,我们将使用unput函数

在任何其他情况下,我们只返回一个换行符

 类似资料:
  • 下面的问题来自于CodingBat:给定一个数组,是否可以选择一组整数,使其与给定的目标相加? 站点作者提供了以下解决方案: 假设我想尝试下面的例子,其中nums=[2,4,8]并调用groupSum(0,nums,10)。 我看到将调用和。 调用和 调用和 等等。 在处理代码时,我看到了以下调用: 我看到应该返回true,因为第一行: ,但我对其他调用感到困惑,如。由于,从第一行开始,它应该清楚

  • 问题内容: 在Java中是否可以从方法返回两个或多个值到main?如果是这样,有可能吗?如果没有,我们怎么办? 问题答案: 你可以使用Java返回Class的对象。 如果要返回多个相关的值,则将它们封装到一个类中,然后返回该类的对象是有意义的。 如果要返回不相关的值,则可以使用Java的内置容器类(例如Map,List,Set等)。有关更多详细信息,请检查java.util包的JavaDoc。

  • 我正在尝试使用FastAPI MongoDB创建一个API,它可以从请求中返回多个值。MongoDB充满了数据,使用mongoengine,我可以在向特定endpoint发送请求时查阅一个或所有数据。我现在要做的是从endpoint接收一个或多个数据,例如: 当查询endpoint< code > http://127 . 0 . 0 . 1:8000/rice 时,我得到一个JSON响应,其中包

  • 我试图使用这个查询返回一个节点对象和一个计算字段。理论上,这应该会返回一个散列,我可以访问每个人,计算并导入velocity模板。

  • 问题内容: 我用Java写了一个函数,我希望这个函数返回多个值。除了使用数组和结构外,还有没有办法返回多个值? 我的代码: 问题答案: 在Java中,当您希望函数返回多个值时,必须 将这些值嵌入到您返回的对象中 或更改传递给函数的对象 在您的情况下,您显然需要定义一个可以包含,和的类: 然后将您的功能更改为

  • 问题内容: 选项:使用元组 考虑下面这个简单的例子: 但是,随着返回值的数量增加,这很快就会成为问题。如果要返回四个或五个值怎么办?当然,你可以继续修改它们,但是很容易忘记哪个值在哪里。在任何想要接收它们的地方打开它们的包装也是很丑陋的。 选项:使用字典 下一步的逻辑步骤似乎是引入某种“记录符号”。在Python中,一种明显的方法是使用dict。 考虑以下: (请注意,y0,y1和y2只是抽象标识