0

我正在用模算术实现一个简单的计算器(环Z_p,所以我知道{0, 1, 2, ..., p - 1}哪里p是素数)。如果输入是-x我想p-x在输出上打印正确的值。我的语法:

exp: num { std::cout << $1 << " "; $$ = $1; }
     | '-' exp %prec NEG { $$ = negate($2); os << "~ "; } // for expressions

num:
        MINUS NUMBER %prec NEG { $$ = negate($2); }
        | NUMBER { $$ = $1; }

以前我有NUMBER现在num在哪里exp。然后打印的东西x而不是p-x. 我没有看到任何其他方法可以做到这一点 - 我怎么知道在下一步我是否会有终端?所以我想出了这个。然而,它给了我关于减少/减少冲突的警告(好吧,我明白为什么),但它给出了正确的结果。

我的问题是:我怎样才能做得更好?我可以摆脱警告但仍然拥有我想要的东西吗?

编辑: 假设p= 7。然后,如果我写-(8+5),我希望输出(反向波兰符号)1 5 +8mod7=1. 这可以通过中的第二条规则来处理exp。但是,如果我写-5,那么我想显示2它是正确的值。这不能仅通过规则来完成,exp因为我在那里打印了确切的数字:

exp:
    NUMBER { std::cout << $1 << " "; $$ = $1; } /* value of rule is $1 */
    | exp PLUS exp { $$ = add($1, $3); std::cout << "+ "; }
    | MINUS exp %prec NEG { $$ = negate($2); }
    ;

这些规则不能按我想要的方式工作,所以我想出了上面介绍的解决方法。

4

1 回答 1

1

我猜你想要做的是这样的:

  1. 接受作为输入算术表达式,使用有符号整数操作数和代数运算符的通常范围,包括一元否定。

  2. 通过要求一元否定的参数不是整数文字来避免歧义。

  3. 对于给定的素数p ,计算环Z p中的每个表达式。

  4. 此外,对于每个表达式,在反向抛光中打印出等效项,所有整数操作数都归一化模p

这是使这个问题与通常的计算器不同的最后一个要求。通常,建议是放弃尝试区分一元否定运算符的不同用途,因为它是不必要的。

但是如果你真的想区分这两种用途,你可以这样做。您只需要编写更明确的规则。这意味着放弃否定运算符的运算符优先级,因为该规则需要明确定义可能的操作数是什么。

首先,我们有两种写数字常量的方法,这两种方法都需要打印出常量(标准化)值。

num : NUMBER        { $$ = ring.normal($1); std::cout << $$ << ' '; }
negnum
    : '-' NUMBER    { $$ = ring.negate(ring.normal($2)); std::cout << $$ << ' '; }

为什么我把它写成两个不同的非终端?因为下一步是确定哪些句法结构可以是一元否定运算符的操作数。num不能,因为-3必须解析为 anegnum并打印为4. 但是 anegnum可以(大概)是一元否定的操作数;--3应该打印为4 ~(假设p == 7)。所以他们必须分开。其他可以作为一元否定操作数的东西是括号表达式和应用一元否定的结果。(另外,也许还有变量,如果有这样的事情。问题中并不清楚,所以我把它们排除在外):

neg : negnum
    | '('  expr ')' { $$ = $2; }
    | '-' neg       { $$ = ring.negate($2); std::cout << "~ "; }

完成后,我们现在可以编写表达式的语法了。对于这部分,我们可以以正常的方式使用优先级(尽管级联语法也很简单):

%left '+' '-' ;
%left '*' '/' ;

expr: num
    | neg
    | expr '+' expr { $$ = ring.add($1, $3); std::cout << "+ "; }
    | expr '-' expr { $$ = ring.sub($1, $3); std::cout << "- "; }
    | expr '*' expr { $$ = ring.mul($1, $3); std::cout << "* "; }
    | expr '/' expr { $$ = ring.div($1, $3); std::cout << "/ "; }

测试(使用打印每个表达式的评估结果的顶级产品):

$ ./ringcalc 7
> 3
3 = 3
> 3+4
3 4 + = 0
> 3-4
3 4 - = 6
> 3+4*5
3 4 5 * + = 2
> 3*4+5
3 4 * 5 + = 3
> -3
4 = 4
> --3
4 ~ = 3
> -(8+5)
1 5 + ~ = 1
于 2021-11-15T05:32:12.260 回答