1
- /* uLisp ESP Release 4.4 - www.ulisp.com
2
- David Johnson-Davies - www.technoblogy.com - 21st March 2023
1
+ /* uLisp ESP Release 4.4b - www.ulisp.com
2
+ David Johnson-Davies - www.technoblogy.com - 31st March 2023
3
3
4
4
Licensed under the MIT license: https://opensource.org/licenses/MIT
5
5
*/
@@ -498,10 +498,15 @@ bool eqsymbols (object *obj, char *buffer) {
498
498
object *arg = cdr (obj);
499
499
int i = 0 ;
500
500
while (!(arg == NULL && buffer[i] == 0 )) {
501
- if (arg == NULL || buffer[i] == 0 ||
502
- arg->chars != (buffer[i]<<24 | buffer[i+1 ]<<16 | buffer[i+2 ]<<8 | buffer[i+3 ])) return false ;
501
+ if (arg == NULL || buffer[i] == 0 ) return false ;
502
+ int test = 0 , shift = 24 ;
503
+ for (int j=0 ; j<4 ; j++, i++) {
504
+ if (buffer[i] == 0 ) break ;
505
+ test = test | buffer[i]<<shift;
506
+ shift = shift - 8 ;
507
+ }
508
+ if (arg->chars != test) return false ;
503
509
arg = car (arg);
504
- i = i + 4 ;
505
510
}
506
511
return true ;
507
512
}
@@ -1003,7 +1008,7 @@ int8_t toradix40 (char ch) {
1003
1008
fromradix40 - returns the character encoded by the number n.
1004
1009
*/
1005
1010
char fromradix40 (char n) {
1006
- if (n >= 1 && n <= 9 ) return ' 0' +n-1 ;
1011
+ if (n >= 1 && n <= 10 ) return ' 0' +n-1 ;
1007
1012
if (n >= 11 && n <= 36 ) return ' a' +n-11 ;
1008
1013
if (n == 37 ) return ' -' ; if (n == 38 ) return ' *' ; if (n == 39 ) return ' $' ;
1009
1014
return 0 ;
@@ -1013,17 +1018,24 @@ char fromradix40 (char n) {
1013
1018
pack40 - packs six radix40-encoded characters from buffer into a 32-bit number and returns it.
1014
1019
*/
1015
1020
uint32_t pack40 (char *buffer) {
1016
- int x = 0 ;
1017
- for (int i=0 ; i<6 ; i++) x = x * 40 + toradix40 (buffer[i]);
1021
+ int x = 0 , j = 0 ;
1022
+ for (int i=0 ; i<6 ; i++) {
1023
+ x = x * 40 + toradix40 (buffer[j]);
1024
+ if (buffer[j] != 0 ) j++;
1025
+ }
1018
1026
return x;
1019
1027
}
1020
1028
1021
1029
/*
1022
1030
valid40 - returns true if the symbol in buffer can be encoded as six radix40-encoded characters.
1023
1031
*/
1024
1032
bool valid40 (char *buffer) {
1025
- if (toradix40 (buffer[0 ]) < 11 ) return false ;
1026
- for (int i=1 ; i<6 ; i++) if (toradix40 (buffer[i]) < 0 ) return false ;
1033
+ int t = 11 ;
1034
+ for (int i=0 ; i<6 ; i++) {
1035
+ if (toradix40 (buffer[i]) < t) return false ;
1036
+ if (buffer[i] == 0 ) break ;
1037
+ t = 0 ;
1038
+ }
1027
1039
return true ;
1028
1040
}
1029
1041
@@ -1058,8 +1070,8 @@ int checkbitvalue (object *obj) {
1058
1070
/*
1059
1071
checkintfloat - check that obj is an integer or floating-point number and return the number
1060
1072
*/
1061
- float checkintfloat (object *obj){
1062
- if (integerp (obj)) return obj->integer ;
1073
+ float checkintfloat (object *obj) {
1074
+ if (integerp (obj)) return ( float ) obj->integer ;
1063
1075
if (!floatp (obj)) error (notanumber, obj);
1064
1076
return obj->single_float ;
1065
1077
}
@@ -1146,6 +1158,20 @@ int listlength (object *list) {
1146
1158
return length;
1147
1159
}
1148
1160
1161
+ /*
1162
+ checkarguments - checks the arguments list in a special form such as with-xxx,
1163
+ dolist, or dotimes.
1164
+ */
1165
+ object *checkarguments (object *args, int min, int max) {
1166
+ if (args == NULL ) error2 (noargument);
1167
+ args = first (args);
1168
+ if (!listp (args)) error (notalist, args);
1169
+ int length = listlength (args);
1170
+ if (length < min) error (toofewargs, args);
1171
+ if (length > max) error (toomanyargs, args);
1172
+ return args;
1173
+ }
1174
+
1149
1175
// Mathematical helper functions
1150
1176
1151
1177
/*
@@ -2599,8 +2625,7 @@ object *sp_setf (object *args, object *env) {
2599
2625
It then returns result, or nil if result is omitted.
2600
2626
*/
2601
2627
object *sp_dolist (object *args, object *env) {
2602
- if (args == NULL || listlength (first (args)) < 2 ) error2 (noargument);
2603
- object *params = first (args);
2628
+ object *params = checkarguments (args, 2 , 3 );
2604
2629
object *var = first (params);
2605
2630
object *list = eval (second (params), env);
2606
2631
push (list, GCStack); // Don't GC the list
@@ -2635,8 +2660,7 @@ object *sp_dolist (object *args, object *env) {
2635
2660
It then returns result, or nil if result is omitted.
2636
2661
*/
2637
2662
object *sp_dotimes (object *args, object *env) {
2638
- if (args == NULL || listlength (first (args)) < 2 ) error2 (noargument);
2639
- object *params = first (args);
2663
+ object *params = checkarguments (args, 2 , 3 );
2640
2664
object *var = first (params);
2641
2665
int count = checkinteger (eval (second (params), env));
2642
2666
int index = 0 ;
@@ -2714,8 +2738,7 @@ object *sp_untrace (object *args, object *env) {
2714
2738
Returns the total number of milliseconds taken.
2715
2739
*/
2716
2740
object *sp_formillis (object *args, object *env) {
2717
- if (args == NULL ) error2 (noargument);
2718
- object *param = first (args);
2741
+ object *param = checkarguments (args, 0 , 1 );
2719
2742
unsigned long start = millis ();
2720
2743
unsigned long now, total = 0 ;
2721
2744
if (param != NULL ) total = checkinteger (eval (first (param), env));
@@ -2756,9 +2779,7 @@ object *sp_time (object *args, object *env) {
2756
2779
Returns a string containing the output to the stream variable str.
2757
2780
*/
2758
2781
object *sp_withoutputtostring (object *args, object *env) {
2759
- if (args == NULL ) error2 (noargument);
2760
- object *params = first (args);
2761
- if (params == NULL ) error2 (nostream);
2782
+ object *params = checkarguments (args, 1 , 1 );
2762
2783
object *var = first (params);
2763
2784
object *pair = cons (var, stream (STRINGSTREAM, 0 ));
2764
2785
push (pair,env);
@@ -2776,8 +2797,7 @@ object *sp_withoutputtostring (object *args, object *env) {
2776
2797
The optional baud gives the baud rate divided by 100, default 96.
2777
2798
*/
2778
2799
object *sp_withserial (object *args, object *env) {
2779
- object *params = first (args);
2780
- if (params == NULL ) error2 (nostream);
2800
+ object *params = checkarguments (args, 2 , 3 );
2781
2801
object *var = first (params);
2782
2802
int address = checkinteger (eval (second (params), env));
2783
2803
params = cddr (params);
@@ -2799,8 +2819,7 @@ object *sp_withserial (object *args, object *env) {
2799
2819
to be read from the stream. The port if specified is ignored.
2800
2820
*/
2801
2821
object *sp_withi2c (object *args, object *env) {
2802
- object *params = first (args);
2803
- if (params == NULL ) error2 (nostream);
2822
+ object *params = checkarguments (args, 2 , 4 );
2804
2823
object *var = first (params);
2805
2824
int address = checkinteger (eval (second (params), env));
2806
2825
params = cddr (params);
@@ -2828,8 +2847,7 @@ object *sp_withi2c (object *args, object *env) {
2828
2847
bitorder 0 for LSBFIRST and 1 for MSBFIRST (default 1), and SPI mode (default 0).
2829
2848
*/
2830
2849
object *sp_withspi (object *args, object *env) {
2831
- object *params = first (args);
2832
- if (params == NULL ) error2 (nostream);
2850
+ object *params = checkarguments (args, 2 , 6 );
2833
2851
object *var = first (params);
2834
2852
params = cdr (params);
2835
2853
if (params == NULL ) error2 (nostream);
@@ -2870,8 +2888,7 @@ object *sp_withspi (object *args, object *env) {
2870
2888
*/
2871
2889
object *sp_withsdcard (object *args, object *env) {
2872
2890
#if defined(sdcardsupport)
2873
- object *params = first (args);
2874
- if (params == NULL ) error2 (nostream);
2891
+ object *params = checkarguments (args, 2 , 3 );
2875
2892
object *var = first (params);
2876
2893
params = cdr (params);
2877
2894
if (params == NULL ) error2 (PSTR (" no filename specified" ));
@@ -4033,7 +4050,7 @@ object *fn_sqrt (object *args, object *env) {
4033
4050
}
4034
4051
4035
4052
/*
4036
- (number [base])
4053
+ (log number [base])
4037
4054
Returns the logarithm of number to the specified base. If base is omitted it defaults to e.
4038
4055
*/
4039
4056
object *fn_log (object *args, object *env) {
@@ -4090,8 +4107,8 @@ object *fn_floor (object *args, object *env) {
4090
4107
}
4091
4108
4092
4109
/*
4093
- (truncate number)
4094
- Returns t if the argument is a floating-point number .
4110
+ (truncate number [divisor] )
4111
+ Returns the integer part of number/divisor. If divisor is omitted it defaults to 1 .
4095
4112
*/
4096
4113
object *fn_truncate (object *args, object *env) {
4097
4114
(void ) env;
@@ -4102,8 +4119,8 @@ object *fn_truncate (object *args, object *env) {
4102
4119
}
4103
4120
4104
4121
/*
4105
- (round number)
4106
- Returns t if the argument is a floating-point number .
4122
+ (round number [divisor] )
4123
+ Returns the integer closest to number/divisor. If divisor is omitted it defaults to 1 .
4107
4124
*/
4108
4125
object *fn_round (object *args, object *env) {
4109
4126
(void ) env;
@@ -4417,10 +4434,8 @@ object *fn_logxor (object *args, object *env) {
4417
4434
}
4418
4435
4419
4436
/*
4420
- (prin1-to-string item [stream])
4421
- Prints its argument to a string, and returns the string.
4422
- Characters and strings are printed with quotation marks and escape characters,
4423
- in a format that will be suitable for read-from-string.
4437
+ (lognot value)
4438
+ Returns the bitwise logical NOT of the value.
4424
4439
*/
4425
4440
object *fn_lognot (object *args, object *env) {
4426
4441
(void ) env;
@@ -5226,7 +5241,7 @@ object *sp_error (object *args, object *env) {
5226
5241
Evaluates the forms with str bound to a wifi-stream.
5227
5242
*/
5228
5243
object *sp_withclient (object *args, object *env) {
5229
- object *params = first (args);
5244
+ object *params = checkarguments (args, 1 , 3 );
5230
5245
object *var = first (params);
5231
5246
char buffer[BUFFERSIZE];
5232
5247
params = cdr (params);
@@ -5345,7 +5360,7 @@ object *fn_wificonnect (object *args, object *env) {
5345
5360
*/
5346
5361
object *sp_withgfx (object *args, object *env) {
5347
5362
#if defined(gfxsupport)
5348
- object *params = first (args);
5363
+ object *params = checkarguments (args, 1 , 1 );
5349
5364
object *var = first (params);
5350
5365
object *pair = cons (var, stream (GFXSTREAM, 1 ));
5351
5366
push (pair,env);
@@ -6204,7 +6219,7 @@ const char doc131[] PROGMEM = "(exp number)\n"
6204
6219
" Returns exp(number)." ;
6205
6220
const char doc132[] PROGMEM = " (sqrt number)\n "
6206
6221
" Returns sqrt(number)." ;
6207
- const char doc133[] PROGMEM = " (number [base])\n "
6222
+ const char doc133[] PROGMEM = " (log number [base])\n "
6208
6223
" Returns the logarithm of number to the specified base. If base is omitted it defaults to e." ;
6209
6224
const char doc134[] PROGMEM = " (expt number power)\n "
6210
6225
" Returns number raised to the specified power.\n "
@@ -6214,10 +6229,10 @@ const char doc135[] PROGMEM = "(ceiling number [divisor])\n"
6214
6229
" Returns ceil(number/divisor). If omitted, divisor is 1." ;
6215
6230
const char doc136[] PROGMEM = " (floor number [divisor])\n "
6216
6231
" Returns floor(number/divisor). If omitted, divisor is 1." ;
6217
- const char doc137[] PROGMEM = " (truncate number)\n "
6218
- " Returns t if the argument is a floating-point number ." ;
6219
- const char doc138[] PROGMEM = " (round number)\n "
6220
- " Returns t if the argument is a floating-point number ." ;
6232
+ const char doc137[] PROGMEM = " (truncate number [divisor] )\n "
6233
+ " Returns the integer part of number/divisor. If divisor is omitted it defaults to 1 ." ;
6234
+ const char doc138[] PROGMEM = " (round number [divisor] )\n "
6235
+ " Returns the integer closest to number/divisor. If divisor is omitted it defaults to 1 ." ;
6221
6236
const char doc139[] PROGMEM = " (char string n)\n "
6222
6237
" Returns the nth character in a string, counting from zero." ;
6223
6238
const char doc140[] PROGMEM = " (char-code character)\n "
@@ -6258,10 +6273,8 @@ const char doc155[] PROGMEM = "(logior [value*])\n"
6258
6273
" Returns the bitwise | of the values." ;
6259
6274
const char doc156[] PROGMEM = " (logxor [value*])\n "
6260
6275
" Returns the bitwise ^ of the values." ;
6261
- const char doc157[] PROGMEM = " (prin1-to-string item [stream])\n "
6262
- " Prints its argument to a string, and returns the string.\n "
6263
- " Characters and strings are printed with quotation marks and escape characters,\n "
6264
- " in a format that will be suitable for read-from-string." ;
6276
+ const char doc157[] PROGMEM = " (lognot value)\n "
6277
+ " Returns the bitwise logical NOT of the value." ;
6265
6278
const char doc158[] PROGMEM = " (ash value shift)\n "
6266
6279
" Returns the result of bitwise shifting value by shift bits. If shift is positive, value is shifted to the left." ;
6267
6280
const char doc159[] PROGMEM = " (logbitp bit value)\n "
@@ -6811,6 +6824,7 @@ object *eval (object *form, object *env) {
6811
6824
pair = value (name, GlobalEnv);
6812
6825
if (pair != NULL ) return cdr (pair);
6813
6826
else if (builtinp (name)) return form;
6827
+ Context = NIL;
6814
6828
error (PSTR (" undefined" ), form);
6815
6829
}
6816
6830
@@ -7443,7 +7457,6 @@ object *nextitem (gfun_t gfun) {
7443
7457
if (ch == ' .' ) valid = 0 ; else if (digitvalue (ch)<base) valid = 1 ; else valid = -1 ;
7444
7458
bool isexponent = false ;
7445
7459
int exponent = 0 , esign = 1 ;
7446
- buffer[2 ] = ' \0 ' ; buffer[3 ] = ' \0 ' ; buffer[4 ] = ' \0 ' ; buffer[5 ] = ' \0 ' ; // In case symbol is < 5 letters
7447
7460
float divisor = 10.0 ;
7448
7461
7449
7462
while (!issp (ch) && !isbr (ch) && index < bufmax) {
@@ -7494,8 +7507,7 @@ object *nextitem (gfun_t gfun) {
7494
7507
builtin_t x = lookupbuiltin (buffer);
7495
7508
if (x == NIL) return nil;
7496
7509
if (x != ENDFUNCTIONS) return bsymbol (x);
7497
- else if ((index <= 6 ) && valid40 (buffer)) return intern (twist (pack40 (buffer)));
7498
- buffer[index +1 ] = ' \0 ' ; buffer[index +2 ] = ' \0 ' ; buffer[index +3 ] = ' \0 ' ; // For internlong
7510
+ if (index <= 6 && valid40 (buffer)) return intern (twist (pack40 (buffer)));
7499
7511
return internlong (buffer);
7500
7512
}
7501
7513
@@ -7568,9 +7580,7 @@ void initgfx () {
7568
7580
#endif
7569
7581
}
7570
7582
7571
- /*
7572
- setup - entry point from the Arduino IDE
7573
- */
7583
+ // Entry point from the Arduino IDE
7574
7584
void setup () {
7575
7585
Serial.begin (9600 );
7576
7586
int start = millis ();
@@ -7579,7 +7589,7 @@ void setup () {
7579
7589
initenv ();
7580
7590
initsleep ();
7581
7591
initgfx ();
7582
- pfstring (PSTR (" uLisp 4.4 " ), pserial); pln (pserial);
7592
+ pfstring (PSTR (" uLisp 4.4b " ), pserial); pln (pserial);
7583
7593
}
7584
7594
7585
7595
// Read/Evaluate/Print loop
@@ -7599,7 +7609,7 @@ void repl (object *env) {
7599
7609
pint (BreakLevel, pserial);
7600
7610
}
7601
7611
pserial (' >' ); pserial (' ' );
7602
- Context = 0 ;
7612
+ Context = NIL ;
7603
7613
object *line = read (gserial);
7604
7614
if (BreakLevel && line == nil) { pln (pserial); return ; }
7605
7615
if (line == (object *)KET) error2 (PSTR (" unmatched right bracket" ));
0 commit comments