diff --git a/eval.c b/eval.c index 30ad2bb..1519f2c 100644 --- a/eval.c +++ b/eval.c @@ -1,7 +1,7 @@ /* * module : eval.c - * version : 1.20 - * date : 04/11/24 + * version : 1.22 + * date : 04/26/24 */ #include "globals.h" @@ -25,7 +25,7 @@ static void set_alarm(int num) } #endif -static void trace(pEnv env, FILE *fp) +void trace(pEnv env, FILE *fp) { writestack(env, env->stck, fp); if (env->debugging == 2) { @@ -54,7 +54,7 @@ void evaluate(pEnv env, NodeList *list) #if ALARM if (time_out) { time_out = 0; - execerror(env->filename, "more time", "evaluate"); + execerror("more time", "evaluate"); } #endif if (env->debugging) @@ -66,7 +66,7 @@ void evaluate(pEnv env, NodeList *list) if (ent.u.body) prog(env, ent.u.body); else if (env->undeferror) - execerror(env->filename, "definition", ent.name); + execerror("definition", ent.name); continue; case ANON_FUNCT_: (*node.u.proc)(env); diff --git a/globals.h b/globals.h index 448da0d..8b9c485 100644 --- a/globals.h +++ b/globals.h @@ -1,7 +1,7 @@ /* module : globals.h - version : 1.42 - date : 04/11/24 + version : 1.46 + date : 05/02/24 */ #ifndef GLOBALS_H #define GLOBALS_H @@ -127,6 +127,7 @@ typedef enum { typedef enum { ABORT_NONE, ABORT_RETRY, + ABORT_ERROR, ABORT_QUIT } Abort; @@ -188,6 +189,7 @@ KHASH_MAP_INIT_INT64(Funtab, int) * Global variables are stored locally in the main function. */ typedef struct Env { + jmp_buf finclude; /* return point in finclude */ double calls; /* statistics */ double opers; vector(Token) *tokens; /* read ahead table */ @@ -231,6 +233,7 @@ typedef struct Env { unsigned char overwrite; unsigned char printing; unsigned char recurse; + unsigned char finclude_busy; } Env; typedef struct table_t { @@ -246,6 +249,7 @@ void initcompile(pEnv env); void exitcompile(pEnv env); void compileprog(pEnv env, NodeList *list); /* eval.c */ +void trace(pEnv env, FILE *fp); void evaluate(pEnv env, NodeList *list); /* exec.c */ void execute(pEnv env, NodeList *list); @@ -258,8 +262,6 @@ int my_yylex(pEnv env); int get_input(void); /* main.c */ void abortexecution_(int num); -void stats(pEnv env); -void dump(pEnv env); /* modl.c */ void savemod(int *hide, int *modl, int *hcnt); void undomod(int hide, int modl, int hcnt); @@ -299,7 +301,7 @@ void save(pEnv env, NodeList *list, int num, int remove); /* scan.c */ void inilinebuffer(pEnv env); void include(pEnv env, char *str); -int yywrap(void); +int my_yywrap(pEnv env); /* yywrap replacement */ void my_error(char *str, YYLTYPE *bloc); void yyerror(pEnv env, char *str); /* util.c */ @@ -310,7 +312,7 @@ void writefactor(pEnv env, Node node, FILE *fp); void writeterm(pEnv env, NodeList *list, FILE *fp); void writestack(pEnv env, NodeList *list, FILE *fp); /* xerr.c */ -void execerror(char *filename, char *message, char *op); +void execerror(char *message, char *op); /* ylex.c */ int yylex(pEnv env); /* byte.c */ diff --git a/lexr.l b/lexr.l index d302096..0242ca5 100644 --- a/lexr.l +++ b/lexr.l @@ -1,13 +1,17 @@ %{ /* module : lexr.l - version : 1.31 - date : 03/22/24 + version : 1.33 + date : 05/06/24 */ #include "globals.h" #define YY_DECL int my_yylex(pEnv env) +#define YY_NO_INPUT #define YY_NO_UNPUT +#define YY_SKIP_YYWRAP + +#define yywrap() my_yywrap(env) #define OUT_OF_COM 0 #define WITHIN_COM 1 @@ -15,8 +19,8 @@ #define MAX_FILLER 3 /* allow max. three empty lines */ char line[INPLINEMAX + 1]; -static int linenum, linepos; +static int linenum, linepos; static int include_stack_ptr; static YY_BUFFER_STATE include_stack[INPSTACKMAX]; @@ -155,11 +159,3 @@ INLINE[ \t]* return CONST_; . return yytext[0]; %% - -/* - * Supporting getch, reading from the stack of input files, like get. - */ -int get_input(void) -{ - return input(); -} diff --git a/main.c b/main.c index 7ee960d..b11b796 100644 --- a/main.c +++ b/main.c @@ -1,15 +1,18 @@ /* * module : main.c - * version : 1.38 - * date : 04/11/24 + * version : 1.44 + * date : 05/06/24 */ #include "globals.h" extern FILE *yyin; /* lexr.c */ +static jmp_buf begin; /* restart with empty program */ + char *bottom_of_stack; /* used in gc.c */ -static jmp_buf begin; /* restart with empty program */ +static void stats(pEnv env); +static void dump(pEnv env); /* * abort execution and restart reading from yyin. In the NOBDW version the @@ -17,6 +20,7 @@ static jmp_buf begin; /* restart with empty program */ */ void abortexecution_(int num) { + fflush(stdin); longjmp(begin, num); } @@ -24,7 +28,7 @@ void abortexecution_(int num) * options - print help on startup options and exit: options are those that * cannot be set from within the language itself. */ -void options(pEnv env) +static void options(pEnv env) { printf("JOY - compiled at %s on %s", __TIME__, __DATE__); #ifdef VERS @@ -71,7 +75,7 @@ void options(pEnv env) #if 0 printf(" -q : operate in quiet mode\n"); #endif - printf(" -r : recurse w/o using the call stack\n"); + printf(" -r : print without using recursion\n"); printf(" -s : dump symbol table after execution\n"); printf(" -t : print a trace of program execution\n"); printf(" -u : set the undeferror flag (0,1)\n"); @@ -88,7 +92,7 @@ void options(pEnv env) #endif } -void unknown_opt(pEnv env, char *exe, int ch) +static void unknown_opt(pEnv env, char *exe, int ch) { printf("Unknown option argument: \"-%c\"\n", ch); printf("More info with: \"%s -h\"\n", exe); @@ -211,7 +215,7 @@ int my_main(int argc, char **argv) #if 0 case 'v' : verbose = 0; break; #endif - case 'w' : env.overwrite = 0; break; + case 'w' : remove("joy.log"); env.overwrite = 0; break; case 'x' : pstats = 1; break; #if YYDEBUG case 'y' : yydebug = 1; break; @@ -321,8 +325,8 @@ int my_main(int argc, char **argv) * initialize standard input and output. */ #ifdef KEYBOARD - if (raw && strcmp(env.filename, "stdin")) { /* filename required */ - env.autoput = 0; /* disable autoput */ + if (raw && strcmp(env.filename, "stdin")) { /* raw requires filename */ + env.autoput = 0; /* disable autoput and usrlib.joy */ env.autoput_set = 1; /* prevent enabling autoput */ SetRaw(&env); } else /* keep output buffered */ @@ -334,8 +338,10 @@ int my_main(int argc, char **argv) if (mustinclude) include(&env, "usrlib.joy"); /* start reading from library first */ rv = setjmp(begin); /* return here after error or abort */ - if (rv == ABORT_QUIT || (rv && !joy)) - goto einde; + if (rv == ABORT_ERROR && joy) /* in case of a runtime error ... */ + trace(&env, stderr); /* ... dump stack and (all of) code */ + if (rv == ABORT_QUIT || (rv && !joy)) /* in case end of file ... */ + goto einde; /* ... wrap up and exit */ /* * (re)initialize code. */ @@ -376,7 +382,7 @@ int main(int argc, char **argv) /* * print statistics. */ -void stats(pEnv env) +static void stats(pEnv env) { printf("%.0f milliseconds CPU\n", (clock() - env->startclock) * 1000.0 / CLOCKS_PER_SEC); @@ -390,7 +396,7 @@ void stats(pEnv env) /* * dump the symbol table, from last to first. */ -void dump(pEnv env) +static void dump(pEnv env) { int i; Entry ent; diff --git a/modl.c b/modl.c index ac03c7a..f943640 100644 --- a/modl.c +++ b/modl.c @@ -1,7 +1,7 @@ /* module : modl.c - version : 1.7 - date : 03/21/24 + version : 1.8 + date : 04/23/24 */ #include "globals.h" @@ -20,7 +20,7 @@ static int module_index = -1; /* * savemod saves the global variables, to be restored later with undomod. -*/ + */ void savemod(int *hide, int *modl, int *hcnt) { *hide = hide_index; @@ -43,7 +43,7 @@ void initmod(pEnv env, char *name) { if (++module_index >= DISPLAYMAX) { module_index = -1; - execerror(env->filename, "index", "display"); + execerror("index", "display"); } env->module_stack[module_index].name = name; env->module_stack[module_index].hide = hide_index; @@ -62,7 +62,7 @@ void initpriv(pEnv env) { if (++hide_index >= DISPLAYMAX) { hide_index = -1; - execerror(env->filename, "index", "display"); + execerror("index", "display"); } env->hide_stack[hide_index] = ++hide_count; inside_hide = 1; @@ -117,6 +117,9 @@ char *classify(pEnv env, char *name) size_t leng; char temp[MAXNUM], *buf = 0, *str; + /* + * if name already has a prefix, there is no need to add another one. + */ if (strchr(name, '.')) return name; /* diff --git a/parm.c b/parm.c index f39c081..11b29fa 100644 --- a/parm.c +++ b/parm.c @@ -1,7 +1,7 @@ /* module : parm.c - date : 1.16 - version : 04/11/24 + date : 1.20 + version : 05/06/24 */ #include "globals.h" @@ -26,7 +26,7 @@ void checknum(char *name, int num, int leng, char *file) break; } if (ptr) - execerror(name, ptr, file); + execerror(ptr, file); } /* @@ -53,253 +53,254 @@ void parm(pEnv env, int num, Params type, char *file) checknum(env->filename, num, leng, file); first = pvec_lst(env->stck); if (first.op != LIST_) - execerror(env->filename, "quotation as top parameter", file); + execerror("quotation as top parameter", file); break; /* two quotes are needed: */ case WHILE: if (leng < 2) - execerror(env->filename, "two parameters", file); + execerror("two parameters", file); first = pvec_lst(env->stck); second = pvec_nth(env->stck, leng - 2); if (first.op != LIST_) - execerror(env->filename, "quotation as top parameter", file); + execerror("quotation as top parameter", file); if (second.op != LIST_) - execerror(env->filename, "quotation as second parameter", file); + execerror("quotation as second parameter", file); break; /* three quotes are needed: */ case IFTE: if (leng < 3) - execerror(env->filename, "three parameters", file); + execerror("three parameters", file); first = pvec_lst(env->stck); second = pvec_nth(env->stck, leng - 2); third = pvec_nth(env->stck, leng - 3); if (first.op != LIST_) - execerror(env->filename, "quotation as top parameter", file); + execerror("quotation as top parameter", file); if (second.op != LIST_) - execerror(env->filename, "quotation as second parameter", file); + execerror("quotation as second parameter", file); if (third.op != LIST_) - execerror(env->filename, "quotation as third parameter", file); + execerror("quotation as third parameter", file); break; /* four quotes are needed: */ case LINREC: if (leng < 4) - execerror(env->filename, "four parameters", file); + execerror("four parameters", file); first = pvec_lst(env->stck); second = pvec_nth(env->stck, leng - 2); third = pvec_nth(env->stck, leng - 3); fourth = pvec_nth(env->stck, leng - 4); if (first.op != LIST_) - execerror(env->filename, "quotation as top parameter", file); + execerror("quotation as top parameter", file); if (second.op != LIST_) - execerror(env->filename, "quotation as second parameter", file); + execerror("quotation as second parameter", file); if (third.op != LIST_) - execerror(env->filename, "quotation as third parameter", file); + execerror("quotation as third parameter", file); if (fourth.op != LIST_) - execerror(env->filename, "quotation as fourth parameter", file); + execerror("quotation as fourth parameter", file); break; /* list is needed: */ case HELP: if (leng < 1) - execerror(env->filename, "one parameter", file); + execerror("one parameter", file); first = pvec_lst(env->stck); if (first.op != LIST_) - execerror(env->filename, "list", file); + execerror("list", file); break; /* list is needed as second parameter: */ case INFRA: if (leng < 2) - execerror(env->filename, "two parameters", file); + execerror("two parameters", file); first = pvec_lst(env->stck); second = pvec_nth(env->stck, leng - 2); if (first.op != LIST_) - execerror(env->filename, "quotation as top parameter", file); + execerror("quotation as top parameter", file); if (second.op != LIST_) - execerror(env->filename, "list as second parameter", file); + execerror("list as second parameter", file); break; /* float or integer is needed: */ case UFLOAT: if (leng < 1) - execerror(env->filename, "one parameter", file); + execerror("one parameter", file); first = pvec_lst(env->stck); if (first.op != FLOAT_ && first.op != INTEGER_) - execerror(env->filename, "float or integer", file); + execerror("float or integer", file); break; /* two floats or integers are needed: */ case MUL: if (leng < 2) - execerror(env->filename, "two parameters", file); + execerror("two parameters", file); first = pvec_lst(env->stck); second = pvec_nth(env->stck, leng - 2); if (first.op != BIGNUM_ && first.op != FLOAT_ && first.op != INTEGER_) - execerror(env->filename, "float or (big)integer", file); + execerror("float or (big)integer", file); if (second.op != BIGNUM_ && second.op != FLOAT_ && second.op != INTEGER_) - execerror(env->filename, "two floats or (big)integers", file); + execerror("two floats or (big)integers", file); break; /* two floats or integers are needed: */ case BFLOAT: if (leng < 2) - execerror(env->filename, "two parameters", file); + execerror("two parameters", file); first = pvec_lst(env->stck); second = pvec_nth(env->stck, leng - 2); if (first.op != FLOAT_ && first.op != INTEGER_) - execerror(env->filename, "float or integer", file); + execerror("float or integer", file); if (second.op != FLOAT_ && second.op != INTEGER_) - execerror(env->filename, "two floats or integers", file); + execerror("two floats or integers", file); break; /* file is needed: */ case FGET: if (leng < 1) - execerror(env->filename, "one parameter", file); + execerror("one parameter", file); first = pvec_lst(env->stck); if (first.op != FILE_ || !first.u.fil) - execerror(env->filename, "file", file); + execerror("file", file); break; /* file is needed as second parameter: */ case FPUT: if (leng < 2) - execerror(env->filename, "two parameters", file); + execerror("two parameters", file); second = pvec_nth(env->stck, leng - 2); if (second.op != FILE_ || !second.u.fil) - execerror(env->filename, "file", file); + execerror("file", file); break; /* string is needed: */ case STRFTIME: if (leng < 2) - execerror(env->filename, "two parameters", file); + execerror("two parameters", file); first = pvec_lst(env->stck); second = pvec_nth(env->stck, leng - 2); if (first.op != STRING_) - execerror(env->filename, "string", file); + execerror("string", file); if (second.op != LIST_) - execerror(env->filename, "list as second parameter", file); + execerror("list as second parameter", file); break; case FPUTCHARS: if (leng < 2) - execerror(env->filename, "two parameters", file); + execerror("two parameters", file); first = pvec_lst(env->stck); second = pvec_nth(env->stck, leng - 2); if (first.op != STRING_ && first.op != BIGNUM_) - execerror(env->filename, "string", file); + execerror("string", file); if (second.op != FILE_ || !second.u.fil) - execerror(env->filename, "file", file); + execerror("file", file); break; case STRTOD: if (leng < 1) - execerror(env->filename, "one parameter", file); + execerror("one parameter", file); first = pvec_lst(env->stck); if (first.op != STRING_ && first.op != BIGNUM_) - execerror(env->filename, "string", file); + execerror("string", file); break; /* string is needed as second parameter: */ case FOPEN: if (leng < 2) - execerror(env->filename, "two parameters", file); + execerror("two parameters", file); first = pvec_lst(env->stck); second = pvec_nth(env->stck, leng - 2); if (first.op != STRING_) - execerror(env->filename, "string", file); + execerror("string", file); if (second.op != STRING_) - execerror(env->filename, "string as second parameter", file); + execerror("string as second parameter", file); break; /* integer is needed: */ case UNMKTIME: if (leng < 1) - execerror(env->filename, "one parameter", file); + execerror("one parameter", file); first = pvec_lst(env->stck); if (first.op != INTEGER_) - execerror(env->filename, "integer", file); + execerror("integer", file); break; case FREAD: if (leng < 2) - execerror(env->filename, "two parameters", file); + execerror("two parameters", file); first = pvec_lst(env->stck); second = pvec_nth(env->stck, leng - 2); - if (first.op != INTEGER_) - execerror(env->filename, "integer", file); + if (first.op != INTEGER_ && first.op != CHAR_ && first.op != BOOLEAN_) + execerror("numeric", file); if (second.op != FILE_ || !second.u.fil) - execerror(env->filename, "file", file); + execerror("file", file); break; case LDEXP: if (leng < 2) - execerror(env->filename, "two parameters", file); + execerror("two parameters", file); first = pvec_lst(env->stck); second = pvec_nth(env->stck, leng - 2); if (first.op != INTEGER_) - execerror(env->filename, "integer", file); + execerror("integer", file); if (second.op != FLOAT_ && second.op != INTEGER_) - execerror(env->filename, "float or integer as second parameter", - file); + execerror("float or integer as second parameter", file); break; case STRTOL: if (leng < 2) - execerror(env->filename, "two parameters", file); + execerror("two parameters", file); first = pvec_lst(env->stck); second = pvec_nth(env->stck, leng - 2); if (first.op != INTEGER_) - execerror(env->filename, "integer", file); + execerror("integer", file); if (second.op != STRING_ && second.op != BIGNUM_) - execerror(env->filename, "string as second parameter", file); + execerror("string as second parameter", file); break; /* two integers are needed: */ case FSEEK: if (leng < 3) - execerror(env->filename, "three parameters", file); + execerror("three parameters", file); first = pvec_lst(env->stck); second = pvec_nth(env->stck, leng - 2); third = pvec_nth(env->stck, leng - 3); if (first.op != INTEGER_ || second.op != INTEGER_) - execerror(env->filename, "two integers", file); + execerror("two integers", file); if (third.op != FILE_ || !third.u.fil) - execerror(env->filename, "file", file); + execerror("file", file); break; /* integer is needed as second parameter: */ case TIMES: if (leng < 2) - execerror(env->filename, "two parameters", file); + execerror("two parameters", file); first = pvec_lst(env->stck); second = pvec_nth(env->stck, leng - 2); if (first.op != LIST_) - execerror(env->filename, "quotation as top parameter", file); + execerror("quotation as top parameter", file); if (second.op != INTEGER_) - execerror(env->filename, "integer as second parameter", file); + execerror("integer as second parameter", file); + if (second.u.num < 0) + execerror("non-negative integer", file); break; /* numeric type is needed: */ case MAXMIN: if (leng < 2) - execerror(env->filename, "two parameters", file); + execerror("two parameters", file); first = pvec_lst(env->stck); second = pvec_nth(env->stck, leng - 2); if ((first.op == FLOAT_ || first.op == INTEGER_) && @@ -308,27 +309,27 @@ void parm(pEnv env, int num, Params type, char *file) else if (first.op != INTEGER_ && first.op != CHAR_ && first.op != BOOLEAN_ && second.op != INTEGER_ && second.op != CHAR_ && second.op != BOOLEAN_) - execerror(env->filename, "numeric", file); + execerror("numeric", file); else if (first.op != second.op) - execerror(env->filename, "two parameters of the same type", file); + execerror("two parameters of the same type", file); break; /* numeric type is needed: */ case PREDSUCC: if (leng < 1) - execerror(env->filename, "one parameter", file); + execerror("one parameter", file); first = pvec_lst(env->stck); if (first.op != INTEGER_ && first.op != CHAR_ && first.op != BOOLEAN_ && first.op != BIGNUM_) - execerror(env->filename, "numeric", file); + execerror("numeric", file); break; /* numeric type is needed as second parameter: */ case PLUSMINUS: if (leng < 2) - execerror(env->filename, "two parameters", file); + execerror("two parameters", file); first = pvec_lst(env->stck); second = pvec_nth(env->stck, leng - 2); if ((first.op == BIGNUM_ || first.op == FLOAT_ || first.op == INTEGER_) @@ -336,187 +337,187 @@ void parm(pEnv env, int num, Params type, char *file) second.op == INTEGER_)) ; else if (first.op != INTEGER_) - execerror(env->filename, "integer", file); + execerror("integer", file); else if (second.op != INTEGER_ && second.op != CHAR_) - execerror(env->filename, "numeric as second parameter", file); + execerror("numeric as second parameter", file); break; /* aggregate parameter is needed: */ case SIZE_: if (leng < 1) - execerror(env->filename, "one parameter", file); + execerror("one parameter", file); first = pvec_lst(env->stck); if (first.op != LIST_ && first.op != STRING_ && first.op != SET_ && first.op != BIGNUM_) - execerror(env->filename, "aggregate parameter", file); + execerror("aggregate parameter", file); break; /* aggregate parameter is needed as second parameter: */ case STEP: if (leng < 2) - execerror(env->filename, "two parameters", file); + execerror("two parameters", file); first = pvec_lst(env->stck); second = pvec_nth(env->stck, leng - 2); if (first.op != LIST_) - execerror(env->filename, "quotation as top parameter", file); + execerror("quotation as top parameter", file); if (second.op != LIST_ && second.op != STRING_ && second.op != SET_ && second.op != BIGNUM_) - execerror(env->filename, "aggregate parameter", file); + execerror("aggregate parameter", file); break; case TAKE: if (leng < 2) - execerror(env->filename, "two parameters", file); + execerror("two parameters", file); first = pvec_lst(env->stck); second = pvec_nth(env->stck, leng - 2); if (first.op != INTEGER_ || first.u.num < 0) - execerror(env->filename, "non-negative integer", file); + execerror("non-negative integer", file); if (second.op != LIST_ && second.op != STRING_ && second.op != SET_ && second.op != BIGNUM_) - execerror(env->filename, "aggregate parameter", file); + execerror("aggregate parameter", file); break; /* two parameters of the same type are needed: */ case CONCAT: if (leng < 2) - execerror(env->filename, "two parameters", file); + execerror("two parameters", file); first = pvec_lst(env->stck); second = pvec_nth(env->stck, leng - 2); if (first.op != LIST_ && first.op != STRING_ && first.op != SET_ && second.op != BIGNUM_) - execerror(env->filename, "aggregate parameter", file); + execerror("aggregate parameter", file); if (first.op != second.op) - execerror(env->filename, "two parameters of the same type", file); + execerror("two parameters of the same type", file); break; /* specific number of types: */ case ANDORXOR: if (leng < 2) - execerror(env->filename, "two parameters", file); + execerror("two parameters", file); first = pvec_lst(env->stck); second = pvec_nth(env->stck, leng - 2); if (first.op != second.op) - execerror(env->filename, "two parameters of the same type", file); + execerror("two parameters of the same type", file); if (first.op != SET_ && first.op != INTEGER_ && first.op != CHAR_ && first.op != BOOLEAN_) - execerror(env->filename, "different type", file); + execerror("different type", file); break; case NOT: if (leng < 1) - execerror(env->filename, "one parameter", file); + execerror("one parameter", file); first = pvec_lst(env->stck); if (first.op != SET_ && first.op != INTEGER_ && first.op != CHAR_ && first.op != BOOLEAN_) - execerror(env->filename, "different type", file); + execerror("different type", file); break; /* specific number of types: */ case PRIMREC: if (leng < 3) - execerror(env->filename, "three parameters", file); + execerror("three parameters", file); first = pvec_lst(env->stck); second = pvec_nth(env->stck, leng - 2); third = pvec_nth(env->stck, leng - 3); if (first.op != LIST_ || second.op != LIST_) - execerror(env->filename, "two quotations", file); + execerror("two quotations", file); if (third.op != LIST_ && third.op != STRING_ && third.op != SET_ && third.op != INTEGER_) - execerror(env->filename, "different type", file); + execerror("different type", file); break; /* specific number of types: */ case SMALL: if (leng < 1) - execerror(env->filename, "one parameter", file); + execerror("one parameter", file); first = pvec_lst(env->stck); if (first.op != LIST_ && first.op != STRING_ && first.op != SET_ && first.op != INTEGER_ && first.op != BOOLEAN_ && first.op != BIGNUM_) - execerror(env->filename, "different type", file); + execerror("different type", file); break; /* user defined symbol: */ case BODY: if (leng < 1) - execerror(env->filename, "one parameter", file); + execerror("one parameter", file); first = pvec_lst(env->stck); if (first.op != USR_) - execerror(env->filename, "user defined symbol", file); + execerror("user defined symbol", file); break; /* valid symbol name: */ case INTERN: if (leng < 1) - execerror(env->filename, "one parameter", file); + execerror("one parameter", file); first = pvec_lst(env->stck); if (first.op != STRING_) - execerror(env->filename, "string", file); + execerror("string", file); /* a negative number is not a valid name */ if (first.u.str[0] == '-' && isdigit((int)first.u.str[1])) - execerror(env->filename, "valid name", file); + execerror("valid name", file); /* a name that starts with any of these characters is not valid */ if (strchr("\"#'().0123456789;[]{}", first.u.str[0])) - execerror(env->filename, "valid name", file); + execerror("valid name", file); /* a name consists of alphanumeric characters, or one of the dashes */ for (i = strlen(first.u.str) - 1; i > 0; i--) if (!isalnum((int)first.u.str[i]) && !strchr("-=_", first.u.str[i])) - execerror(env->filename, "valid name", file); + execerror("valid name", file); break; /* character: */ case FORMAT: if (leng < 4) - execerror(env->filename, "four parameters", file); + execerror("four parameters", file); first = pvec_lst(env->stck); second = pvec_nth(env->stck, leng - 2); third = pvec_nth(env->stck, leng - 3); fourth = pvec_nth(env->stck, leng - 4); if (first.op != INTEGER_ || second.op != INTEGER_) - execerror(env->filename, "two integers", file); + execerror("two integers", file); if (third.op != CHAR_) - execerror(env->filename, "character", file); + execerror("character", file); if (!strchr("dioxX", third.u.num)) - execerror(env->filename, "one of: d i o x X", file); + execerror("one of: d i o x X", file); if (fourth.op != INTEGER_ && fourth.op != CHAR_ && fourth.op != BOOLEAN_) - execerror(env->filename, "numeric as fourth parameter", file); + execerror("numeric as fourth parameter", file); break; case FORMATF: if (leng < 4) - execerror(env->filename, "four parameters", file); + execerror("four parameters", file); first = pvec_lst(env->stck); second = pvec_nth(env->stck, leng - 2); third = pvec_nth(env->stck, leng - 3); fourth = pvec_nth(env->stck, leng - 4); if (first.op != INTEGER_ || second.op != INTEGER_) - execerror(env->filename, "two integers", file); + execerror("two integers", file); if (third.op != CHAR_) - execerror(env->filename, "character", file); + execerror("character", file); if (!strchr("eEfgG", third.u.num)) - execerror(env->filename, "one of: e E f g G", file); + execerror("one of: e E f g G", file); if (fourth.op != FLOAT_) - execerror(env->filename, "float as fourth parameter", file); + execerror("float as fourth parameter", file); break; /* set member: */ case CONS: if (leng < 2) - execerror(env->filename, "two parameters", file); + execerror("two parameters", file); first = pvec_lst(env->stck); second = pvec_nth(env->stck, leng - 2); switch (first.op) { @@ -525,15 +526,15 @@ void parm(pEnv env, int num, Params type, char *file) case STRING_: case BIGNUM_: if (second.op != CHAR_) - execerror(env->filename, "character", file); + execerror("character", file); break; case SET_: if ((second.op != INTEGER_ && second.op != CHAR_) || second.u.num < 0 || second.u.num >= SETSIZE) - execerror(env->filename, "small numeric", file); + execerror("small numeric", file); break; default: - execerror(env->filename, "aggregate parameter", file); + execerror("aggregate parameter", file); } break; /* @@ -541,7 +542,7 @@ void parm(pEnv env, int num, Params type, char *file) */ case IN_: if (leng < 2) - execerror(env->filename, "two parameters", file); + execerror("two parameters", file); first = pvec_lst(env->stck); second = pvec_nth(env->stck, leng - 2); switch (first.op) { @@ -551,16 +552,16 @@ void parm(pEnv env, int num, Params type, char *file) case BIGNUM_: #if 0 if (second.op != CHAR_) - execerror(env->filename, "character", file); + execerror("character", file); #endif break; case SET_: if ((second.op != INTEGER_ && second.op != CHAR_) || second.u.num < 0 || second.u.num >= SETSIZE) - execerror(env->filename, "small numeric", file); + execerror("small numeric", file); break; default: - execerror(env->filename, "aggregate parameter", file); + execerror("aggregate parameter", file); } break; /* @@ -568,7 +569,7 @@ void parm(pEnv env, int num, Params type, char *file) */ case HAS: if (leng < 2) - execerror(env->filename, "two parameters", file); + execerror("two parameters", file); first = pvec_lst(env->stck); second = pvec_nth(env->stck, leng - 2); switch (second.op) { @@ -578,16 +579,16 @@ void parm(pEnv env, int num, Params type, char *file) case BIGNUM_: #if 0 if (first.op != CHAR_) - execerror(env->filename, "character", file); + execerror("character", file); #endif break; case SET_: if ((first.op != INTEGER_ && first.op != CHAR_) || first.u.num < 0 || first.u.num >= SETSIZE) - execerror(env->filename, "small numeric", file); + execerror("small numeric", file); break; default: - execerror(env->filename, "aggregate parameter", file); + execerror("aggregate parameter", file); } break; /* @@ -595,16 +596,16 @@ void parm(pEnv env, int num, Params type, char *file) */ case CASE: if (leng < 2) - execerror(env->filename, "two parameters", file); + execerror("two parameters", file); first = pvec_lst(env->stck); if (first.op != LIST_) - execerror(env->filename, "list", file); + execerror("list", file); if (!pvec_cnt(first.u.lis)) - execerror(env->filename, "non-empty list", file); + execerror("non-empty list", file); for (i = pvec_cnt(first.u.lis) - 1; i >= 0; i--) { second = pvec_nth(first.u.lis, i); if (second.op != LIST_) - execerror(env->filename, "internal list", file); + execerror("internal list", file); } break; /* @@ -612,24 +613,24 @@ void parm(pEnv env, int num, Params type, char *file) */ case FIRST: if (leng < 1) - execerror(env->filename, "one parameter", file); + execerror("one parameter", file); first = pvec_lst(env->stck); switch (first.op) { case LIST_: if (!pvec_cnt(first.u.lis)) - execerror(env->filename, "non-empty list", file); + execerror("non-empty list", file); break; case STRING_: case BIGNUM_: if (!*first.u.str) - execerror(env->filename, "non-empty string", file); + execerror("non-empty string", file); break; case SET_: if (!first.u.set) - execerror(env->filename, "non-empty set", file); + execerror("non-empty set", file); break; default: - execerror(env->filename, "aggregate parameter", file); + execerror("aggregate parameter", file); } break; /* @@ -637,66 +638,66 @@ void parm(pEnv env, int num, Params type, char *file) */ case OF: if (leng < 2) - execerror(env->filename, "two parameters", file); + execerror("two parameters", file); first = pvec_lst(env->stck); second = pvec_nth(env->stck, leng - 2); if (second.u.num < 0) - execerror(env->filename, "non-negative integer", file); + execerror("non-negative integer", file); switch (first.op) { case LIST_ : if (!pvec_cnt(first.u.lis)) - execerror(env->filename, "non-empty list", file); + execerror("non-empty list", file); if (second.u.num >= pvec_cnt(first.u.lis)) - execerror(env->filename, "smaller index", file); + execerror("smaller index", file); break; case STRING_: case BIGNUM_: if (!*first.u.str) - execerror(env->filename, "non-empty string", file); + execerror("non-empty string", file); if (second.u.num >= (int)strlen(first.u.str)) - execerror(env->filename, "smaller index", file); + execerror("smaller index", file); break; case SET_ : if (!first.u.set) - execerror(env->filename, "non-empty set", file); + execerror("non-empty set", file); for (i = 0, j = second.u.num; i < SETSIZE; i++) if (first.u.set & ((int64_t)1 << i)) { if (!j) return; j--; } - execerror(env->filename, "smaller index", file); + execerror("smaller index", file); break; - default : execerror(env->filename, "aggregate parameter", file); + default : execerror("aggregate parameter", file); } break; case AT: if (leng < 2) - execerror(env->filename, "two parameters", file); + execerror("two parameters", file); first = pvec_lst(env->stck); second = pvec_nth(env->stck, leng - 2); if (first.u.num < 0) - execerror(env->filename, "non-negative integer", file); + execerror("non-negative integer", file); switch (second.op) { case LIST_ : if (!pvec_cnt(second.u.lis)) - execerror(env->filename, "non-empty list", file); + execerror("non-empty list", file); if (first.u.num >= pvec_cnt(second.u.lis)) - execerror(env->filename, "smaller index", file); + execerror("smaller index", file); break; case STRING_: case BIGNUM_: if (!*second.u.str) - execerror(env->filename, "non-empty string", file); + execerror("non-empty string", file); if (first.u.num >= (int)strlen(second.u.str)) - execerror(env->filename, "smaller index", file); + execerror("smaller index", file); break; case SET_ : if (!second.u.set) - execerror(env->filename, "non-empty set", file); + execerror("non-empty set", file); for (i = 0, j = first.u.num; i < SETSIZE; i++) if (second.u.set & ((int64_t)1 << i)) { if (!j) return; j--; } - execerror(env->filename, "smaller index", file); + execerror("smaller index", file); break; - default : execerror(env->filename, "aggregate parameter", file); + default : execerror("aggregate parameter", file); } break; /* @@ -704,72 +705,71 @@ void parm(pEnv env, int num, Params type, char *file) */ case DIV: if (leng < 2) - execerror(env->filename, "two parameters", file); + execerror("two parameters", file); first = pvec_lst(env->stck); second = pvec_nth(env->stck, leng - 2); if (first.op != INTEGER_ || second.op != INTEGER_) - execerror(env->filename, "two integers", file); + execerror("two integers", file); if (!first.u.num) - execerror(env->filename, "non-zero operand", file); + execerror("non-zero operand", file); break; case REM: if (leng < 2) - execerror(env->filename, "two parameters", file); + execerror("two parameters", file); first = pvec_lst(env->stck); second = pvec_nth(env->stck, leng - 2); if (first.op != FLOAT_ && first.op != INTEGER_) - execerror(env->filename, "float or integer", file); + execerror("float or integer", file); if (second.op != FLOAT_ && second.op != INTEGER_) - execerror(env->filename, "two floats or integers", file); + execerror("two floats or integers", file); if ((first.op == FLOAT_ && !first.u.dbl) || !first.u.num) - execerror(env->filename, "non-zero operand", file); + execerror("non-zero operand", file); break; case DIVIDE: if (leng < 2) - execerror(env->filename, "two parameters", file); + execerror("two parameters", file); first = pvec_lst(env->stck); second = pvec_nth(env->stck, leng - 2); if (first.op != BIGNUM_ && first.op != FLOAT_ && first.op != INTEGER_) - execerror(env->filename, "float or integer", file); + execerror("float or integer", file); if (second.op != BIGNUM_ && second.op != FLOAT_ && second.op != INTEGER_) - execerror(env->filename, "two floats or integers", file); + execerror("two floats or integers", file); if ((first.op == BIGNUM_ && first.u.str[1] == '0') || (first.op == FLOAT_ && !first.u.dbl) || !first.u.num) - execerror(env->filename, "non-zero divisor", file); + execerror("non-zero divisor", file); break; /* check numeric list: */ case FWRITE: if (leng < 2) - execerror(env->filename, "two parameters", file); + execerror("two parameters", file); first = pvec_lst(env->stck); second = pvec_nth(env->stck, leng - 2); if (first.op != LIST_) - execerror(env->filename, "list", file); + execerror("list", file); if (second.op != FILE_ || !second.u.fil) - execerror(env->filename, "file", file); + execerror("file", file); for (i = pvec_cnt(first.u.lis) - 1; i >= 0; i--) { second = pvec_nth(first.u.lis, i); if (second.op != INTEGER_) - execerror(env->filename, "numeric list", file); + execerror("numeric list", file); } break; /* * check list at top with user defined symbol. */ case ASSIGN: - if (leng < 2) - execerror(env->filename, "two parameters", file); + checknum(env->filename, num, leng, file); first = pvec_lst(env->stck); if (first.op != LIST_) - execerror(env->filename, "list", file); + execerror("list", file); if (!pvec_cnt(first.u.lis)) - execerror(env->filename, "non-empty list", file); + execerror("non-empty list", file); first = pvec_lst(first.u.lis); if (first.op != USR_) - execerror(env->filename, "user defined symbol", file); + execerror("user defined symbol", file); break; #ifdef USE_MULTI_THREADS_JOY /* @@ -777,20 +777,20 @@ void parm(pEnv env, int num, Params type, char *file) */ case RECEIVE: if (leng < 1) - execerror(env->filename, "one parameter", file); + execerror("one parameter", file); first = pvec_lst(env->stck); if (first.op != INTEGER_) - execerror(env->filename, "channel", file); + execerror("channel", file); break; /* channel as second parameter: */ case SEND: if (leng < 2) - execerror(env->filename, "two parameters", file); + execerror("two parameters", file); second = pvec_nth(env->stck, leng - 2); if (second.op != INTEGER_) - execerror(env->filename, "channel", file); + execerror("channel", file); break; #endif } diff --git a/prim.c b/prim.c index c7f61c6..2db44bb 100644 --- a/prim.c +++ b/prim.c @@ -73,6 +73,7 @@ #include "./src/file.c" #include "./src/filetime.c" #include "./src/filter.c" +#include "./src/finclude.c" #include "./src/first.c" #include "./src/fjump.c" #include "./src/float.c" @@ -98,7 +99,6 @@ #include "./src/genrecaux.c" #include "./src/geql.c" #include "./src/get.c" -#include "./src/getch.c" #include "./src/getenv.c" #include "./src/gmtime.c" #include "./src/greater.c" @@ -232,6 +232,7 @@ #include "./src/unary2.c" #include "./src/unary3.c" #include "./src/unary4.c" +#include "./src/unassign.c" #include "./src/uncons.c" #include "./src/undeferror.c" #include "./src/undefs.c" diff --git a/prim.h b/prim.h index 4471124..5eaba41 100644 --- a/prim.h +++ b/prim.h @@ -73,6 +73,7 @@ void fgets_(pEnv env); void file_(pEnv env); void filetime_(pEnv env); void filter_(pEnv env); +void finclude_(pEnv env); void first_(pEnv env); void fjump_(pEnv env); void float_(pEnv env); @@ -98,7 +99,6 @@ void genrec_(pEnv env); void genrecaux_(pEnv env); void geql_(pEnv env); void get_(pEnv env); -void getch_(pEnv env); void getenv_(pEnv env); void gmtime_(pEnv env); void greater_(pEnv env); @@ -232,6 +232,7 @@ void unary_(pEnv env); void unary2_(pEnv env); void unary3_(pEnv env); void unary4_(pEnv env); +void unassign_(pEnv env); void uncons_(pEnv env); void undeferror_(pEnv env); void undefs_(pEnv env); diff --git a/save.c b/save.c index 0e64c29..bd7c75d 100644 --- a/save.c +++ b/save.c @@ -1,7 +1,7 @@ /* module : save.c - version : 1.12 - date : 03/21/24 + version : 1.13 + date : 05/06/24 */ #include "globals.h" #include "prim.h" @@ -12,6 +12,7 @@ */ void save(pEnv env, NodeList *list, int num, int remove) { + FILE *fp; Node node; int status; @@ -26,9 +27,17 @@ void save(pEnv env, NodeList *list, int num, int remove) if ((status = pvec_getarity(list)) == ARITY_UNKNOWN) { status = arity(env, list, num) == 1 ? ARITY_OK : ARITY_NOT_OK; if (env->overwrite) { - printf("%s: (", status == ARITY_OK ? "info" : "warning"); - writeterm(env, list, stdout); - printf(") has %scorrect arity\n", status == ARITY_OK ? "" : "in"); + /* + * Arities are reported in a log file, because the screen may be + * cleared right after displaying a message. + */ + if ((fp = fopen("joy.log", "a")) != 0) { + fprintf(fp, "%s: (", status == ARITY_OK ? "info" : "warning"); + writeterm(env, list, fp); + fprintf(fp, ") has %scorrect arity\n", status == ARITY_OK ? + "" : "in"); + fclose(fp); + } } } pvec_setarity(list, status); diff --git a/scan.c b/scan.c index ab8d48d..613e6f3 100644 --- a/scan.c +++ b/scan.c @@ -1,7 +1,7 @@ /* module : scan.c - version : 1.18 - date : 03/21/24 + version : 1.20 + date : 05/02/24 */ #include "globals.h" @@ -35,7 +35,7 @@ static void redirect(FILE *fp, char *str) { infile[ilevel].line = yylineno; /* save last line number and line */ if (ilevel + 1 == INPSTACKMAX) /* increase the include level */ - execerror(str, "fewer include files", "include"); + execerror("fewer include files", "include"); infile[++ilevel].fp = yyin = fp; /* update yyin, used by yylex */ infile[ilevel].line = 1; /* start with line 1 */ strncpy(infile[ilevel].name, str, FILENAMEMAX); @@ -120,13 +120,13 @@ void include(pEnv env, char *name) * If that also fails, no other path can be tried and an error is * generated. */ - execerror(name, "valid file name", "include"); + execerror("valid file name", "include"); } /* - * yywrap - continue reading after EOF. + * my_yywrap - continue reading after EOF. */ -int yywrap(void) +int my_yywrap(pEnv env) { if (!ilevel) /* at end of first file, end program */ return 1; /* terminate */ @@ -134,6 +134,8 @@ int yywrap(void) infile[ilevel].fp = 0; /* invalidate file pointer */ yyin = infile[--ilevel].fp; /* proceed with previous file */ old_buffer(infile[ilevel].line); /* and previous input buffer */ + if (env->finclude_busy) + longjmp(env->finclude, 1); /* back to finclude */ return 0; /* continue with old buffer */ } diff --git a/src/finclude.c b/src/finclude.c new file mode 100644 index 0000000..99b15b5 --- /dev/null +++ b/src/finclude.c @@ -0,0 +1,26 @@ +/* + module : finclude.c + version : 1.11 + date : 05/02/24 +*/ +#ifndef FINCLUDE_C +#define FINCLUDE_C + +/** +Q0 OK 3160 finclude : DU S -> F ... +[FOREIGN] Reads Joy source code from stream S and pushes it onto stack. +*/ +void finclude_(pEnv env) +{ + Node node; + + PARM(1, STRTOD); + env->stck = pvec_pop(env->stck, &node); /* remove file name */ + include(env, node.u.str); + env->finclude_busy = 1; /* tell scanner about finclude */ + if (setjmp(env->finclude)) + env->finclude_busy = 0; /* done with finclude */ + else while (1) + get_(env); /* read all factors from file */ +} +#endif diff --git a/src/fput.c b/src/fput.c index 2a2d124..6a8ffed 100644 --- a/src/fput.c +++ b/src/fput.c @@ -1,7 +1,7 @@ /* module : fput.c - version : 1.9 - date : 03/05/24 + version : 1.10 + date : 04/27/24 */ #ifndef FPUT_C #define FPUT_C @@ -23,6 +23,5 @@ void fput_(pEnv env) putc(']', node.u.fil); } else writefactor(env, elem, node.u.fil); - putc(' ', node.u.fil); } #endif diff --git a/src/getch.c b/src/getch.c deleted file mode 100644 index 7211229..0000000 --- a/src/getch.c +++ /dev/null @@ -1,27 +0,0 @@ -/* - module : getch.c - version : 1.13 - date : 03/21/24 -*/ -#ifndef GETCH_C -#define GETCH_C - -/** -Q0 POSTPONE 3160 getch : A -> N -[IMPURE] Reads a character from input and puts it onto stack. -*/ -void getch_(pEnv env) -{ - static unsigned char init; - Node node; - - node.u.num = get_input(); - if (!init) { - if (node.u.num == '\n') - node.u.num = get_input(); /* skip first newline */ - init = 1; - } - node.op = CHAR_; - env->stck = pvec_add(env->stck, node); -} -#endif diff --git a/src/quit.c b/src/quit.c index da81d3e..c66f9d9 100644 --- a/src/quit.c +++ b/src/quit.c @@ -1,7 +1,7 @@ /* module : quit.c - version : 1.12 - date : 03/21/24 + version : 1.13 + date : 04/29/24 */ #ifndef QUIT_C #define QUIT_C @@ -12,6 +12,6 @@ Exit from Joy. */ void quit_(pEnv env) { - exit(EXIT_SUCCESS); + abortexecution_(ABORT_QUIT); } #endif diff --git a/src/unassign.c b/src/unassign.c new file mode 100644 index 0000000..d0d6bb3 --- /dev/null +++ b/src/unassign.c @@ -0,0 +1,28 @@ +/* + module : unassign.c + version : 1.1 + date : 05/06/24 +*/ +#ifndef UNASSIGN_C +#define UNASSIGN_C + +/** +Q0 IGNORE_POP 3235 unassign : D [N] -> +[IMPURE] Sets the body of the name N to uninitialized. +*/ +void unassign_(pEnv env) +{ + Node node; + int index; + Entry ent; + + PARM(1, ASSIGN); /* quotation on top */ + env->stck = pvec_pop(env->stck, &node); /* singleton list */ + node = pvec_lst(node.u.lis); /* first/last element */ + index = node.u.ent; /* index user defined name */ + ent = vec_at(env->symtab, index); /* symbol table entry */ + ent.is_user = 1; /* ensure again user defined */ + ent.u.body = 0; /* (re)initialise body */ + vec_at(env->symtab, index) = ent; /* update symbol table */ +} +#endif diff --git a/tabl.c b/tabl.c index 49b405a..8710561 100644 --- a/tabl.c +++ b/tabl.c @@ -214,7 +214,7 @@ /* 3130 */ { Q0, IGNORE_OK, "quit", quit_, "N", "->", "Exit from Joy.\n" }, /* 3140 */ { Q0, OK, "casting", casting_, "DDA", "X Y -> Z", "[EXT] Z takes the value from X and uses the value from Y as its type.\n" }, /* 3150 */ { Q0, OK, "filetime", filetime_, "DA", "F -> T", "[FOREIGN] T is the modification time of file F.\n" }, -/* 3160 */ { Q0, POSTPONE, "getch", getch_, "A", "-> N", "[IMPURE] Reads a character from input and puts it onto stack.\n" }, +/* 3160 */ { Q0, OK, "finclude", finclude_, "DU", "S -> F ...", "[FOREIGN] Reads Joy source code from stream S and pushes it onto stack.\n" }, /* 3170 */ { Q0, OK, "over", over_, "A", "X Y -> X Y X", "[EXT] Pushes an extra copy of the second item X on top of the stack.\n" }, /* 3180 */ { Q0, OK, "pick", pick_, "DA", "X Y Z 2 -> X Y Z X", "[EXT] Pushes an extra copy of nth (e.g. 2) item X on top of the stack.\n" }, /* 3190 */ { Q0, IGNORE_POP, "assign", assign_, "DD", "V [N] ->", "[IMPURE] Assigns value V to the variable with name N.\n" }, @@ -222,6 +222,7 @@ /* 3210 */ { Q0, OK, "sametype", sametype_, "DDA", "X Y -> B", "[EXT] Tests whether X and Y have the same type.\n" }, /* 3220 */ { Q0, OK, "scale", scale_, "D", "I ->", "[NUM] Sets the number of digits to be used after the decimal point.\n" }, /* 3230 */ { Q0, OK, "typeof", typeof_, "DA", "X -> I", "[EXT] Replace X by its type.\n" }, +/* 3235 */ { Q0, IGNORE_POP, "unassign", unassign_, "D", "[N] ->", "[IMPURE] Sets the body of the name N to uninitialized.\n" }, /* 3240 */ { Q0, OK, "exit", exit_, "N", "->", "[MTH] Exit a thread.\n" }, /* 3250 */ { Q0, OK, "kill", kill_, "N", "->", "[MTH] Make all threads eligible for garbage collection.\n" }, /* 3260 */ { Q0, OK, "recv", recv_, "A", "P -> P N", "[MTH] Receive a node from a channel and push it on the stack.\n" }, diff --git a/test2/CMakeLists.txt b/test2/CMakeLists.txt index 7059b3e..8213703 100644 --- a/test2/CMakeLists.txt +++ b/test2/CMakeLists.txt @@ -1,7 +1,7 @@ # # module : CMakeLists.txt -# version : 1.12 -# date : 04/11/24 +# version : 1.13 +# date : 05/02/24 # macro(exe9 src) add_custom_target(${src}.out ALL @@ -104,7 +104,6 @@ exe9(gc2) exe9(genrec) exe9(geql) exe9(get) -exe9(getch) exe9(getenv) exe9(gmtime) exe9(greater) diff --git a/test2/body.joy b/test2/body.joy index 2729f91..a8523fa 100644 --- a/test2/body.joy +++ b/test2/body.joy @@ -1,8 +1,6 @@ (* module : body.joy - version : 1.4 - date : 03/21/24 + version : 1.5 + date : 04/19/24 *) -DEFINE last == dup rest null [first] [rest last] branch. - -[last] first body [dup rest null [first] [rest last] branch] equal. +[sum] first body [0 [+] fold] equal. diff --git a/test2/equal.joy b/test2/equal.joy index 4502713..4246d1e 100644 --- a/test2/equal.joy +++ b/test2/equal.joy @@ -1,13 +1,11 @@ (* module : equal.joy - version : 1.9 - date : 04/11/24 + version : 1.10 + date : 04/19/24 *) -DEFINE last == dup rest null [first] [rest last] branch. - -[last] first [pop] first equal false =. -[last] first 10 equal false =. -[pop] first [last] first equal false =. +[sum] first [pop] first equal false =. +[sum] first 10 equal false =. +[pop] first [sum] first equal false =. [pop] first [pop] first equal. [pop] first 10 equal false =. 1 true equal. diff --git a/test2/getch.joy b/test2/getch.joy deleted file mode 100644 index f3c70c9..0000000 --- a/test2/getch.joy +++ /dev/null @@ -1,10 +0,0 @@ -(* - module : getch.joy - version : 1.5 - date : 03/21/24 -*) -0 setautoput getch getch getch. -ABC -1 setautoput 'C =. -'B =. -'A =. diff --git a/test2/helpdetail.joy b/test2/helpdetail.joy index c54f845..d29564a 100644 --- a/test2/helpdetail.joy +++ b/test2/helpdetail.joy @@ -1,12 +1,10 @@ (* module : helpdetail.joy - version : 1.5 - date : 03/22/24 + version : 1.6 + date : 04/19/24 *) -DEFINE last == dup rest null [first] [rest last] branch. - "test" "w" fopen -[stdin stdout stderr 3.14 [] "" {} 10 'A true maxint helpdetail last dummy] +[stdin stdout stderr 3.14 [] "" {} 10 'A true maxint helpdetail sum dummy] cons helpdetail. $ cat test $ rm test diff --git a/test2/name.joy b/test2/name.joy index 33922e9..5bdd431 100644 --- a/test2/name.joy +++ b/test2/name.joy @@ -1,12 +1,10 @@ (* module : name.joy - version : 1.4 - date : 03/21/24 + version : 1.5 + date : 04/19/24 *) -DEFINE last == dup rest null [first] [rest last] branch. - [pop] first name "pop" =. -[last] first name "last" =. +[sum] first name "sum" =. true name " truth value type" =. 'A name " character type" =. 10 name " integer type" =. diff --git a/test2/null.joy b/test2/null.joy index 0b52c28..33d4d76 100644 --- a/test2/null.joy +++ b/test2/null.joy @@ -1,12 +1,10 @@ (* module : null.joy - version : 1.4 - date : 03/21/24 + version : 1.5 + date : 04/19/24 *) -DEFINE last == dup rest null [first] [rest last] branch. - [pop] first null false =. -[last] first null false =. +[sum] first null false =. false null. true null false =. '\000 null. diff --git a/test2/put.joy b/test2/put.joy index 1b05276..505d62a 100644 --- a/test2/put.joy +++ b/test2/put.joy @@ -1,12 +1,10 @@ (* module : put.joy - version : 1.5 - date : 04/15/24 + version : 1.6 + date : 04/19/24 *) -DEFINE last == dup rest null [first] [rest last] branch. - [pop] first putln. -[last] first putln. +[sum] first putln. true putln. 'A putln. 10 putln. diff --git a/test2/typeof.joy b/test2/typeof.joy index 2b0a2ba..4dd1c1e 100644 --- a/test2/typeof.joy +++ b/test2/typeof.joy @@ -1,11 +1,9 @@ (* module : typeof.joy - version : 1.3 - date : 03/21/24 + version : 1.4 + date : 04/19/24 *) -DEFINE last == dup rest null [first] [rest last] branch. - -[last] first typeof 2 =. +[sum] first typeof 2 =. [pop] first typeof 3 =. true typeof 4 =. 'A typeof 5 =. diff --git a/test2/user.joy b/test2/user.joy index 4006c98..44aafc5 100644 --- a/test2/user.joy +++ b/test2/user.joy @@ -1,9 +1,7 @@ (* module : user.joy - version : 1.4 - date : 03/21/24 + version : 1.5 + date : 04/19/24 *) -DEFINE last == dup rest null [first] [rest last] branch. - -[last] first user. +[sum] first user. [pop] first user false =. diff --git a/writ.c b/writ.c index 600d4ca..e2a95a9 100644 --- a/writ.c +++ b/writ.c @@ -1,7 +1,7 @@ /* * module : writ.c - * version : 1.22 - * date : 04/11/24 + * version : 1.24 + * date : 04/23/24 */ #include "globals.h" @@ -23,7 +23,7 @@ void writefactor(pEnv env, Node node, FILE *fp) * only serves as a reminder for future customers. */ if (!env->stck) - execerror(env->filename, "non-empty stack", "print"); + execerror("non-empty stack", "print"); #endif switch (node.op) { case USR_PRIME_: @@ -96,9 +96,11 @@ void writefactor(pEnv env, Node node, FILE *fp) case FLOAT_: sprintf(buf, "%g", node.u.dbl); /* exponent character is e */ if ((ptr = strchr(buf, '.')) == 0) { /* locate decimal point */ - if ((ptr = strchr(buf, 'e')) == 0) /* locate start of exponent */ - strcat(buf, ".0"); /* append decimal point + 0 */ - else { + if ((ptr = strchr(buf, 'e')) == 0) {/* locate start of exponent */ + i = buf[strlen(buf) - 1]; + if (isdigit(i)) /* check digit present */ + strcat(buf, ".0"); /* add decimal point and 0 */ + } else { strcpy(tmp, ptr); /* save exponent */ sprintf(ptr, ".0%s", tmp); /* insert decimal point + 0 */ } @@ -202,7 +204,7 @@ void writeterm(pEnv env, NodeList *list, FILE *fp) for (i = j - 1; i >= 0; i--) { writefactor(env, pvec_nth(list, i), fp); if (i) - putchar(' '); + putc(' ', fp); } else { vec_init(array); /* collect nodes in a vector */ @@ -217,13 +219,13 @@ void writeterm(pEnv env, NodeList *list, FILE *fp) */ void writestack(pEnv env, NodeList *list, FILE *fp) { - int i, j; + int i; vector(Node) *array; - if ((j = pvec_cnt(list)) == 0) + if ((i = pvec_cnt(list)) == 0) return; vec_init(array); /* collect nodes in a vector */ - for (i = j - 1; i >= 0; i--) + for (--i; i >= 0; i--) vec_push(array, pvec_nth(list, i)); writing(env, (void *)array, fp); } diff --git a/xerr.c b/xerr.c index da8e4d8..6857762 100644 --- a/xerr.c +++ b/xerr.c @@ -1,14 +1,14 @@ /* * module : xerr.c - * version : 1.2 - * date : 03/21/24 + * version : 1.3 + * date : 04/23/24 */ #include "globals.h" /* print a runtime error to stderr and abort the execution of current program. */ -void execerror(char *filename, char *message, char *op) +void execerror(char *message, char *op) { int leng = 0; char *ptr, *str; @@ -22,7 +22,6 @@ void execerror(char *filename, char *message, char *op) else leng = strlen(ptr); fflush(stdout); - fprintf(stderr, "%s:run time error: %s needed for %.*s\n", filename, - message, leng, ptr); - abortexecution_(ABORT_RETRY); + fprintf(stderr, "run time error: %s needed for %.*s\n", message, leng, ptr); + abortexecution_(ABORT_ERROR); }