Bison 歧义规则创建汇编语法

Bison ambiguous rule creating assembler grammar

你好,我有一个为汇编程序定义的语法。 我无法解决歧义。

歧义由此产生

一些操作码的间接寻址模式是操作码'('address')'

例如下面的代码跳转到 $2AFD

的内容
jmp (AFD)

我允许地址是一个表达式

但是

jsr (22 + ) * 2

是 $448A 的绝对跳转子程序

我有一个规则,允许包含在'(' ')'中的表达式

这是我的操作码规则

opcodes:
    OPCODE                                              { $$ = opcode(,    i, 0);                     }
    | OPCODE '#' expr                                   { $$ = opcode(,    I, 1, );                 }
    | OPCODE expr                                       { $$ = opcode(,    a, 1, );                 }
    | OPCODE expr 'X'                                   { $$ = opcode(,   ax, 1, );                 }
    | OPCODE expr 'Y'                                   { $$ = opcode(,   ay, 1, );                 }
    | OPCODE '(' expr ')'                               { $$ = opcode(,  ind, 1, );                 }
    | OPCODE '(' expr 'X' ')'                           { $$ = opcode(, zpix, 1, );                 }
    | OPCODE '(' expr ')' 'Y'                           { $$ = opcode(, zpiy, 1, );                 }

这是我的表达规则

expr:
    INTEGER                                             { $$ = con();                                 }
    | SYMBOL                                            { $$ = id();                                  }
    | '-' expr %prec UMINUS                             { $$ = opr(UMINUS, 1, );                      }
    | math                                              { $$ = ;                                      }
    | compares                                          { $$ = ;                                      }
    | '(' expr ')'                                      { $$ = ;                                      }
    ;

math: 
    expr OR expr                                        { $$ = opr(OR, 2, , );                      }
    | expr AND expr                                     { $$ = opr(AND, 2, , );                     }
    | expr '|' expr                                     { $$ = opr('|', 2, , );                     }
    | expr '&' expr                                     { $$ = opr('&', 2, , );                     }
    | expr '^' expr                                     { $$ = opr('^', 2, , );                     }
    | '~' expr                                          { $$ = opr('~', 1, );                         }
    | expr '+' expr                                     { $$ = opr('+', 2, , );                     }
    | expr '-' expr                                     { $$ = opr('-', 2, , );                     }
    | expr '*' expr                                     { $$ = opr('*', 2, , );                     }
    | expr '/' expr                                     { $$ = opr('/', 2, , );                     }
    ;

compares: 
    expr '<' expr                                       { $$ = opr('<', 2, , );                     }
    | expr '>' expr                                     { $$ = opr('>', 2, , );                     }
    | expr GE expr                                      { $$ = opr(GE, 2, , );                      }
    | expr LE expr                                      { $$ = opr(LE, 2, , );                      }
    | expr NE expr                                      { $$ = opr(NE, 2, , );                      }
    | expr EQ expr                                      { $$ = opr(EQ, 2, , );                      }
    ;

我的问题是如何最好地解决歧义。

默认规则可以正常工作,但我不希望出现 100 次 sr 冲突和 2 次 rr 冲突。我不想用 %expect 来隐藏问题。 我想像对 UMINUS 一样使用 %prec。 我也在这个项目中使用了flex。

我不知道使用优先声明的好的解决方案。这可能是可能的,但它需要在评论中进行更多的解释,而不是黑客的价值。

这是我的做法。请注意,我已经消除了 mathcompares 之间的区别,因为我看不到该值,并且每次都只是执行无用的单位缩减。但是,如果您的真实代码具有更复杂的操作,实际上根据差异执行某些操作,则一定要恢复它。它与解决冲突无关。

这里的重点是避免 ( expr ) 被解析为表达式,除非它是表达式的一部分。所以顶层expr不能有多余的括号,而子表达式可以用括号括起来。

expr: INTEGER
    | SYMBOL
    | '-' subexpr %prec UMINUS
    | '~' subexpr %prec UMINUS  /* See note 1 below */
    | subexpr '+' subexpr
    | ...                       /* Everything which was in math */
    | subexpr '<' subexpr
    | ...                       /* Everything which was in compares */
    ;
subexpr:
      expr
    | '(' subexpr ')'
    ;

现在,您如何编写操作码规则取决于您要实现的精确 syntax/semantics。我将从这个开始,它没有冲突:

opcodes:
      OPCODE
    | OPCODE '#' subexpr
    | OPCODE expr
    | OPCODE subexpr 'X'
    | OPCODE expr 'Y'
    | OPCODE '(' subexpr ')'
    | OPCODE '(' subexpr 'X' ')'
    | OPCODE '(' subexpr ')' 'Y'

请注意,我为 aay 规则使用了 expr(不能以 ( 开头);这需要将它们分别与 indzpiy 规则区分开来。由于 axzpix 之间没有歧义(在后一种情况下 X 需要放在括号内),因此可以允许 (22 + ) X 被解析为它被写成 (22 + X) 但它很可能应该表示语法错误。

总的来说,我认为这种句法近乎歧义的做法会让人类读者感到困惑,应该避免,但我相信你有自己的理由。


备注:

  1. 通常,所有前缀运算符都具有完全相同的优先级。如果使用优先级声明,我更愿意用相同的优先级标记标记所有前缀运算符。但每个人都有自己的风格。 (所有后缀运算符也具有相同的优先级,通常高于前缀运算符。)