Ply shift/reduce 冲突:悬挂 else 和空制作

Ply shift/reduce conflicts: dangling else and empty productions

我有很多冲突,其中大部分是由于运算符和关系运算符具有不同的优先级。但我仍然面临一些我真的不知道如何解决的冲突。其中一些在下面。我怀疑也许我应该对 stmtlist 进行 epsilon 消除,但老实说我不确定。

状态 70:

state 70

    (27) block -> LCB varlist . stmtlist RCB
    (25) varlist -> varlist . vardec
    (28) stmtlist -> . stmt
    (29) stmtlist -> . stmtlist stmt
    (30) stmtlist -> .
    (15) vardec -> . type idlist SEMICOLON
    (33) stmt -> . RETURN exp SEMICOLON
    (34) stmt -> . exp SEMICOLON
    (35) stmt -> . WHILE LRB exp RRB stmt
    (36) stmt -> . FOR LRB exp SEMICOLON exp SEMICOLON exp RRB stmt
    (37) stmt -> . IF LRB exp RRB stmt elseiflist
    (38) stmt -> . IF LRB exp RRB stmt elseiflist ELSE stmt
    (39) stmt -> . PRINT LRB ID RRB SEMICOLON
    (40) stmt -> . block
    (7) type -> . INTEGER
    (8) type -> . FLOAT
    (9) type -> . BOOLEAN
    (44) exp -> . lvalue ASSIGN exp
    (45) exp -> . exp SUM exp
    (46) exp -> . exp MUL exp
    (47) exp -> . exp SUB exp
    (48) exp -> . exp DIV exp
    (49) exp -> . exp MOD exp
    (50) exp -> . exp AND exp
    (51) exp -> . exp OR exp
    (52) exp -> . exp LT exp
    (53) exp -> . exp LE exp
    (54) exp -> . exp GT exp
    (55) exp -> . exp GE exp
    (56) exp -> . exp NE exp
    (57) exp -> . exp EQ exp
    (58) exp -> . const
    (59) exp -> . lvalue
    (60) exp -> . ID LRB explist RRB
    (61) exp -> . LRB exp RRB
    (62) exp -> . ID LRB RRB
    (63) exp -> . SUB exp
    (64) exp -> . NOT exp
    (27) block -> . LCB varlist stmtlist RCB
    (31) lvalue -> . ID
    (32) lvalue -> . ID LSB exp RSB
    (72) const -> . INTEGERNUMBER
    (73) const -> . FLOATNUMBER
    (74) const -> . TRUE
    (75) const -> . FALSE

  ! shift/reduce conflict for RETURN resolved as shift
  ! shift/reduce conflict for WHILE resolved as shift
  ! shift/reduce conflict for FOR resolved as shift
  ! shift/reduce conflict for IF resolved as shift
  ! shift/reduce conflict for PRINT resolved as shift
  ! shift/reduce conflict for ID resolved as shift
  ! shift/reduce conflict for LRB resolved as shift
  ! shift/reduce conflict for SUB resolved as shift
  ! shift/reduce conflict for NOT resolved as shift
  ! shift/reduce conflict for LCB resolved as shift
  ! shift/reduce conflict for INTEGERNUMBER resolved as shift
  ! shift/reduce conflict for FLOATNUMBER resolved as shift
  ! shift/reduce conflict for TRUE resolved as shift
  ! shift/reduce conflict for FALSE resolved as shift
    RCB             reduce using rule 30 (stmtlist -> .)
    RETURN          shift and go to state 99
    WHILE           shift and go to state 101
    FOR             shift and go to state 102
    IF              shift and go to state 103
    PRINT           shift and go to state 104
    INTEGER         shift and go to state 8
    FLOAT           shift and go to state 9
    BOOLEAN         shift and go to state 10
    ID              shift and go to state 31
    LRB             shift and go to state 36
    SUB             shift and go to state 34
    NOT             shift and go to state 37
    LCB             shift and go to state 45
    INTEGERNUMBER   shift and go to state 38
    FLOATNUMBER     shift and go to state 39
    TRUE            shift and go to state 40
    FALSE           shift and go to state 41

  ! RETURN          [ reduce using rule 30 (stmtlist -> .) ]
  ! WHILE           [ reduce using rule 30 (stmtlist -> .) ]
  ! FOR             [ reduce using rule 30 (stmtlist -> .) ]
  ! IF              [ reduce using rule 30 (stmtlist -> .) ]
  ! PRINT           [ reduce using rule 30 (stmtlist -> .) ]
  ! ID              [ reduce using rule 30 (stmtlist -> .) ]
  ! LRB             [ reduce using rule 30 (stmtlist -> .) ]
  ! SUB             [ reduce using rule 30 (stmtlist -> .) ]
  ! NOT             [ reduce using rule 30 (stmtlist -> .) ]
  ! LCB             [ reduce using rule 30 (stmtlist -> .) ]
  ! INTEGERNUMBER   [ reduce using rule 30 (stmtlist -> .) ]
  ! FLOATNUMBER     [ reduce using rule 30 (stmtlist -> .) ]
  ! TRUE            [ reduce using rule 30 (stmtlist -> .) ]
  ! FALSE           [ reduce using rule 30 (stmtlist -> .) ]

    stmtlist                       shift and go to state 96
    vardec                         shift and go to state 97
    stmt                           shift and go to state 98
    type                           shift and go to state 72
    exp                            shift and go to state 100
    block                          shift and go to state 105
    lvalue                         shift and go to state 33
    const                          shift and go to state 35 

这里是所有作品的列表:

program → declist main ( ) block

declist → dec | declist dec | 

dec → vardec | funcdec

type → int | float | bool

iddec → id | id [ exp ] | id=exp

idlist → iddec | idlist , iddec

vardec → type idlist ;

funcdec → type id (paramdecs) block | void id (paramdecs) block

paramdecs → paramdecslist | 

paramdecslist → paramdec | paramdecslist , paramdec

paramdec → type id | type id []

Precedencevarlist → vardec | varlist vardec | 

block → { varlist stmtlist }

stmtlist → stmt | stmlist stmt | 

lvalue → id | id [exp]

stmt → return exp ; | exp ;| block |

while (exp) stmt |

for(exp ; exp ; exp) stmt |

if (exp) stmt elseiflist | if (exp) stmt elseiflist else stmt |

print ( id) ;

elseiflist → elif (exp) stmt | elseiflist elif (exp) stmt | 

exp → lvalue=exp | exp operator exp |exp relop exp|

const | lvalue | id(explist) | (exp) | id() | - exp | ! exp

operator → “||” | && | + | - | * | / | %

const → intnumber | floatnumber | true | false

relop → > | < | != | == | <= | >=

explist → exp | explist,exp

另一个问题是著名的悬垂 else,我将 ('nonassoc', 'IFP'), ('left', 'ELSE' , 'ELIF') 添加到优先元组并以这种方式更改语法:

def p_stmt_5(self, p):
    """stmt : IF LRB exp RRB stmt elseiflist %prec IFP """
    print("""stmt : IF LRB exp RRB stmt elseiflist """)

def p_stmt_6(self, p):
    """stmt : IF LRB exp RRB stmt elseiflist ELSE stmt"""
    print("""stmt : IF LRB exp RRB stmt elseiflist else stmt """)

但这并没有让它消失。下面是发生 shift/reduce 冲突的状态。

状态 130

    (37) stmt -> IF LRB exp RRB stmt . elseiflist
    (38) stmt -> IF LRB exp RRB stmt . elseiflist ELSE stmt
    (41) elseiflist -> . ELIF LRB exp RRB stmt
    (42) elseiflist -> . elseiflist ELIF LRB exp RRB stmt
    (43) elseiflist -> .

  ! shift/reduce conflict for ELIF resolved as shift
    ELIF            shift and go to state 134
    RCB             reduce using rule 43 (elseiflist -> .)
    RETURN          reduce using rule 43 (elseiflist -> .)
    WHILE           reduce using rule 43 (elseiflist -> .)
    FOR             reduce using rule 43 (elseiflist -> .)
    IF              reduce using rule 43 (elseiflist -> .)
    PRINT           reduce using rule 43 (elseiflist -> .)
    ID              reduce using rule 43 (elseiflist -> .)
    LRB             reduce using rule 43 (elseiflist -> .)
    SUB             reduce using rule 43 (elseiflist -> .)
    NOT             reduce using rule 43 (elseiflist -> .)
    LCB             reduce using rule 43 (elseiflist -> .)
    INTEGERNUMBER   reduce using rule 43 (elseiflist -> .)
    FLOATNUMBER     reduce using rule 43 (elseiflist -> .)
    TRUE            reduce using rule 43 (elseiflist -> .)
    FALSE           reduce using rule 43 (elseiflist -> .)
    ELSE            reduce using rule 43 (elseiflist -> .)

  ! ELIF            [ reduce using rule 43 (elseiflist -> .) ]

    elseiflist                     shift and go to state 133

最后还有两个有 shift/reduce 错误的状态,我在下面列出:

state 45

    (27) block -> LCB . varlist stmtlist RCB
    (24) varlist -> . vardec
    (25) varlist -> . varlist vardec
    (26) varlist -> .
    (15) vardec -> . type idlist SEMICOLON
    (7) type -> . INTEGER
    (8) type -> . FLOAT
    (9) type -> . BOOLEAN

  ! shift/reduce conflict for INTEGER resolved as shift
  ! shift/reduce conflict for FLOAT resolved as shift
  ! shift/reduce conflict for BOOLEAN resolved as shift
    RETURN          reduce using rule 26 (varlist -> .)
    WHILE           reduce using rule 26 (varlist -> .)
    FOR             reduce using rule 26 (varlist -> .)
    IF              reduce using rule 26 (varlist -> .)
    PRINT           reduce using rule 26 (varlist -> .)
    ID              reduce using rule 26 (varlist -> .)
    LRB             reduce using rule 26 (varlist -> .)
    SUB             reduce using rule 26 (varlist -> .)
    NOT             reduce using rule 26 (varlist -> .)
    LCB             reduce using rule 26 (varlist -> .)
    INTEGERNUMBER   reduce using rule 26 (varlist -> .)
    FLOATNUMBER     reduce using rule 26 (varlist -> .)
    TRUE            reduce using rule 26 (varlist -> .)
    FALSE           reduce using rule 26 (varlist -> .)
    RCB             reduce using rule 26 (varlist -> .)
    INTEGER         shift and go to state 8
    FLOAT           shift and go to state 9
    BOOLEAN         shift and go to state 10

  ! INTEGER         [ reduce using rule 26 (varlist -> .) ]
  ! FLOAT           [ reduce using rule 26 (varlist -> .) ]
  ! BOOLEAN         [ reduce using rule 26 (varlist -> .) ]

    varlist                        shift and go to state 70
    vardec                         shift and go to state 71
    type                           shift and go to state 72

并且:

state 0

    (0) S' -> . program
    (1) program -> . declist MAIN LRB RRB block
    (2) declist -> . dec
    (3) declist -> . declist dec
    (4) declist -> .
    (5) dec -> . vardec
    (6) dec -> . funcdec
    (15) vardec -> . type idlist SEMICOLON
    (16) funcdec -> . type ID LRB paramdecs RRB block
    (17) funcdec -> . VOID ID LRB paramdecs RRB block
    (7) type -> . INTEGER
    (8) type -> . FLOAT
    (9) type -> . BOOLEAN

  ! shift/reduce conflict for VOID resolved as shift
  ! shift/reduce conflict for INTEGER resolved as shift
  ! shift/reduce conflict for FLOAT resolved as shift
  ! shift/reduce conflict for BOOLEAN resolved as shift
    MAIN            reduce using rule 4 (declist -> .)
    VOID            shift and go to state 7
    INTEGER         shift and go to state 8
    FLOAT           shift and go to state 9
    BOOLEAN         shift and go to state 10

  ! VOID            [ reduce using rule 4 (declist -> .) ]
  ! INTEGER         [ reduce using rule 4 (declist -> .) ]
  ! FLOAT           [ reduce using rule 4 (declist -> .) ]
  ! BOOLEAN         [ reduce using rule 4 (declist -> .) ]

    program                        shift and go to state 1
    declist                        shift and go to state 2
    dec                            shift and go to state 3
    vardec                         shift and go to state 4
    funcdec                        shift and go to state 5
    type                           shift and go to state 6

在此先感谢您。

这里实际上有两个有些相关的问题,都与递归产生式中重复的基本案例引起的歧义有关:

1。 stmtlist

中的歧义

首先,正如您所说,stmtlist 存在问题。 stmtlist 的语法是:

stmtlist → stmt | stmlist stmt | 

有两个基本情况:stmtlist → stmtstmtlist → 。这种重复意味着可以用两种方式解析单个 stmt

  1. stmtlist → stmt

  2. stmtlist → stmtlist stmt → stmt

语法歧义总是表现为冲突。消除冲突,消除歧义。如果您希望 stmtlist 可能为空,请使用:

stmtlist → stmlist stmt | 

如果你想坚持 stmtlist 至少包含一个 stmt,请使用:

stmtlist → stmlist stmt | stmt

最重要的是,尝试理解上述建议的逻辑。

此外,您允许 stmt 为空。很明显,这将导致 stmtlist 中的歧义,因为不可能知道列表中有多少个空的 stmt。可能是 3;可能是 42;可能是八百万。空是看不见的。

stmt 的潜在虚无也与那些以 stmt 结尾的复合语句产生歧义,例如 "while" '(' exp ')' stmt。如果 stmt 什么都不是,那么

while (x) while(y) c;

可以是两个语句:while(x) 有一个空的重复语句,然后 while(y) 有一个在 c; 上的循环。或者它可能具有(可能是预期的)while(x) 循环的含义,其重复语句是嵌套的 while(y) c;。我建议没有人会期待第一种解释,而且语法不应该允许它。如果你想要一个空的 while 目标,你可以使用 ; 作为重复语句,而不是什么都没有。

我确定您并没有打算让 stmt 什么都不是。允许将空语句写成 ;(即空后跟分号)很有意义,但这显然是一种不同的语法。 (在 {} 中,您可能不想允许任何内容,而不是坚持使用分号。为此,您需要一个空的 stmtlist,而不是一个空的 stmt。 )

2。其他悬挂:实际上是 elseiflist

中的歧义

我认为这是您正在使用的语法:

(37) stmt -> "if" '(' exp ')' stmt elseiflist %prec IFP
(38) stmt -> "if" '(' exp ')' stmt elseiflist "else" stmt
(41) elseiflist -> "elif" '(' exp ')' stmt
(42) elseiflist -> elseiflist "elif" '(' exp ')' stmt
(43) elseiflist ->

正如 stmtlist 产生式一样,elseiflist 是具有两个基本情况的递归产生式,其中一个是冗余的。同样,有必要确定 elseiflist 是否真的可以为空(提示:可以),然后删除一个或另一个基本情况以避免解析不明确。

话虽如此,我认为这不是编写 if 语句语法的最佳方式;它构建的解析树可能并不像您预期​​的那样。但我想它会起作用。