【问题标题】:Lemon Parser: This rule can not be reducedLemon Parser:这条规则不能减少
【发布时间】:2017-10-19 21:31:19
【问题描述】:

我正在尝试编写一个语法来解析模板语言,比如 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)

例如我尝试使用:

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

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

这条规则不能减少。

#2 也一样

坦率地说,我了解问题的根源 - 缺少大小写/默认绑定,但实际上我不知道如何解决这个问题。

任何帮助将不胜感激!

【问题讨论】:

    标签: parsing grammar lalr lemon


    【解决方案1】:

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

    出现许多移位/减少冲突是因为在看到%{ 之后的标记之前不可能知道要做什么。例如,考虑部分模板(我故意破坏了缩进):

    {% switch username %} <b>{% case "Jim" %} I want to say:</b> {%

    现在,粗体部分是否应该减少为case_clause

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

    {% switch username %} <b>{% case "Jim" %} I want to say:</b> {% <b><i>endcase</i></b>
    {% switch username %} <b>{% case "Jim" %} I want to say:</b> {% <b><i>case</i></b>
    {% switch username %} <b>{% case "Jim" %} I want to say:</b> {% <b><i>switch</i></b>

    在第一个输入中,我们没有做归约,但我们已经到了statement_list 的末尾。在第二个中,我们需要减少,因为我们找到了整个case_clause。在第三个中,我们开始了一个新的statement,它需要附加到statement_list

    第一个和第三个可能的输入没有问题,因为它们都只对应一个换档动作;必要的削减——无论是哪一项——将在以后进行。但是第二个需要在%{ 之前发生reduce,当我们看到case 标记时,已经太晚了。

    在我看来,最简单的解决方案是强制词法分析器将{% <em>keyword</em> 识别为单个标记(每个关键字不同)。例如,以下内容与您的语法不同之处仅在于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);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2022-10-21
      • 2022-10-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多