首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用Sablecc移动/减少冲突

使用Sablecc移动/减少冲突
EN

Stack Overflow用户
提问于 2018-11-06 17:28:13
回答 1查看 397关注 0票数 1

我应该使用Sablecc为MiniPython编写一个MiniPython文件。我得到这些转换/减少冲突:

代码语言:javascript
复制
shift/reduce conflict in state [stack: TIf PTpower *] on TMult in {
     [ PMltp = * TMult PTopower Mltp ] (shift)
     [ PMlpt = * ] followed by TMult (reduce)
}

shift/reduce conflict in state [stack: TIf PTopower *] on TDiv in {
     [ PMltp = * TDiv PTopower Mltp ] (shift)
     [ PMltp = * ] followed by TDiv (reduce)
}

其中一些令牌是:

代码语言:javascript
复制
id = letter (letter | digit)*;
digit = ['0' .. '9'];
letter = ['a' .. 'z']|['A' .. 'Z'];
pow = '**';
mult = '*';
div = '/';
plus = '+';
minus = '-';
assert = 'assert';
l_par = '(';
r_par = ')';
l_bra = '[';
r_bra = ']';

我的.grammar文件的一部分是:

代码语言:javascript
复制
expression = multiplication exprsn;

exprsn =   {addition} plus multiplication exprsn
         | {subtraction} minus multiplication exprsn
         | {empty};

topower = something tpwr;

tpwr =   {topower} pow something tpwr
       | {empty};

multiplication = topower mltp;

mltp =   {multiplication} mult topower mltp
       | {division} div topower mltp
       | {empty};

something =   {id} id
            | {parexp} l_par expression r_par
            | {fcall} functioncall
            | {value} value
            | {list} id l_bra expression r_bra
            | {other} l_bra value comval* r_bra
            | {assert} assert expression comexpr?;

comexpr = comma expression;

这是我试图消除左递归之后的语法。我注意到,如果我从assert产品中删除了something规则,就不会有任何冲突。同时,将{empty}规则从exprsntpwrmltp规则中删除也没有冲突,但我认为这不是解决这一问题的正确方法。

任何建议都会很感激的。

更新:以下是根据请求删除左递归之前的整个语法:

代码语言:javascript
复制
Package minipython;

Helpers
    digit = ['0' .. '9'];
    letter = ['a' .. 'z']|['A' .. 'Z']; 
    cr = 13; 
    lf = 10;
    all = [0..127]; 
    eol = lf | cr | cr lf ;
    not_eol = [all - [cr + lf]]; 

Tokens
    tab = 9;
    plus = '+';
    dot = '.';
    pow = '**';
    minus = '-';
    mult = '*';
    div = '/';
    eq = '=';
    minuseq = '-=';
    diveq = '/=';
    exclam = '!';
    def = 'def';
    equal = '==';
    nequal = '!=';
    l_par = '(';
    r_par = ')';
    l_bra = '[';
    r_bra = ']';
    comma= ',';
    qmark = '?';
    gqmark = ';';
    assert = 'assert';
    if = 'if';
    while = 'while';
    for = 'for';
    in = 'in';
    print = 'print';
    return = 'return';
    importkn = 'import';
    as = 'as';
    from = 'from';
    less = '<';
    great = '>';
    true = 'true';
    semi = ':';
    false = 'false';
    quote = '"';
    blank = (' ' | lf | cr);
    line_comment = '#' not_eol* eol; 
    number = digit+ | (digit+ '.' digit+);
    id = letter (letter | digit)*;
    string = '"'not_eol* '"';
    cstring = ''' letter ''';

Ignored Tokens
    blank, line_comment;

Productions
program = commands*;

commands =   {stmt} statement
           | {func} function;

function = def id l_par argument? r_par semi statement;

argument = id eqval? ceidv*;

eqval = eq value;

ceidv = comma id eqval?;

statement =   {if} tab* if comparison semi statement
            | {while} tab* while comparison semi statement
            | {for} tab* for [id1]:id in [id2]:id semi statement
            | {return} tab* return expression
            | {print} tab* print expression comexpr*
            | {assign} tab* id eq expression
            | {minassign} tab* id minuseq expression
            | {divassign} tab* id diveq expression
            | {list} tab* id l_bra [ex1]:expression r_bra eq [ex2]:expression
            | {fcall} tab* functioncall
            | {import} import;

comexpr = comma expression;

expression =   {multiplication} multiplication
             | {addition} expression plus multiplication
             | {subtraction} expression minus multiplication;

topower =   {smth} something
          | {power} topower pow something;

something =   {id} id
            | {parexp} l_par expression r_par
            | {fcall} functioncall
            | {value} value
            | {list} id l_bra expression r_bra
            | {assert} assert expression comexpr?
            | {other} l_bra value comval* r_bra;

comval = comma value;   

multiplication =   {power} topower
                 | {multiplication} multiplication mult topower
                 | {division} multiplication div topower;

import =   {import} importkn module asid? comod*
         | {from} from module importkn id asid? comid*;

asid = as id;

comod = comma module asid?;

comid = comma id asid?;

module = idot* id;

idot = id dot;

comparison =   {true} true
             | {false} false
             | {greater} [ex1]:expression great [ex2]:expression
             | {lesser} [ex1]:expression less [ex2]:expression
             | {equals} [ex1]:expression equal [ex2]:expression
             | {nequals} [ex1]:expression nequal [ex2]:expression;

functioncall = id l_par arglist? r_par;

arglist = expression comexpr*;

value =   {fcall} id dot functioncall
        | {numb} number
        | {str} string
        | {cstr} cstring;

现在的转移/减少冲突是:

代码语言:javascript
复制
shift/reduce conflict in state [stack: TIf PTopower *] on TPow in {
     [ PMultiplication - PTopower * ] followed by TPow (reduce),
     [ PTopower = PTopower * TPow PSomething ] (shift)
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-11-06 18:58:44

(注:这个答案是从原来的语法中得出的,而不是试图删除左递归,这有一些额外的问题。)没有必要从提供给LALR(1)解析器生成器(如SableCC)的语法中删除左递归。

实际上,基本问题是生产:

代码语言:javascript
复制
something = {assert} assert expression comexpr?

这一成果令人好奇,部分原因在于非终端(“某某物”)的名称没有提供任何关于它是什么的提示,但主要是因为人们通常希望assert expression是一个语句,而不是表达式的一部分。something显然是从expression派生出来的

代码语言:javascript
复制
expression = multiplication
multiplication = topower
topower = something

但是assert的生产以一个expression结束。这会导致歧义,因为

代码语言:javascript
复制
assert 4 + 3

可以将其解析为:(为简洁起见省略的一些步骤):

代码语言:javascript
复制
expression = expression     plus    multiplication
                |             |           |
                V             |           |
            something         |           |
                |             |           |
                V             |           |
          assert expression   |           |
             |        |       |           |
             |        V       V           V
          assert      4       +           3

或者更自然地,如:

代码语言:javascript
复制
expression =          something
                          |
                          V
             assert                expression
                |                      |
                |                      V
                |          expression plus multiplication
                |               |       |        |
                |               V       V        V
             assert             4       +        3

第一个解析似乎不太可能,因为assert实际上没有返回一个值(据我估计)。(虽然第二种方法更自然,如果操作人员是比较而不是添加的话。)

如果没有看到您要解析的语言的定义,我就无法为如何解决这个问题提供具体建议,但我倾向于让assert成为一条语句,并将something重命名为更具描述性的东西(“术语”很常见,尽管我通常使用"atom")。

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53177000

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档