yacc中的并列乘法

问题描述

我正在尝试实现一种允许通过并置进行乘法的语法。 这是用于解析 CAS 的多项式输入。

据我所知,它工作得很好,除了少数边缘情况。 我发现有两个问题:

  1. 与其他规则冲突,例如,a^2 b 被(错误地)解析为 (^ a (* 2 b)),而不是 (* (^ a 2) b)
  2. yacc(bison) 报告 28 shift/reduce conflicts8 reduce/reduce conflicts

我很确定正确解决一个问题也会解决第二个问题,但到目前为止我还没有成功。

以下是我正在使用的语法要点:

%start  prgm
%union {
    double  num;
    char    *var;
    ASTNode *node;
}
%token  <num>   NUM
%token  <var>   VAR
%type   <node>  expr

%left   '+' '-'
%left   '*' '/'
%right  '^'
%%
prgm:     // nothing
    | prgm '\n'
    | prgm expr '\n'
    ;
expr:     NUM
    | VAR
    | expr '+' expr
    | expr '-' expr
    | expr '*' expr
    | expr '/' expr
    | expr '^' expr
    | expr expr %prec '*'
    | '-' expr
    | '(' expr ')'
    ;
%%

删除并列规则 (expr expr %prec '*') 解决了 shift/reduce 和 reduce/reduce 警告。

请注意,我语法中的 ab 应表示 (* a b)。 多字符变量前面应该有引号(');这在 lex 文件中已经处理得很好。 词法分析器完全忽略空格 ( ) 和制表符 (\t)。

我知道 this question,但此处并列的使用似乎并不表示乘法。

任何意见或帮助将不胜感激!


附言如果有帮助,this is the link to the entire project.

解决方法

如您链接的问题的答案所示,很难指定并列的运算符优先级,因为没有要移位的运算符。 (在您的代码中,您可以指定产生式 duplicated_numbers = ... list_of_duplicates = [] for item in list_of_items: if item[0] in duplicated_numbers: list_of_duplicates.append(item) 的优先级。但是这种减少将与什么前瞻标记进行比较?将 FIRST(expr) 中的每个标记添加到您的优先级声明中不是很可扩展,并且可能导致不需要的优先解决方案。

优先级解决方案的另一个问题是一元减运算符的行为(链接问题中未解决的问题),因为如所写,您的语法允许将 expr: expr expr 解析为减法或a - ba 的并列乘法。 (并注意 -b 在 FIRST(expr) 中,导致我上面提到的可能不需要的分辨率之一。)

因此,如链接问题中所建议的,最佳解决方案是使用具有显式优先级的语法,例如以下内容:(此处,我使用 - 作为非终结符的名称,而不是juxt):

expr_sequence

这个语法可能不是你想要的:

  • 对一元减号的处理相当简单,但有几个问题。我认为将 %start prgm %token NUM %token VAR %left '+' '-' %left '*' '/' %right '^' %% prgm: // nothing | prgm '\n' | prgm expr '\n' expr: juxt | '-' juxt | expr '+' expr | expr '-' expr | expr '*' expr | expr '/' expr | expr '^' expr juxt: atom | juxt atom atom: NUM | VAR | '(' expr ')' 解析为 -xy 而不是 -(xy) 没有问题,但这并不理想。此外,它不允许 (-x)y (也可能不是问题但不理想)。最后,它不会将 --x 解析为 -x^y,而是将其解析为 -(x^y),这与常见做法相反。
  • 此外,它错误地将并列绑定得太紧。您可能会也可能不会认为 (-x)^y 解析为 a/xy 是一个问题,但您可能会反对将 a/(xy) 解析为 2x^7

避免这些问题的最简单方法是使用一种语法,其中运算符优先级通过明确的语法规则统一实现。

这是一个实现标准优先规则的示例(幂运算优先于一元减法;并列乘法与显式乘法具有相同的优先级)。值得花几分钟仔细查看哪个非终结符出现在哪个产生式中,并考虑它与所需的优先级规则有何关联。

(2x)^7