diff --git a/doc/MOYimplJOY.md b/doc/MOYimplJOY.md index 0b496347..50223d54 100644 --- a/doc/MOYimplJOY.md +++ b/doc/MOYimplJOY.md @@ -54,27 +54,6 @@ _MSC_VER Special instructions on behalf of the Microsoft C compiler are guarded by these defines. -REMEMBER_FILENAME ------------------ - -In error reporting, the filename is not mentioned. The line where an error -occurred is shown, followed by a line that contains a `^`, followed by an -error message. That is presumably enough. But in case of many more files -in the future, it might become necessary to mention the filename where the -error occurred. That is when this define will be needed. This define can now -be used, because file and line are reported when this define is enabled. - -SIGNAL_HANDLING ---------------- - -If `gc.c` is used instead of the BDW garbage collector, this define offers the -possibility to catch a segment violation and print a user-selected error -message. The use of this feature is not recommended, because it prevents during -debugging to pinpoint the exact location where the error occurred. Also `gc.c` -is not recommended, as it is slower than the BDW garbage collector and the -extra dependency is overcome by building from source by the Microsoft compiler -or installing the BDW package in other environments. - JVERSION -------- @@ -84,49 +63,6 @@ happens to be always 1.0 and whether it is a Release build or not can be seen by executing `ccmake .`. That program reads the latest CMakeCache.txt and reports about the options available therein. -BDW_GARBAGE_COLLECTOR ---------------------- - -The BDW garbage collector creates an extra dependency, but if it can be -installed system wide, it is easy enough to link against it. It is faster than -`gc.c`. The interface is kept the same, except that initialization was -different. The `gc.c` needs to know what the top of the stack is, that is why -it receives the address of argc through a global variable. - -CORRECT_INTERN_LOOKUP ---------------------- - -This is a check that was originally not present in Joy. The check makes sure -that a name that is interned constitutes a valid identifier. If not, printing -the name may look very odd. In a colored version of Joy that could be remedied -by giving symbols their own color, but as it is, it may be better to prevent -illegal names. - -SEARCH_EXEC_DIRECTORY ---------------------- - -This is an extension that allows sloppy locations of `usrlib.joy` and other -libraries. The aim is to make library files available without copying them to -a host of other directories. The original only looks in the current working -directory. That may prevent out-of-source builds in CMake. - -USE_SNPRINTF ------------- - -Snprintf calculates the size of the buffer that is needed by printf. It makes -the use of printf safer. The downside is that snprintf is not available in the -ANSI standard. Even so, it might be beneficial to use this define when snprintf -is available. - -WIN32 ------ - -Static analyzers point to various flaws in the source code, such as the use of -`gmtime` and `localtime`, that should be replaced by `_r` functions. Ok, but -the new functions are not available on the Windows platform. That is why this -define is there. Maybe it should be replaced by a USE_R_FUNCTIONS define. -This define is no longer needed. - SOURCE_DATE_EPOCH ----------------- @@ -147,12 +83,6 @@ YYDEBUG When activated, this define allows the user to see the parse tree, as maintained by bison. A `-y` command flag is also required. -COSMO ------ - -Compiling against the cosmopolitan library seems attractive, but the -combination of cosmopolitan and the BDW garbage collector may be difficult. - ALARM ----- @@ -193,15 +123,15 @@ remaining option, -h, cannot be disabled. Implementation details ====================== -About the implementation: the aim is to not disturb the language. That means -that all tests in the test2 directory and all examples in the lib directory -should behave exactly as in the reference implementation of Joy. +About the implementation: the aim is to leave the language untouched. That +means that all tests in the test2 directory and all examples in the lib +directory should behave exactly as in the reference implementation of Joy. What is different in this implementation is the use of vectors instead of -linked lists and the absence of recursion. There are exceptions: `get` and +linked lists and the stackless recursion. There are exceptions: `get` and `fget` use readfactor that may call readterm, that calls readfactor. -The big advantage of not using recursion is in the size of data structures that +The big advantage of stackless recursion is in the size of data structures that can be handled. A program that builds a list of integers looks like this: echo '1 100000 from-to-list.' | build/joy.exe @@ -212,12 +142,18 @@ collector that causes the stack overflow. `Joy` has Cheney's algorithm implemented, that is not recursive but still fails because `from-to-list` makes use of `linrec` and `linrec` recurses. -This implementation does not use recursion and so succeeds where other -implementations fail. There is also a downside: function calling is slower. +This implementation is stackless and so succeeds where other implementations +fail. There is also a downside: function calling is slower. + +Benchmark +--------- -Summary -======= +Implementation|fib (time)|lst (size) +---|---|--- +42minjoy|1m12| +joy0|38|13395 +Joy|1m25|43052 +joy1|3m37|72883 +Moy|2m3|10000000 -Linked lists are not good engineering. Recursion is not good engineering. -Dynamic memory is not good engineering. Ok, this implementation uses dynamic -memory. Lots of it. +Moy is after all not the slowest implementation. diff --git a/lib/numlib.joy b/lib/numlib.joy index bdd35a90..9977ddc9 100644 --- a/lib/numlib.joy +++ b/lib/numlib.joy @@ -10,14 +10,11 @@ LIBRA even == 2 rem null; odd == even not; prime == - [dup 2 =] - [pop true] - [2 - [over over dup * > ord 2 pick 2 pick rem and] - [succ] + 2 + [ over over dup * > ord 2 pick 2 pick rem and ] + [ succ ] while -# dup * < ; - rem null not] ifte; + dup * < ; (* functions *) diff --git a/main.c b/main.c index 29e25727..69cad719 100644 --- a/main.c +++ b/main.c @@ -1,7 +1,7 @@ /* * module : main.c - * version : 1.14 - * date : 09/11/23 + * version : 1.16 + * date : 09/14/23 */ #include "globals.h" @@ -135,7 +135,7 @@ PRIVATE void options(void) printf(" -v : do not print a copyright notice\n"); #endif #ifdef OVERWRITE - printf(" -w : suppress warnings about overwriting builtin\n"); + printf(" -w : suppress warnings: overwriting, arities\n"); #endif #if YYDEBUG printf(" -y : print a trace of parser execution\n"); @@ -259,8 +259,7 @@ PRIVATE int my_main(int argc, char **argv) env.undeferror = INIUNDEFERROR; inilinebuffer(env.filename); inisymboltable(&env); - if (setjmp(begin) == SIGSEGV) /* return here after error or abort */ - quit_(&env); /* do not continue after SIGSEGV */ + setjmp(begin); /* return here after error or abort */ lst_resize(env.prog, 0); if (mustinclude) { mustinclude = include(&env, "usrlib.joy", ERROR_ON_USRLIB); @@ -273,7 +272,6 @@ int main(int argc, char **argv) { int (*volatile m)(int, char **) = my_main; - signal(SIGSEGV, abortexecution_); GC_INIT(); return (*m)(argc, argv); } diff --git a/save.c b/save.c index 262aeb74..0327c96e 100644 --- a/save.c +++ b/save.c @@ -1,7 +1,7 @@ /* module : save.c - version : 1.5 - date : 09/07/23 + version : 1.6 + date : 09/14/23 */ #include "globals.h" #include "prim.h" @@ -21,9 +21,11 @@ PUBLIC void save(pEnv env, NodeList *list, int num) status = arity(env, list, num) == 1 ? ARITY_OK : ARITY_KNOWN; if (status == ARITY_KNOWN) { #ifdef ARITY - printf("arity: "); - writeterm(env, list, stdout); - printf("\n"); + if (env->overwrite) { + printf("arity: "); + writeterm(env, list, stdout); + printf("\n"); + } #endif status = ARITY_NOT_OK; } diff --git a/src/minus.c b/src/minus.c index a9c2b5e2..2136510a 100644 --- a/src/minus.c +++ b/src/minus.c @@ -1,7 +1,7 @@ /* module : minus.c - version : 1.4 - date : 09/11/23 + version : 1.5 + date : 09/14/23 */ #ifndef MINUS_C #define MINUS_C @@ -15,11 +15,34 @@ void minus_(pEnv env) { #ifndef COMPILER Node first, second; +#ifdef USE_BIGNUM_ARITHMETIC + int sign1, sign2; + int64_t num, num1, num2; +#endif PARM(2, PLUSMINUS); second = lst_pop(env->stck); first = lst_pop(env->stck); switch (first.op) { +#ifdef USE_BIGNUM_ARITHMETIC + case BIGNUM_: + switch (second.op) { + case BIGNUM_: + first.u.str = num_str_sub(first.u.str, second.u.str); + break; + + case FLOAT_: + second.u.str = dbl2big(second.u.dbl); + first.u.str = num_str_sub(first.u.str, second.u.str); + break; + + default: + second.u.str = num2big(second.u.num); + first.u.str = num_str_sub(first.u.str, second.u.str); + break; + } + break; +#endif case FLOAT_: switch (second.op) { case FLOAT_: @@ -34,13 +57,37 @@ void minus_(pEnv env) default: switch (second.op) { +#ifdef USE_BIGNUM_ARITHMETIC + case BIGNUM_: + first.u.str = dbl2big(first.u.dbl); + first.u.str = num_str_sub(first.u.str, second.u.str); + first.op = BIGNUM_; + break; +#endif case FLOAT_: second.u.dbl = first.u.num - second.u.dbl; lst_push(env->stck, second); return; default: - first.u.num -= second.u.num; +#ifdef USE_BIGNUM_ARITHMETIC + num1 = first.u.num; + num2 = second.u.num; + sign1 = num1 < 0; + sign2 = num2 < 0; + if (!sign1 && sign2) { /* overflow possible */ + num2 = -num2; + num = num1 + num2; /* unsigned addition, possible wrap around */ + if (num < num1 || num < num2) { /* test overflow */ + first.u.str = num2big(num1); + second.u.str = num2big(num2); + first.u.str = num_str_add(first.u.str, second.u.str); + first.op = BIGNUM_; + } else + first.u.num += num2; + } else +#endif + first.u.num -= second.u.num; break; } break; diff --git a/src/plus.c b/src/plus.c index c3a34418..023b4aff 100644 --- a/src/plus.c +++ b/src/plus.c @@ -1,7 +1,7 @@ /* module : plus.c - version : 1.6 - date : 09/11/23 + version : 1.7 + date : 09/14/23 */ #ifndef PLUS_C #define PLUS_C @@ -88,7 +88,7 @@ void plus_(pEnv env) num1 = -num1; num2 = -num2; } - num = num1 + num2; + num = num1 + num2; /* unsigned addition, possible wrap around */ if (num < num1 || num < num2) { /* test overflow */ first.u.str = num2big(num1); second.u.str = num2big(num2); diff --git a/undo.c b/undo.c index 4e2edcfc..0ac3a951 100644 --- a/undo.c +++ b/undo.c @@ -1,7 +1,7 @@ /* module : undo.c - version : 1.5 - date : 09/07/23 + version : 1.6 + date : 09/14/23 */ #include "globals.h" #include "prim.h" @@ -21,9 +21,11 @@ PUBLIC void undo(pEnv env, NodeList *list, int num) status = arity(env, list, num) == 1 ? ARITY_OK : ARITY_KNOWN; if (status == ARITY_KNOWN) { #ifdef ARITY - printf("arity: "); - writeterm(env, list, stdout); - printf("\n"); + if (env->overwrite) { + printf("arity: "); + writeterm(env, list, stdout); + printf("\n"); + } #endif status = ARITY_NOT_OK; }