mirror of
https://github.com/lcn2/calc.git
synced 2025-08-19 01:13:27 +03:00
Compare commits
2 Commits
2.11.0t8.2
...
2.11.0t8.4
Author | SHA1 | Date | |
---|---|---|---|
|
8db10967e8 | ||
|
49be672338 |
17
BUGS
17
BUGS
@@ -68,9 +68,20 @@ importantly, fixes (in the form of a context diff patch) to:
|
||||
|
||||
Known bugs:
|
||||
|
||||
None reported. We are sure some bugs exist. When you find them,
|
||||
please let us know! See the above for details on how to report and
|
||||
were to EMail your bug reports and hopefully patches to fix them.
|
||||
* calc -i ignores quit binding or EOF input in some cases. For example:
|
||||
|
||||
echo 'define f(x) { ' > myfile
|
||||
calc -i read myfile
|
||||
"./myfile", line 2: End-of-file in function body
|
||||
Error in commands
|
||||
>
|
||||
|
||||
At this point, calc will re-prompt if you give it an EOF, or
|
||||
type ^D while using lib/altbind or while ^D is bound to quit.
|
||||
|
||||
We are sure some more bugs exist. When you find them, please let
|
||||
us know! See the above for details on how to report and were to
|
||||
EMail your bug reports and hopefully patches to fix them.
|
||||
|
||||
=-=
|
||||
|
||||
|
27
CHANGES
27
CHANGES
@@ -44,6 +44,33 @@ Following is the change from calc version 2.11.0t8 to date:
|
||||
|
||||
Misc source file cleanup for things such as } else { style consistency.
|
||||
|
||||
Fixed the basis for FNV-1 hashes. Piror to this fix, the hash()
|
||||
builtin produced FNV hash values that did not match the FNV-1
|
||||
algorithm as specified in:
|
||||
|
||||
http://reality.sgi.com/chongo/tech/comp/fnv/index.html
|
||||
|
||||
Removed an unused argument in the function getbody() in codegen.c.
|
||||
|
||||
Encountering of EOF in getbody() will cause a scanerror rather then
|
||||
stop activity. This will now result in a scanerror:
|
||||
|
||||
echo 'define f(x) { ' > myfile
|
||||
calc -i read myfile
|
||||
|
||||
A '{' at the start of a command and a later matching '}' surrounding zero
|
||||
or more statements (and possibly newlines) results in a function body to
|
||||
be "evaluated". This permits another command to follow on the same
|
||||
line as the '}' as in:
|
||||
|
||||
{display(5)} read something;
|
||||
and:
|
||||
{static a = 5} define f(x) = a + x;
|
||||
|
||||
String constants can now be concatenated. For exmaple:
|
||||
|
||||
s = "curds" ' and ' "whey";
|
||||
|
||||
|
||||
Following is the change from calc version 2.11.0t7 to 2.11.0t7.5:
|
||||
|
||||
|
@@ -57,7 +57,7 @@ associndex(ASSOC *ap, BOOL create, long dim, VALUE *indices)
|
||||
* so that we can first select the correct hash chain, and
|
||||
* also so we can quickly compare each element for a match.
|
||||
*/
|
||||
hash = (QCKHASH)0;
|
||||
hash = FNV1_32_BASIS;
|
||||
for (i = 0; i < dim; i++)
|
||||
hash = hashvalue(&indices[i], hash);
|
||||
|
||||
|
58
codegen.c
58
codegen.c
@@ -31,7 +31,7 @@ static void getshowstatement(void);
|
||||
static void getfunction(void);
|
||||
static void ungetfunction(void);
|
||||
static void getbody(LABEL *contlabel, LABEL *breaklabel,
|
||||
LABEL *nextcaselabel, LABEL *defaultlabel, BOOL toplevel);
|
||||
LABEL *nextcaselabel, LABEL *defaultlabel);
|
||||
static void getdeclarations(int symtype);
|
||||
static void getsimpledeclaration (int symtype);
|
||||
static int getonevariable (int symtype);
|
||||
@@ -190,22 +190,26 @@ evaluate(BOOL nestflag)
|
||||
|
||||
funcname = (nestflag ? "**" : "*");
|
||||
beginfunc(funcname, nestflag);
|
||||
if (nestflag)
|
||||
(void) tokenmode(TM_DEFAULT);
|
||||
while (loop) {
|
||||
switch (gettoken()) {
|
||||
case T_SEMICOLON:
|
||||
break;
|
||||
if (gettoken() == T_LEFTBRACE) {
|
||||
getbody(NULL_LABEL, NULL_LABEL, NULL_LABEL, NULL_LABEL);
|
||||
} else {
|
||||
if (nestflag)
|
||||
(void) tokenmode(TM_DEFAULT);
|
||||
rescantoken();
|
||||
while (loop) {
|
||||
switch (gettoken()) {
|
||||
case T_SEMICOLON:
|
||||
break;
|
||||
case T_NEWLINE:
|
||||
case T_EOF:
|
||||
loop = 0;
|
||||
break;
|
||||
|
||||
case T_NEWLINE:
|
||||
case T_EOF:
|
||||
loop = 0;
|
||||
break;
|
||||
|
||||
default:
|
||||
rescantoken();
|
||||
getstatement(NULL_LABEL, NULL_LABEL,
|
||||
NULL_LABEL, NULL_LABEL);
|
||||
default:
|
||||
rescantoken();
|
||||
getstatement(NULL_LABEL, NULL_LABEL,
|
||||
NULL_LABEL, NULL_LABEL);
|
||||
}
|
||||
}
|
||||
}
|
||||
addop(OP_UNDEF);
|
||||
@@ -322,13 +326,11 @@ getfunction(void)
|
||||
}
|
||||
switch (gettoken()) {
|
||||
case T_ASSIGN:
|
||||
rescantoken();
|
||||
getsimplebody();
|
||||
break;
|
||||
case T_LEFTBRACE:
|
||||
rescantoken();
|
||||
getbody(NULL_LABEL, NULL_LABEL, NULL_LABEL,
|
||||
NULL_LABEL, TRUE);
|
||||
NULL_LABEL);
|
||||
break;
|
||||
default:
|
||||
scanerror(T_NULL,
|
||||
@@ -347,11 +349,6 @@ getfunction(void)
|
||||
static void
|
||||
getsimplebody(void)
|
||||
{
|
||||
if (gettoken() != T_ASSIGN) {
|
||||
scanerror(T_SEMICOLON,
|
||||
"Missing equals for simple function body");
|
||||
return;
|
||||
}
|
||||
(void) tokenmode(TM_NEWLINES);
|
||||
(void) getexprlist();
|
||||
addop(OP_RETURN);
|
||||
@@ -365,14 +362,10 @@ getsimplebody(void)
|
||||
*/
|
||||
/*ARGSUSED*/
|
||||
static void
|
||||
getbody(LABEL *contlabel, LABEL *breaklabel, LABEL *nextcaselabel, LABEL *defaultlabel, BOOL toplevel)
|
||||
getbody(LABEL *contlabel, LABEL *breaklabel, LABEL *nextcaselabel, LABEL *defaultlabel)
|
||||
{
|
||||
int oldmode;
|
||||
|
||||
if (gettoken() != T_LEFTBRACE) {
|
||||
scanerror(T_SEMICOLON, "Missing left brace for function body");
|
||||
return;
|
||||
}
|
||||
oldmode = tokenmode(TM_DEFAULT);
|
||||
while (TRUE) {
|
||||
switch (gettoken()) {
|
||||
@@ -380,6 +373,10 @@ getbody(LABEL *contlabel, LABEL *breaklabel, LABEL *nextcaselabel, LABEL *defaul
|
||||
(void) tokenmode(oldmode);
|
||||
return;
|
||||
|
||||
case T_EOF:
|
||||
scanerror(T_SEMICOLON, "End-of-file in function body");
|
||||
return;
|
||||
|
||||
default:
|
||||
rescantoken();
|
||||
getstatement(contlabel, breaklabel, nextcaselabel, defaultlabel);
|
||||
@@ -595,8 +592,7 @@ getstatement(LABEL *contlabel, LABEL *breaklabel, LABEL *nextcaselabel, LABEL *d
|
||||
break;
|
||||
|
||||
case T_LEFTBRACE:
|
||||
rescantoken();
|
||||
getbody(contlabel, breaklabel, nextcaselabel, defaultlabel, FALSE);
|
||||
getbody(contlabel, breaklabel, nextcaselabel, defaultlabel);
|
||||
return;
|
||||
|
||||
case T_IF:
|
||||
|
2
func.c
2
func.c
@@ -1527,7 +1527,7 @@ f_hash(int count, VALUE **vals)
|
||||
long lhash;
|
||||
VALUE result;
|
||||
|
||||
hash = (QCKHASH)0;
|
||||
hash = FNV1_32_BASIS;
|
||||
while (count-- > 0)
|
||||
hash = hashvalue(*vals++, hash);
|
||||
lhash = (long) hash;
|
||||
|
15
help/hash
15
help/hash
@@ -12,10 +12,23 @@ TYPES
|
||||
DESCRIPTION
|
||||
Returns a hash value for one or more values of arbitrary types.
|
||||
|
||||
This function implements the Fowler/Noll/Vo hash-1 (FNV-1 hash).
|
||||
The basis of the hash algorithm was taken from an idea sent
|
||||
by Email to the IEEE POSIX P1003.2 mailing list from Phong Vo
|
||||
(kpv@research.att.com) and Glenn Fowler (gsf@research.att.com).
|
||||
Landon Curt Noll (http://reality.sgi.com/chongo) later improved on
|
||||
their algorithm to come up with Fowler/Noll/Vo hash.
|
||||
|
||||
See:
|
||||
|
||||
http://reality.sgi.com/chongo/tech/comp/fnv/index.html
|
||||
|
||||
for more information in this hash.
|
||||
|
||||
EXAMPLE
|
||||
> a = isqrt(2e1000); s = "xyz";
|
||||
> hash(a,s)
|
||||
870000771
|
||||
1916476840
|
||||
|
||||
LIMITS
|
||||
The number of arguments is not to exceed 100.
|
||||
|
@@ -6861,7 +6861,7 @@ print '181: parsed test_ptr()';
|
||||
*/
|
||||
define test_newstring()
|
||||
{
|
||||
local A, B, C, D, S, p;
|
||||
local A, B, C, D, S, p, q;
|
||||
|
||||
print '7700: Beginning test_newstring';
|
||||
|
||||
@@ -6953,7 +6953,14 @@ define test_newstring()
|
||||
print '7762: setbit(A, 16, 0);';
|
||||
vrfy(A == "A\255fdef", '7763: A == "A\255fdef"');
|
||||
|
||||
print '7764: Ending test_newstring';
|
||||
q = "curds" " and " "whey";
|
||||
print '7764: q = "curds" " and " "whey"';
|
||||
vrfy(q == "curds and whey", '7765: q == "curds and whey"');
|
||||
q = "chongo" ' was ' "here";
|
||||
print '7766: q = "chongo" \' was \' "here"';
|
||||
vrfy(q == "chongo was here", '7767: q == "chongo was here"');
|
||||
|
||||
print '7768: Ending test_newstring';
|
||||
}
|
||||
print '182: parsed test_newstring()';
|
||||
|
||||
@@ -7115,6 +7122,8 @@ print '188: parsed test_natnumset()';
|
||||
*/
|
||||
define test_somenew()
|
||||
{
|
||||
local a, s;
|
||||
|
||||
print '8200: Starting test_somenew';
|
||||
|
||||
vrfy(char(-1) == char(255), '8201: char(-1) == char(255)');
|
||||
@@ -7139,7 +7148,11 @@ define test_somenew()
|
||||
vrfy(1/(1/0) == 0, '8215: 1/(1/0) == 0');
|
||||
vrfy(inverse(1/0) == 0, '8216: inverse(1/0) == 0');
|
||||
|
||||
print '8217: Ending test_somenew';
|
||||
a = isqrt(2e1000); s = "xyz";
|
||||
print '8217: a = isqrt(2e1000); s = "xyz";';
|
||||
vrfy(hash(a,s) == 1916476840, '8218: hash(a,s) == 1916476840');
|
||||
|
||||
print '8219: Ending test_somenew';
|
||||
}
|
||||
print '189: parsed test_somenew()';
|
||||
|
||||
@@ -7195,16 +7208,27 @@ print '1700: Beginning read test';
|
||||
value = 0;
|
||||
vrfy(value == 0, '1701: value == 0');
|
||||
read "test1700";
|
||||
vrfy(value == 1, '1702: value == 1');
|
||||
read -once "test1700";
|
||||
print '1702: read "test1700";';
|
||||
vrfy(value == 1, '1703: value == 1');
|
||||
read -once "test1700";
|
||||
print '1704: read -once "test1700";';
|
||||
vrfy(value == 1, '1705: value == 1');
|
||||
read "test1700.cal";
|
||||
vrfy(value == 2, '1704: value == 2');
|
||||
print '1706: read "test1700.cal";';
|
||||
vrfy(value == 2, '1707: value == 2');
|
||||
read -once "test1700.cal";
|
||||
vrfy(value == 2, '1705: value == 2');
|
||||
print '1708: read -once "test1700.cal";';
|
||||
vrfy(value == 2, '1709: value == 2');
|
||||
read "test1700.cal";
|
||||
vrfy(value == 3, '1706: value == 3');
|
||||
print '1707: Ending read test';
|
||||
print '1710: read "test1700.cal";';
|
||||
vrfy(value == 3, '1711: value == 3');
|
||||
{++value;} read "test1700.cal";
|
||||
print '1712: {++value;} read "test1700.cal";';
|
||||
vrfy(value == 5, '1713: value == 5');
|
||||
{++value;} read -once "test1700.cal";
|
||||
print '1714: {++value;} read -once "test1700.cal";';
|
||||
vrfy(value == 6, '1715: value == 6');
|
||||
print '1716: Ending read test';
|
||||
|
||||
print;
|
||||
return test_obj();
|
||||
@@ -7279,6 +7303,9 @@ print;
|
||||
return test_size();
|
||||
print;
|
||||
|
||||
/*
|
||||
* 5800 assignment tests
|
||||
*/
|
||||
return test_assign(5800, 1);
|
||||
define xy5800_assign(a,b) { };
|
||||
print '5812: define xy5800_assign(a,b) { }';
|
||||
@@ -7323,7 +7350,7 @@ X5800 = obj xy5800 = {1,2};
|
||||
print '5864: X5800 = obj xy5800 = {1,2}';
|
||||
vrfy(X5800 == (obj xy5800 = {1,2}),
|
||||
'5865: X5800 == (obj xy5800 = {1,2})');
|
||||
print '5899: End of 5800 sequence';
|
||||
print '5866: End of 5800 sequence';
|
||||
|
||||
print;
|
||||
return test_is();
|
||||
@@ -7407,7 +7434,10 @@ print '8304: define h8300(x)=x^3;define i8300(x)=x-1;define j8300(x)=x+1;';
|
||||
vrfy(h8300(10) == 1000, '8305: h8300(10) == 1000');
|
||||
vrfy(i8300(10) == 9, '8306: i8300(10) == 9');
|
||||
vrfy(j8300(10) == 11, '8307: j8300(10) == 11');
|
||||
print '8308: Ending define tests';
|
||||
{static k8300 = 5} define l8300(x) = k8300 + x;
|
||||
print '8308: {static k8300 = 5} define l8300(x) = k8300 + x;';
|
||||
vrfy(l8300(10) == 15, '8309: l8300(10) == 15');
|
||||
print '8310: Ending define tests';
|
||||
|
||||
|
||||
/*
|
||||
|
64
seed.c
64
seed.c
@@ -86,6 +86,50 @@ typedef struct s_hash64 hash64;
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* FNV-1 basis
|
||||
*
|
||||
* We start the hash at a non-zero value at the beginning so that
|
||||
* hashing blocks of data with all 0 bits do not map onto the same
|
||||
* 0 hash value. The virgin value that we use below is the hash value
|
||||
* that we would get from following 32 ASCII characters:
|
||||
*
|
||||
* chongo <Landon Curt Noll> /\../\
|
||||
*
|
||||
* Note that the \'s above are not back-slashing escape characters.
|
||||
* They are literal ASCII backslash 0x5c characters.
|
||||
*
|
||||
* The effect of this virgin initial value is the same as starting
|
||||
* with 0 and pre-pending those 32 characters onto the data being
|
||||
* hashed.
|
||||
*
|
||||
* Yes, even with this non-zero virgin value there is a set of data
|
||||
* that will result in a zero hash value. Worse, appending any
|
||||
* about of zero bytes will continue to produce a zero hash value.
|
||||
* But that would happen with any initial value so long as the
|
||||
* hash of the initial was the `inverse' of the virgin prefix string.
|
||||
*
|
||||
* But then again for any hash function, there exists sets of data
|
||||
* which that the hash of every member is the same value. That is
|
||||
* life with many to few mapping functions. All we do here is to
|
||||
* prevent sets whose members consist of 0 or more bytes of 0's from
|
||||
* being such an awkward set.
|
||||
*
|
||||
* And yes, someone can figure out what the magic 'inverse' of the
|
||||
* 32 ASCII character are ... but this hash function is NOT intended
|
||||
* to be a cryptographic hash function, just a fast and reasonably
|
||||
* good hash function.
|
||||
*/
|
||||
#if defined(HAVE_B64)
|
||||
# define FNV1_64_BASIS ((hash64)(0xcbf29ce484222325ULL))
|
||||
#else
|
||||
# define FNV1_64_BASIS_0 ((USB32)0x2325)
|
||||
# define FNV1_64_BASIS_1 ((USB32)0x8422)
|
||||
# define FNV1_64_BASIS_2 ((USB32)0x9ce4)
|
||||
# define FNV1_64_BASIS_3 ((USB32)0xcbf2)
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* hash_buf - perform a 64 bit Fowler/Noll/Vo hash on a buffer
|
||||
*
|
||||
@@ -116,24 +160,16 @@ hash_buf(char *buf, unsigned len)
|
||||
* (gsf@research.att.com).
|
||||
*
|
||||
* See:
|
||||
* http://reality.sgi.com/chongo/src/fnv/fnv_hash.tar.gz
|
||||
* http://reality.sgi.com/chongo/src/fnv/h32.c
|
||||
* http://reality.sgi.com/chongo/src/fnv/h64.c
|
||||
* http://reality.sgi.com/chongo/tech/comp/fnv/index.html
|
||||
*
|
||||
* for information on 32bit and 64bit Fowler/Noll/Vo hashes.
|
||||
*
|
||||
* Landon Curt Noll (http://reality.sgi.com/chongo) later improved
|
||||
* on their algorithm to come up with Fowler/Noll/Vo hash.
|
||||
*
|
||||
* The 32 hash was able to process 234936 words from the web2 dictionary
|
||||
* without any 32 bit collisions using a constant of
|
||||
* 16777619 = 0x1000193.
|
||||
*
|
||||
* The 64 bit hash uses 1099511628211 = 0x100000001b3 instead.
|
||||
*/
|
||||
#if defined(HAVE_B64)
|
||||
/* hash each octet of the buffer */
|
||||
for (hval = (hash64)0ULL; buf < buf_end; ++buf) {
|
||||
for (hval = FNV1_64_BASIS; buf < buf_end; ++buf) {
|
||||
|
||||
/* multiply by 1099511628211ULL mod 2^64 using 64 bit longs */
|
||||
hval *= (hash64)1099511628211ULL;
|
||||
@@ -145,7 +181,11 @@ hash_buf(char *buf, unsigned len)
|
||||
#else /* HAVE_B64 */
|
||||
|
||||
/* hash each octet of the buffer */
|
||||
for (val[0]=val[1]=val[2]=val[3]=0; buf < buf_end; ++buf) {
|
||||
val[0] = FNV1_64_BASIS_0;
|
||||
val[1] = FNV1_64_BASIS_1;
|
||||
val[2] = FNV1_64_BASIS_2;
|
||||
val[3] = FNV1_64_BASIS_3;
|
||||
for (; buf < buf_end; ++buf) {
|
||||
|
||||
/*
|
||||
* multiply by 1099511628211 mod 2^64 using 32 bit longs
|
||||
@@ -167,7 +207,7 @@ hash_buf(char *buf, unsigned len)
|
||||
val[0] = tmp[0] & 0xffff;
|
||||
tmp[2] += (tmp[1] >> 16);
|
||||
val[1] = tmp[1] & 0xffff;
|
||||
val[3] += (tmp[2] >> 16);
|
||||
val[3] = tmp[3] + (tmp[2] >> 16);
|
||||
val[2] = tmp[2] & 0xffff;
|
||||
/*
|
||||
* Doing a val[3] &= 0xffff; is not really needed since it simply
|
||||
|
12
token.c
12
token.c
@@ -438,6 +438,18 @@ eatstring(int quotechar)
|
||||
case '"':
|
||||
case '\'':
|
||||
if (ch == quotechar) {
|
||||
for (;;) {
|
||||
ch = nextchar();
|
||||
if (ch != ' ' && ch != '\t' &&
|
||||
(ch != '\n' ||
|
||||
newlines))
|
||||
break;
|
||||
}
|
||||
if (ch == '"' || ch == '\'') {
|
||||
quotechar = ch;
|
||||
continue;
|
||||
}
|
||||
reread();
|
||||
done = TRUE;
|
||||
ch = '\0';
|
||||
}
|
||||
|
@@ -12,7 +12,7 @@
|
||||
#define MAJOR_VER 2 /* major version */
|
||||
#define MINOR_VER 11 /* minor version */
|
||||
#define MAJOR_PATCH 0 /* patch level or 0 if no patch */
|
||||
#define MINOR_PATCH "8.2" /* test number or empty string if no patch */
|
||||
#define MINOR_PATCH "8.4" /* test number or empty string if no patch */
|
||||
|
||||
/*
|
||||
* calc version constants
|
||||
|
37
zmath.h
37
zmath.h
@@ -144,6 +144,43 @@ typedef SB32 LEN; /* unit of length storage */
|
||||
#endif /* LONG_BITS == 64 */
|
||||
|
||||
|
||||
/*
|
||||
* FNV-1 basis
|
||||
*
|
||||
* We start the hash at a non-zero value at the beginning so that
|
||||
* hashing blocks of data with all 0 bits do not map onto the same
|
||||
* 0 hash value. The virgin value that we use below is the hash value
|
||||
* that we would get from following 32 ASCII characters:
|
||||
*
|
||||
* chongo <Landon Curt Noll> /\../\
|
||||
*
|
||||
* Note that the \'s above are not back-slashing escape characters.
|
||||
* They are literal ASCII backslash 0x5c characters.
|
||||
*
|
||||
* The effect of this virgin initial value is the same as starting
|
||||
* with 0 and pre-pending those 32 characters onto the data being
|
||||
* hashed.
|
||||
*
|
||||
* Yes, even with this non-zero virgin value there is a set of data
|
||||
* that will result in a zero hash value. Worse, appending any
|
||||
* about of zero bytes will continue to produce a zero hash value.
|
||||
* But that would happen with any initial value so long as the
|
||||
* hash of the initial was the `inverse' of the virgin prefix string.
|
||||
*
|
||||
* But then again for any hash function, there exists sets of data
|
||||
* which that the hash of every member is the same value. That is
|
||||
* life with many to few mapping functions. All we do here is to
|
||||
* prevent sets whose members consist of 0 or more bytes of 0's from
|
||||
* being such an awkward set.
|
||||
*
|
||||
* And yes, someone can figure out what the magic 'inverse' of the
|
||||
* 32 ASCII character are ... but this hash function is NOT intended
|
||||
* to be a cryptographic hash function, just a fast and reasonably
|
||||
* good hash function.
|
||||
*/
|
||||
#define FNV1_32_BASIS ((QCKHASH)(0x811c9dc5))
|
||||
|
||||
|
||||
/*
|
||||
* The largest power of 10 we will compute for our decimal conversion
|
||||
* internal constants is: 10^(2^TEN_MAX).
|
||||
|
Reference in New Issue
Block a user