Lemon Parser:这个规则不能减少

时间:2017-10-19 21:31:19

标签: parsing grammar lalr lemon

我正在尝试编写一个语法来解析模板语言jinja2(或您选择的twig),而且我无法成功解析switch-case语句。

让我展示所需的语法:

{% switch username %}
    {% case "Jim" %}
        I want to say: 
    {% case "Nik" %}
        Hello man!
    {% endcase %}
    {% case "Bob" %}
        Hi
    {% default %}
        Who are you?
{% endswitch %}

这里endcase只是作为休息。

我的语法文件的工作部分:

program ::= template_language(Q) . {
    status->ret = Q;
}

template_language(R) ::= statement_list(L) . {
    R = L;
}

statement_list(R) ::= statement_list(L) statement(S) . {
    R = my_list(L, S);
}

statement_list(R) ::= statement(S) . {
    R = my_list(NULL, S);
}

statement(R) ::= switch_statement(E) . {
    R = E;
}

// empty {% switch expr %} {% endswitch %}
switch_statement(R) ::= OPEN_DELIMITER SWITCH expr(E) CLOSE_DELIMITER OPEN_DELIMITER ENDSWITCH CLOSE_DELIMITER . {
    R = my_switch_statement(E, NULL, status->scanner_state);
}

switch_statement(R) ::= OPEN_DELIMITER SWITCH expr(E) CLOSE_DELIMITER case_clauses(C) OPEN_DELIMITER ENDSWITCH CLOSE_DELIMITER . {
    R = my_switch_statement(E, C, status->scanner_state);
}

case_clauses(R) ::= case_clauses(C) case_clause(K) . {
    R = my_list(C, K);
}

case_clauses(R) ::= case_clause(K) . {
    R = my_list(NULL, K);
}

// empty {% case expr %} {% endcase %}
case_clause(R) ::= OPEN_DELIMITER CASE expr(E) CLOSE_DELIMITER OPEN_DELIMITER ENDCASE CLOSE_DELIMITER . {
    R = case_clause(E, NULL, status->scanner_state);
}

case_clause(R) ::= OPEN_DELIMITER CASE expr(E) CLOSE_DELIMITER statement_list(T) OPEN_DELIMITER ENDCASE CLOSE_DELIMITER . {
    R = case_clause(E, T, status->scanner_state);
}

这只是我语法的一部分,我为forifwhiledoloop等工作语法。

但我不知道:

  1. {% case expr %} statement_list(T)没有{% endcase %}
  2. {% default %} statement_list(T)
  3. 例如我试图使用:

    case_clause(R) ::= OPEN_DELIMITER CASE expr(E) CLOSE_DELIMITER statement_list(T) . {
        R = case_clause(E, T, status->scanner_state);
    }
    

    #1但没​​有运气,得到了

      

    此规则无法减少。

    同样的#2

    坦率地说,我理解问题的根源 - 缺少案例/默认限制,但实际上我不知道如何解决这个问题。

    非常感谢任何帮助!

1 个答案:

答案 0 :(得分:3)

问题是你的语法是LR(2),而不是LR(1)。

出现了许多转移/减少冲突,因为在看到%{之后的令牌之前,无法知道该怎么做。例如,考虑部分模板(我故意破坏了缩进):

{% switch username %} {% case "Jim" %} I want to say: {%

现在,是否应将粗体部分缩减为case_clause

请记住,在LR(k)语法中,必须通过仅查看要减少的序列末尾之后的k标记来做出减少的决定。与大多数LR解析器生成器一样,Lemon只实现LR(1)解析器,因此需要仅使用一个前瞻令牌(%}来做出决策。但是,如果不知道 next 令牌是什么,就无法做出决定:

{% switch username %} {% case "Jim" %} I want to say: {% endcase
{% switch username %} {% case "Jim" %} I want to say: {% case
{% switch username %} {% case "Jim" %} I want to say: {% switch

在第一个输入中,我们不进行缩减,但是我们已经到了statement_list的末尾。在第二个中,我们需要减少因为我们找到了整个case_clause。在第三个问题中,我们已经启动了一个新的statement,需要将其附加到statement_list

第一个和第三个可能的输入没有问题,因为它们都只对应一个换档动作;必要的减少 - 无论哪一个 - 都将在以后执行。但是第二个需要在%{之前进行缩减,当我们看到case令牌时,为时已晚。

在我看来,最简单的解决方案是强制词法分析器将{% keyword识别为单个标记(每个关键字都不同)。例如,以下内容与您的语法不同之处仅在于OPEN_DELIMITER FOO的每个实例都已被OPEN_FOO替换,并未出现任何问题:(我还将CLOSE_DELIMITER替换为CLOSE避免水平滚动。)

program ::= template_language(Q) . {
    status->ret = Q;
}

template_language(R) ::= statement_list(L) . {
    R = L;
}

statement_list(R) ::= statement_list(L) statement(S) . {
    R = my_list(L, S);
}

statement_list(R) ::= statement(S) . {
    R = my_list(NULL, S);
}

statement(R) ::= switch_statement(E) . {
    R = E;
}

// empty {% switch expr %} {% endswitch %}
switch_statement(R) ::= OPEN_SWITCH expr(E) CLOSE OPEN_ENDSWITCH CLOSE . {
    R = my_switch_statement(E, NULL, status->scanner_state);
}

switch_statement(R) ::= OPEN_SWITCH expr(E) CLOSE case_clauses(C) OPEN_ENDSWITCH CLOSE . {
    R = my_switch_statement(E, C, status->scanner_state);
}

case_clauses(R) ::= case_clauses(C) case_clause(K) . {
    R = my_list(C, K);
}

case_clauses(R) ::= case_clause(K) . {
    R = my_list(NULL, K);
}

// empty {% case expr %} {% endcase %}
case_clause(R) ::= OPEN_CASE expr(E) CLOSE OPEN_ENDCASE CLOSE . {
    R = case_clause(E, NULL, status->scanner_state);
}

case_clause(R) ::= OPEN_CASE expr(E) CLOSE statement_list(T) OPEN_ENDCASE CLOSE . {
    R = case_clause(E, T, status->scanner_state);
}

case_clause(R) ::= OPEN_CASE expr(E) CLOSE statement_list(T) . {
    R = case_clause(E, T, status->scanner_state);
}


case_clause(R) ::= OPEN_DEFAULT CLOSE statement_list(T) . {
    R = case_clause(E, T, status->scanner_state);
}

作为旁注,我建议通过不特殊的套接空语句列表来简化语法。只允许statement_list的空基础案例:

program ::= template_language(Q) . {
    status->ret = Q;
}

template_language(R) ::= statement_list(L) . {
    R = L;
}

statement_list(R) ::= statement_list(L) statement(S) . {
    R = my_list(L, S);
}

statement_list(R) ::= . {
    R = NULL;
}

statement(R) ::= switch_statement(E) . {
    R = E;
}

switch_statement(R) ::= OPEN_SWITCH expr(E) CLOSE case_clauses(C) OPEN_ENDSWITCH CLOSE . {
    R = my_switch_statement(E, C, status->scanner_state);
}

case_clauses(R) ::= case_clauses(C) case_clause(K) . {
    R = my_list(C, K);
}

case_clauses(R) ::= . {
    R = NULL;
}

case_clause(R) ::= OPEN_CASE expr(E) CLOSE statement_list(T) OPEN_ENDCASE CLOSE . {
    R = case_clause(E, T, status->scanner_state);
}

case_clause(R) ::= OPEN_CASE expr(E) CLOSE statement_list(T) . {
    R = case_clause(E, T, status->scanner_state);
}

case_clause(R) ::= OPEN_DEFAULT CLOSE statement_list(T) . {
    R = case_clause(E, T, status->scanner_state);
}