0

我正在尝试编写一个小型解析器。不幸的是,我遇到了“减少班次冲突”。语法不是我的强项,我只需要完成这件小事。这是产生错误的简化语法:

stmts_opt -> stmts
;

stmts -> stmt 
| stmts stmt
| stmsts
;

stmt -> id 
| ITERATE content_stmt 
| IF test then content_stmt ELSE content_stmt
| IF test then content_stmt
;

content_stmt: BEGIN stmt_opt END
| stmt
;

提供修改后的语法的解决方案将受到高度赞赏。

编辑:

我修改了适合@rici 答案的语法,但问题仍然存在。这是我的实际语法制作:

prog:   BEGIN_PROG def_sprogram BEGIN_EXEC  stmts_opt END_EXEC END_PROG
            { () }
;

def_sprogram:   /* empty */     { () }
| define_new def_sprogram       { () }
;


define_new:         DEFINE_NEW_INSTRUCTION ID AS content_stmt SEMI   { }
;

stmts_opt:  /* empty */     { () }
|           stmts           { () }
;

stmts:      stmt            { () }
|           stmts SEMI stmt { () }
|           stmts SEMI      { () }
;

content_stmt:  BEGIN stmts_opt END { () }
|       stmt    { () }
;

stmt:       open_stmt { () }
|           closed_stmt { () }
;

open_stmt:  ITERATE INT TIMES open_stmt { () }  
|           WHILE test DO open_stmt { () }
|           IF test THEN closed_stmt ELSE open_stmt { () }
|           IF test THEN stmt { () }
;

closed_stmt:  simple_stmt   { () }  
|           ITERATE INT TIMES closed_stmt   { () }  
|           WHILE test DO closed_stmt { () }
|           IF test THEN closed_stmt ELSE closed_stmt { () }
;

这是我正在测试的示例:

BEGINNING-OF-PROGRAM
  BEGINNING-OF-EXECUTION

    IF not-next-to-a-beeper THEN
      move;

    IF not-facing-north THEN

        turnleft;


    ELSE <--- ERROR
        turnleft;

    IF not-facing-east THEN
      IF not-facing-west THEN
        turnleft;

    turnoff
  END-OF-EXECUTION
END-OF-PROGRAM

我在第一个中遇到错误ELSE。我还尝试按照@rici 的建议声明一个简单的优先级:

%nonassoc THEN
%nonassoc ELSE

但这也没有解决错误。

4

1 回答 1

1

“悬空的 else” 移位减少冲突的最简单解决方案是强制解决以支持移位ELSE令牌。由于 camlyacc 确实支持优先声明(根据我能够找到的相当粗略的文档),这应该像在声明部分(在第一个之前%%)中添加以下内容一样简单:

%nonassoc THEN
%nonassoc ELSE

(关联性无关紧要,因为语法中没有任何地方THEN可以ELSE关联。)

如果您想使用显式的“匹配/不匹配”(或“打开/关闭”语句),只需注意这BEGIN stmts_opt END是“匹配”(或“关闭”语句),因为它不能接受THEN. 其他匹配的语句是

matched_stmt: BEGIN stmts_opt END
            | ITERATE matched_stmt
            | IF test THEN matched_stmt ELSE matched_stmt
            | /* Any other kind of simple statement */

不匹配的语句是

unmatched_stmt: ITERATE unmatched_stmt
              | IF test THEN matched_stmt
              | IF test THEN unmatched_stmt
              | IF test THEN matched_stmt ELSE unmatched_stmt

matched_stmt许多人更喜欢创建一个包含和的非终端unmatched_stmt。但是,在您的情况下,您似乎不想嵌套BEGIN...END块,将它们限制为复合语句的内容。因此,除了右侧之外,您stmt将是上述所有内容。BEGIN stmts_opt END

于 2017-11-05T02:24:30.120 回答