ack/lang/cem/cpp.ansi/ch3bin.c
George Koehler 59b3c10563 Use (arith) 1 << ... when getting the sign bit.
This prevents an overflow reported by @hexcoder- in
https://github.com/davidgiven/ack/issues/56

lang/cem/cpp.ansi/LLlex.c used a plain 1 << ... and caused an overflow
on machines where sizeof(int) < sizeof(long).  Using 1L << ... would
work for now but might fail later if arith became long long.

C doesn't specify whether negative integers use 2's complement or some
other format.  Therefore, (arith) 1 << ... has an undefined value.  It
should still work because the value is some integer where the sign bit
is set and all other bits are clear.

(unsigned arith) 1 << ... would also get the sign bit, but casting it
from unsigned back to signed would make the same undefined value.

(arith) -1 << ... would assume 2's complement.
2017-10-29 17:45:10 -04:00

106 lines
1.8 KiB
C

/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
/* $Id$ */
/* EVALUATION OF BINARY OPERATORS */
#include "Lpars.h"
#include "arith.h"
ch3bin(pval, pis_uns, oper, val, is_uns)
register arith *pval, val;
int oper, is_uns, *pis_uns;
{
if (is_uns) *pis_uns = 1;
switch (oper) {
case '/':
if (val == 0) {
error("/ by 0");
break;
}
if (*pis_uns) {
*pval /= (unsigned arith) val;
}
else {
*pval = *pval / val;
}
break;
case '%':
if (val == 0) {
error("%% by 0");
break;
}
if (*pis_uns) {
*pval %= (unsigned arith) val;
}
else {
*pval = *pval % val;
}
break;
case '*':
*pval = *pval * val;
break;
case '+':
*pval = *pval + val;
break;
case '-':
*pval = *pval - val;
break;
case LEFT:
*pval = *pval << val;
break;
case RIGHT:
if (val == 0) break;
if (*pis_uns) {
*pval = (*pval >> 1) & ~arith_sign;
*pval = *pval >> (val - 1);
}
else *pval = *pval >> val;
break;
case '<':
{ arith tmp = *pval; *pval = val; val = tmp; }
/* fall through */
case '>':
if (*pis_uns) {
*pval = (unsigned arith) *pval > (unsigned arith) val;
}
else *pval = (*pval > val);
break;
case LESSEQ:
{ arith tmp = *pval; *pval = val; val = tmp; }
/* fall through */
case GREATEREQ:
if (*pis_uns) {
*pval = (unsigned arith) *pval >= (unsigned arith) val;
}
else *pval = (*pval >= val);
break;
case EQUAL:
*pval = (*pval == val);
break;
case NOTEQUAL:
*pval = (*pval != val);
break;
case '&':
*pval = *pval & val;
break;
case '^':
*pval = *pval ^ val;
break;
case '|':
*pval = *pval | val;
break;
case AND:
*pval = (*pval && val);
break;
case OR:
*pval = (*pval || val);
break;
case ',':
*pis_uns = is_uns;
*pval = val;
break;
}
}