-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathLISTS1.C
2505 lines (2114 loc) · 78.6 KB
/
LISTS1.C
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
/*
;
; This module belongs to St. Vitus' Lisp which is the Lisp Interpreter
; for the MS-DOS machines. This is used also by many other programs
; which use the list-subsystem software package coded by Antti Karttunen,
; e.g. softwares like KANJIDIC (Electronic Kanji Dictionary) and ODE11
; (Octal Debugger & Executor for the PDP-11 code).
; Following text applies to this module and to
; all other modules in this package unless otherwise noted:
;
; Copyright (C) 1991 Antti J. Karttunen
;
; This program is free software; you can redistribute it and/or modify
; it under the terms of the GNU General Public License as published by
; the Free Software Foundation; either version 1, or (at your option)
; any later version.
;
; This program is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
; GNU General Public License (in file GPL.TXT) for more details.
;
; You should have received a copy of the GNU General Public License
; along with this program; if not, write to the Free Software
; Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
;
*/
/* LISTS1.C -- Copyright (C) 1988, 1989, 1990 & 1991 Antti Karttunen
Writing of this file started at 7. & 8. October 1988.
This file contains most of the list-reading and printing
functions and the lots of other miscellaneous stuff.
Memory allocation functions, symbol table
(*oblist*) functions intern & lookup are now in separate files.
(car, cdr & so on are in fundamen.asm).
This module is used by many programs, mainly by:
LISP.EXE (St. Vitus' Lisp), compile with -DSVL
KANJIDIC.EXE (Electronic Kanji-Dictionary) and (-DKANJIDIC)
ODE11.EXE (Octal Debugger & Executor for the PDP-11 code).
All coded by (C) Antti Karttunen.
*/
/* List concept fundamentally changed at 26-DEC-88. Typed Objects, TOB's */
/* List structure changed again at 26-MAR-89. "Conanized pointers" are used
instead of 20-bit absolute addresses. (Almost two times faster !)
Abridged for kanjidic.c, some Lisp-I/O-functions removed at 17-Sep-1989
to their own module.
Read macros added at 3. & 4. of January of 1991, by AK.
Actually this whole module requires cleaning up, i.e. removing of all the
awful kludges and replacing them with more uniform stuff.
More control should be given to lisp interpreter by means of global
system variables (and maybe read macros), and character syntax tables
(something like ctp_[]). (And possibility to define own integer printtypes
from lisp interpreter ?) (but that's done already!)
And maybe function names and syntax should be made more Franz lisp
compatible.
_IBASE_ & _INTEGER_PRINTTYPES_ compactlist-vector 6-Jan-1991
Monenkin jutun sis{{nlukemisen implementointi "sis{isin{ read-macroina"
olisi miettimisen arvoinen juttu.
Esim. ' quote (lisp)
#' function (lisp)
/* C-style comment
; comment (zapline_rm ?)
" string
` character or something else
0 Octal numbers (done already, maybe lousily)
1-9 Decimal numbers
( read list ?
< { and [ read special list ?
24.AUG.1991 All above done ! genauxread is much cleaner now.
10-AUG-1991. Some minor modifications made by AK.
Some issomething -macros changed to f_issomething so that
reading-process doesn't go haywire when it encounters
8-bit letters, e.g. IBM- or ISO-scandis or Shift-JIS kanji-characters.
Function skipwhitespaces now recognizes also Shift-JIS blankos, (hex. 8140).
*/
#include "includes.h"
#define LPAR '(' /* +1 */
#define RPAR ')'
/* BEGHAR is some list-starting char,
returns corresponding list-ending char:
I.e. if it's ( then returns ), and for any other character that
character + 2, so that for example following pairs work: { } [ ] < >
*/
#define getlendchar(BEGHAR) ((BEGHAR == LPAR) ? (BEGHAR + 1) : (BEGHAR + 2))
#define C 1
/* Error flags for signerror: */
#define LUNBALANCED 257
#define RUNBALANCED 258
#define UNMATQUOTE 259
#define COMMENTNEVERENDS 260
#define INV_DTPR 261 /* Invalid Dotted Pair */
#define INV_QUOTEXPR 262 /* Invalid Quoted Expression */
#define INV_QUOTCHAR 263 /* Invalid Quoted Character */
#define INV_READMACRO 264 /* Invalid Readmacro */
#define INV_IBASE 265 /* Invalid ibase (not 8 nor 10) */
TOB findsymbols();
BYTE *_EMPTY_STRING_ = byteptr("");
/* This is 'dynamic' pointer, it floats through line: */
/* First time (in program execution) in getnextchar forces to read new line: */
/* maybe_static */ BYTE *lineptr = NULL;
/* Remember that whenever lineptr is set to NULL, it should be immediately
set to _EMPTY_STRING_ so that getnextchar works at the next time */
/* maybe_static */ BYTE *_save_lineptr=NULL;
static PFSTR getfun;
/* This is 'static' pointer, i.e. it always points to start of line */
maybe_static BYTE *linebuf = byteptr("<VIRGIN>");
static int maxline;
static void *source;
static long linecount=0;
static int visitcount=0;
BYTE *lto2hex();
BYTE *parse_char();
BYTE *itohex();
static PFTOB internfun=intern;
/* Returns the next character. Zero if End Of File encountered. */
/* Remember that lineptr points to the next character of linebuf
* after getnextchar()
* (i.e. related to that character which getnextchar returned)
*/
/* maybe_static */ UINT getnextchar()
{
UINT getnextchar();
/* If there is still something in this line, then return it: */
if(*lineptr) { return(*lineptr++); }
else /* if lineptr is in the end, then... */
{ /* ...there is reason to read a new line in */
/* This is for the read-macro checking code in genauxread, so that
it knows when the new line has been read in: */
_save_lineptr = NULL;
lineptr = ((*getfun)(linebuf,maxline,source));
/* if got NULL, then return 0 as sign of EOF: */
if(!lineptr) { lineptr = _EMPTY_STRING_; return(0); }
else { if(linecount != -1) { linecount++; } }
/* If in sentence mode then convert ibm-scandis to seven bit ones: */
if(*sent_flag) { convert_string(lineptr,ibm_scand2asc); }
return(getnextchar()); /* And try again... */
}
}
/* Now also handles Shift-JIS blanks (umlaut-u and @ hex: 8140): */
maybe_static int skipwhitespaces()
{
UINT getnextchar();
register UINT c;
leguaani:
while(f_isspace(c = getnextchar())) { }
if((c == 0x81) && (*lineptr == '@')) /* If Shift-JIS blank */
{ lineptr++; goto leguaani; } /* Skip the miau, and loop back */
return(c); /* return first non white space character. */
}
/* sreadexpr: Reads expression from the string given as argument.
If there is nothing in string (i.e. it's "" or contains just white spaces)
then ENDMARK is returned.
Modified at 15. March 1988 to allow multiple reads from same string,
so that rest of string after returned expression is copied to start.
For example: if string called string is initially as below:
BYTE *string = "AKU (1 2) REPE";
then if sreadexpr is called many times, following happens:
1st time: sreadexpr(string) returns symbol AKU, string is " (1 2) REPE"
2nd time: sreadexpr(string) returns list (1 2), string is " REPE"
3rd time: sreadexpr(string) returns symbol REPE, string is ""
4th & last time:
sreadexpr(string) returns ENDMARK, because string ended.
Of course argument of sreadexpr can be constant-string too, like:
sreadexpr("TAVI (6 9) PETO") and it works equally well
when calling many times, although it is a little bit perverse idea
to modify constant-strings.
*/
TOB sreadexpr(line)
BYTE *line;
{
TOB genread();
TOB e;
BYTE *getoneline();
PFSTR save_getfun;
BYTE *save_lineptr,*save_linebuf;
void *save_source;
int save_maxline,save_visitcount;
/* Save (& Restore) essential read variables, so that ,,environ_var_name
doesn't mess up the things:
*/
save_getfun = getfun;
save_lineptr = lineptr;
save_linebuf = linebuf;
save_source = source;
save_maxline = maxline;
save_visitcount = visitcount;
visitcount = 0;
/* linecount = -1; */
lineptr = _EMPTY_STRING_;
/* ==> so that first time in getnextchar assigns
lineptr to linebuf (via getoneline) */
e = genread(getoneline,line,0,NULL);
/* Copy the rest of string to the start of line, so that
caller can call sreadexpr another time to read more expressions
from line, if there is any.
*/
strcpy(line,lineptr);
getfun = save_getfun;
lineptr = save_lineptr;
linebuf = save_linebuf;
source = save_source;
maxline = save_maxline;
visitcount = save_visitcount;
return(e);
}
BYTE *getoneline(line,turha,turha2)
BYTE *line;
int turha;
void *turha2;
{
if(!visitcount) { visitcount++; return(line); }
else { return(NULL); }
}
/* Returns next expression from input stream fp
* and type of expression in status.
* If () is encountered, returns NIL, (of course)
* If EOF is encountered, returns ENDMARK.
*/
TOB readexpr(fp) /* Read Expression (from file-stream fp) */
FILE *fp;
{
TOB genread();
BYTE *myfgets(); /* fgets changed to myfgets */
/* shouldn't do lineptr = ""; here because there can still be unread stuff
in linebuf after previous call to readexpr (lineptr is pointing there)
*/
return(genread(myfgets,(tob_string(_LINEBUF_)+3),_LINEBUFSIZE_,fp));
}
TOB genread(_getfun,_linebuf,_maxline,_source)
PFSTR _getfun;
BYTE *_linebuf;
int _maxline;
void *_source;
{
TOB genauxread();
register TOB p;
UINT lendchar;
getfun = _getfun;
linebuf = _linebuf;
maxline = _maxline;
source = _source;
/* See Aztec-C manual, System Independent Functions, pages lib.57 & 58 */
if(setjmp(readerrbuf))
{ /* If encountered read-error: (coming from signerror) */
zapline_rm(); /* Clear the line from other rubbish */
return(ENDMARK);
}
p = genauxread();
/* If we have encountered ending-parentheses ')', for example,
then it is surely unbalanced expression: */
if(specharp(p) && (lendchar = tob_spechar(p)))
{ signerror(LUNBALANCED,lendchar); }
else { return(p); }
}
/* This is the function which scans the line buffer, skips the white spaces,
then calls the corresponding read macro if that has been defined for
that character, otherwise returns symbol composed of those character(s).
*/
TOB genauxread()
{
TOB result;
register BYTE c;
loopus:
c = skipwhitespaces();
if(!c) { return(ENDMARK); }
/* Check whether a read macro has been defined
for this char. Do it here so that meaning of all other characters
than '\0', tab, and spaces can be overridden by user:
*/
if(!nilp(result = cxr(c,_READ_MACROS_)))
{
result = call_readmacro(c,result);
/* If read macro returned endmark then ignore the character and continue
reading. (Like splicing read macro returning NIL in Franz lisp): */
if(endmarkp(result))
{
if(_save_lineptr != lineptr) { goto loopus; }
/* If read macro returned ENDMARK and left lineptr to point to the
character which triggered it, then don't go back to loopus,
because that would result an idiot loop, when same character
would trigger the same read macro again and again. Instead
continue from this point:
*/ c = skipwhitespaces();
if(!c) { return(ENDMARK); }
/* Otherwise fall through to the bottom, where symbol_rm is called */
}
else { return(result); }
}
/* else */ /* If not anything else, then it must me some symbol, */
{ /* e.g: kala * or krapulapieru */
/* Symbol parsing function is stored as "read macro" for
character '\0' which is never encountered on real input: */
result = call_readmacro(0,car(_READ_MACROS_));
/* If user defined read macro returned ENDMARK (default internal read
macros never return that) then go back to the beginning of loop.) */
if(endmarkp(result)) { goto loopus; }
/* else */ return(result);
}
}
TOB call_readmacro(c,aurinko)
BYTE c;
register TOB aurinko; /* Aurinko contains various things at various times */
{
/* Set _save_lineptr to point the character which triggered this read macro:
*/
_save_lineptr = lineptr-1;
if(nonnilsymbolp(aurinko)) { aurinko = value(aurinko); }
#ifdef SVL /* If compiled for Lisp */
/* If read macro defined in Lisp: */
if(consp(aurinko)) /* || nonnilsymbolp(aurinko) */
{
TOB apply();
/* Nowadays apply accepts also single atom for arglist,
so this line is used: */
aurinko = apply(aurinko,string_tob(_save_lineptr));
}
else
#endif
if(bcdp(aurinko))
{ aurinko = ((*(tob_fun(aurinko)))(string_tob(_save_lineptr))); }
else /* Illegal read macro definition in _READ_MACROS_ */
{ signerror(INV_READMACRO,c); }
return(aurinko);
}
maybe_static UINT isnumber(rest,s)
register BYTE **rest,*s;
{
UINT default_base;
*rest = s;
/* If ibase is 0, then don't read numbers at all: (intern them as symbols) */
if(!(default_base = tob_uint(value(_IBASE_)))) { return(0); }
/* single + or - is not a valid number: */
if(!f_isdigit(*s) && !f_isdigit(*(s+1))) { return(0); }
while(f_isdigit(*++s)) { }
/* If number ends in dot, and after that dot is some non-continuous characters
then it's decimal anyway, regardless of ibase: */
if((*s == '.') && !iscontinuous(s+1))
{ *rest = s+1; return(10); }
else if(iscontinuous(s)) { return(0); }
else
{
*rest = s;
return(default_base);
}
}
/* This should be assigned to characters + and - and digits 1-9 and
also to 0 if that's not assigned to octhex_rm
*/
TOB number_rm(line)
TOB line;
{
ULI atol();
ULI lum; /* Beware of Lum ! */
int num;
UINT base;
BYTE *piece;
/* Set lineptr back to the triggering character */
set_lineptr(line);
/* If not a valid number (or ibase = 0) then leave lineptr point
to the triggering character and return endmark to indicate that
this should be read in normal way (as a symbol):
*/
if(!(base = isnumber(&piece,lineptr)))
{ return(ENDMARK); }
else
{
if(base == 8)
{
sscanf((lineptr + (*lineptr == '-')),"%lo",&lum);
}
else if(base == 10) /* Decimal number */
{
/* Take the absolute long value from lineptr: (get it ?) */
lum = atol(lineptr + (*lineptr == '-'));
}
else { signerror(INV_IBASE,base); }
if(*lineptr == '-') /* If negative value... */
{ /* -32768 is the lowest negative 16-bit integer: */
if(lum > 32768)
{ lum = -lum; goto longcell; }
else { num = lum; num = -num; }
}
else /* it's positive */
{
if(lum > 65535) { goto longcell; }
else { num = lum; }
}
lineptr = piece; /* assign lineptr to the rest of line */
return((base == 8) ? oct_tob(num) : dec_tob(num));
}
/* Numbers which don't fit to sixteen bits (-32768 -- 65535) are
returned as longcells: */
longcell:
lineptr = piece;
return(make_longcell(lum,ENDMARK));
}
/* read macro for reading octal & hex numbers, with leading zero.
This should be assigned to the character '0'
If there is some non-octal characters (other than spaces and such)
then number_rm read macro is used for them.
I think that this should also return longcells if magnitude goes
above 65535 but I don't care to write it now.
*/
TOB octhex_rm(line)
TOB line;
{
register UINT z;
BYTE *s;
/* If ibase is zero then don't read even octal numbers: */
if(!(tob_uint(value(_IBASE_)))) { return(set_lineptr(line)); }
s = tob_string(line);
/* At this point s should point to the triggering character
(i.e. 0) and lineptr to character just after that */
/* If C-style hex number: */
if(*s == '0' && (*lineptr == 'x') && f_isxdigit(*(lineptr+1)))
{
return(hex_tob(hextoi(&lineptr,++lineptr)));
}
/* Start converting from first digit (i.e. c) if it's accidentally
something else than '0', e.g. if user has assigned this read macro
to other digits too:
(s is assigned to point to first non-octal-digit character)
*/
z = octoi(&s,s);
/* If immediately after octal digits is "alnum" digit or dot then
try with number_rm whether it's decimal number:
*/
if((iscontinuous(s)) || (*s == '.'))
{
return(number_rm(line));
/* This is commented out:
lineptr--; (* Set lineptr point back to that zero *)
return(ENDMARK);
*/
}
/* If s is still pointing to lineptr, i.e. there was no octal digits
after zero, then return zero with decimal subtype, not octal: */
if(s == lineptr) { return(int_tob(z)); }
else { lineptr = s; return(oct_tob(z)); }
}
#ifdef SVL
TOB quote_rm(line)
TOB line;
{
UINT c;
c = *tob_string(line);
line = genauxread();
if(endmarkp(line)) { signerror(INV_QUOTEXPR,c); }
return(list2(_QUOTE_,line));
}
/* This converts #'expression in input to (function expression)
This function should be assigned to character #
*/
TOB function_rm(line)
TOB line;
{
UINT c;
/* If the second character is not single quote (') then
set lineptr back to # and read it in the normal way: */
if(*lineptr != '\'')
{
lineptr--;
return(ENDMARK);
}
c = *(tob_string(line));
getnextchar(); /* "read away" that single-quote */
line = genauxread();
if(endmarkp(line)) { signerror(INV_QUOTEXPR,c); }
return(list2(_FUNCTION_,line));
}
#endif
TOB comment_rm(line)
TOB line;
{
register UINT endchar,c;
/* If the second character is not an asterisk (*) then
set lineptr back to triggering character (usually slash)
and read it in the normal way:
*/
if(*lineptr != '*')
{
lineptr--;
return(ENDMARK);
}
/* Get the triggering character to endchar: */
endchar = *(tob_string(line));
lineptr++; /* Skip the asterisk */
Mikki_Hiiri_Korvat:
while((c = getnextchar()) && (c != '*')) { }
if(!c) { signerror(COMMENTNEVERENDS,0); }
if(*lineptr != endchar) { goto Mikki_Hiiri_Korvat; }
getnextchar(); /* "read away" that endchar */
return(ENDMARK);
}
/* This is normally assigned to semicolon (;) */
TOB zapline_rm()
{
while(*lineptr) { lineptr++; }
return(ENDMARK);
}
/* This is a read macro for character quote: */
TOB charquote_rm(line)
TOB line;
{
BYTE c;
UINT rezult,rezult2;
/* Put to c the character which triggered this read macro: */
c = *(tob_string(line));
lineptr = parse_char(&rezult, lineptr);
/* If there's ending quote after first char or something like \X8140 */
if((*lineptr == c) || (rezult > 255))
{ /* If latter case then check that there's ending quote, and skip it: */
if(*lineptr++ != c) { signerror(INV_QUOTCHAR,c); }
return(char_tob(rezult)); /* And return the result */
}
else /* There's a double char constant */
{ /* Read the second one: */
lineptr = parse_char(&rezult2, lineptr);
if(*lineptr++ != c) { signerror(INV_QUOTCHAR,c); }
/* First char to high byte, second one to low byte: */
return(char_tob((rezult << 8) + rezult2));
}
}
/* This is a read macro for string quote, usually a doublequote: */
TOB stringquote_rm(line)
TOB line;
{
/* Read string in from that triggering quote onward: */
return(getnextstring(&lineptr,tob_string(line)));
}
/* This is for kanjidic: #ifdef KANJIDIC */
TOB value_rm(line)
TOB line;
{
TOB result;
BYTE c;
/* Put to c the character which triggered this read macro: */
c = *(tob_string(line));
/* If there is two that kind of characters one after another then
get the value of an environment variable: */
if((*lineptr == c))
{
BYTE *getenv();
BYTE save_DINS_flag;
save_DINS_flag = *dins_flag;
*dins_flag = 0; /* Intern new symbols */
getnextchar(); /* "read away" that second getvaluechar */
result = genauxread();
if(endmarkp(line))
{
*dins_flag = save_DINS_flag;
signerror(INV_QUOTEXPR,c);
}
if(gen_stringp(result))
{
BYTE *s;
if(!(s = getenv(pname(result)))) { result = NIL; }
else
{
BYTE buf[165];
/* Make safe copy of s because sreadexpr corrupts it: */
strncpy(buf,s,163);
result = sreadexpr(buf);
}
}
*dins_flag = save_DINS_flag;
return(result);
}
/* Else it's read macro for getting value of symbol:
(only one getvalue char): */
else
{
result = genauxread();
if(endmarkp(result)) { signerror(INV_QUOTEXPR,c); }
else { return(nonnilsymbolp(result) ? value(result) : result); }
}
}
/* #endif */
TOB listend_rm(line)
TOB line;
{
return(spechar_tob(*(tob_string(line))));
}
TOB listbegin_rm(line)
TOB line;
{
TOB genauxread();
TOB item; /* returned by genauxread */
UINT lbegchar;
UINT lendchar;
UINT infovar;
BYTE dots_encountered=0;
TOB start,lista;
lbegchar = *tob_string(line);
lendchar = getlendchar(lbegchar);
lista = start = cons(NIL,NIL);
if(lbegchar != LPAR)
{ /* If not that ordinary parentheses () list, then put lbegchar
* to first member of list:
*/
rplacd(lista,cons(spechar_tob(lbegchar),NIL));
lista = cdr(lista);
}
/* Continue so long as item returned is not ENDMARK. */
while((item = genauxread()) != ENDMARK)
{ /* And not spechar, i.e. list ending character: */
if(specharp(item) && (infovar = tob_spechar(item)))
{ break; }
rplacd(lista,cons(item,NIL));
lista = cdr(lista);
if(eq(item,_DOT_) && *dtpr_flag) { dots_encountered++; }
}
if(endmarkp(item))
{ /* Too much on the left, something is lacking on the right */
signerror(RUNBALANCED,lendchar);
}
else
{
if(infovar == lendchar) /* this particular (correct one) */
{
rplacd(lista,NIL); /* Complete the list */
lista = free_cons(start); /* Free start and get cdr of it */
if(dots_encountered)
{
TOB naarasvompatti;
naarasvompatti = lista; /* Save lista */
lista = make_dtpr(dots_encountered,lista);
free_list(naarasvompatti); /* Free the old list */
}
return(lista);
}
else /* too much on the right, something lacks on the left side.
* (because we got wrong kind of list-end-character) */
{ signerror(LUNBALANCED,infovar); }
}
}
/* New compact_read_the_list by AK at 27-11-1989.
(Name changed to clistbegin_rm).
Old scheme didn't always work because compact list was allocated to
stack, and in some occassions it could cross "segment boundary"
(i.e. 0x?000:FFFF), and that would confuse cdr et other list
handling primitives. So now stuff is still read into stack,
but to tob vector instead of compact list
(each item takes four bytes, not three).
*/
TOB clistbegin_rm(line)
TOB line;
{
TOB genauxread(),c_make_dtpr(),tobvec_to_clist();
TOB item; /* returned by genauxread */
UINT lbegchar;
UINT lendchar;
UINT infovar,count=0;
BYTE dots_encountered=0;
TOB *lptr;
TOB read_buf[SIZEOF_CLISTREADBUF+3];
lbegchar = *tob_string(line);
lendchar = getlendchar(lbegchar);
lptr = read_buf;
if(lbegchar != LPAR)
{ /* If not that ordinary parentheses () list, then put lbegchar
* to first member of list:
*/
*lptr = spechar_tob(lbegchar);
lptr++;
count++;
}
/* Continue so long as item returned is not ENDMARK. */
while((item = genauxread()) != ENDMARK)
{ /* And not spechar, i.e. list ending character: */
if(specharp(item) && (infovar = tob_spechar(item)))
{ break; }
if(count > SIZEOF_CLISTREADBUF)
{
fprintf(stderr,"\n**ERROR in compact_read_the_list:\n");
fprintf(stderr,
"count is greater than SIZEOF_CLISTREADBUF (%d > %d). Compact list abridged.\n",
count,SIZEOF_CLISTREADBUF);
prstat(stderr);
infovar = lendchar;
count--;
break;
/*
myexit(1);
*/
}
*lptr = item;
lptr++;
count++;
if(eq(item,_DOT_) && *dtpr_flag) { dots_encountered++; }
}
if(endmarkp(item))
{ /* Too much on the left, something is lacking on the right */
signerror(RUNBALANCED,lendchar);
}
else
{
if(infovar == lendchar) /* this particular (correct one) */
{
if(!count) { return(NIL); } /* If read 0 elements */
*lptr = NIL; /* Put the ending NIL to vector (not necessary ?)*/
if(dots_encountered)
{
return(c_make_dtpr(dots_encountered,read_buf,count));
} /* it's normal list: */
else { return(tobvec_to_clist(read_buf,count)); }
}
else /* too much on the right, something lacks on the left side.
* (because we got wrong kind of list-end-character) */
{ signerror(LUNBALANCED,infovar); }
}
}
/*
TOB compact_read_the_list(lbegchar)
int lbegchar;
{
TOB genauxread();
TOB item; (* returned by genauxread *)
int lendchar;
int infovar,count=0;
BYTE dots_encountered=0;
TOB start,lista;
declare_clist(read_buf,(SIZEOF_CLISTREADBUF+2));
lista = start = cons_tob(read_buf);
rplacc(start,1); (* set compact bit for zeroth element *)
lendchar = getlendchar(lbegchar);
if(lbegchar != LPAR)
{ (* If not that ordinary parentheses () list, then put lbegchar
* to first member of list:
*)
BYTE smallbuf[2];
smallbuf[0] = lbegchar;
smallbuf[1] = '\0';
lista = cdr(lista);
rplaca(lista,((*internfun)(smallbuf)));
rplacc(lista,1);
count++;
}
(* Continue so long as item returned is not ENDMARK. *)
while((item = genauxread()) != ENDMARK)
{
if(count > SIZEOF_CLISTREADBUF)
{
fprintf(stderr,"\nERROR in compact_read_the_list:\n");
fprintf(stderr,"count is greater than SIZEOF_CLISTREADBUF (%d > %d)\n",
count,SIZEOF_CLISTREADBUF);
prstat(stderr);
myexit(1);
}
lista = cdr(lista);
rplacac(lista,item);
count++;
if(eq(item,_DOT_) && *dtpr_flag) { dots_encountered++; }
}
if(infovar == EOF)
{ (* Too much on the left, something lacks on the right *)
signerror(RUNBALANCED,lendchar);
}
else if((*islendcharfun)(infovar))
{
if(infovar == lendchar) (* this particular (correct one) *)
{
if(lista == start) { return(NIL); } (* If read just () *)
rplacc(lista,0); (* clear c-bit from last elem (necessary ?) *)
rplacd(lista,NIL); (* Complete the list *)
if(dots_encountered)
{
return(make_dtpr(dots_encountered,cdr(start)));
}
else { return(clistsave(cdr(start))); } (* it's normal list *)
}
else (* too much on the right, something lacks on the left side.
* (because we got wrong kind of list-end-character) *)
{ signerror(LUNBALANCED,infovar); }
}
}
*/
/* Auxiliary function for plain_read_the_list: */
TOB make_dtpr(dots_encountered,lista)
register BYTE dots_encountered;
register TOB lista;
{
if((length(lista) != 3) || /* If length is not three */
(dots_encountered != 1) || /* Or more than one . met */
(!eq(cadr(lista),_DOT_))) /* Or middle one is not dot */
{ signerror(INV_DTPR,'.'); } /* Then it is invalid dotted pair. */
else /* it's correct, of the form (something . something) */
{
return(cons(car(lista),car(cddr(lista))));
}
}
/* Auxiliary function for compact_read_the_list: */
TOB c_make_dtpr(dots_encountered,tobptr,count)
register BYTE dots_encountered;
register TOB *tobptr;
int count;
{
if((count != 3) || /* If length is not three */
(dots_encountered != 1) || /* Or more than one . met */
(!eq(*(tobptr+1),_DOT_))) /* Or middle one is not dot */
{ signerror(INV_DTPR,'.'); } /* Then it is invalid dotted pair. */
else /* it's correct, of the form (something . something) */
{
return(cons(*tobptr,*(tobptr+2)));
}
}
/*
Creates (interns) symbol from all the continuous characters from
line onward, and sets lineptr point to the first following non-continuous
character on line. If first char of line is non-continuous, then
single-char symbol interned from that is returned.
*/
TOB symbol_rm(line)
TOB line;
{
TOB result;
register BYTE *string;
BYTE *start;
BYTE save;
string = tob_string(line);
start = string; /* mark the start of the string */
/* It is guaranteed that string is never "", (i.e. empty)
so following line is unnecessary: */
/* if(!*string) { return(NULL); } */
/* If first char is noncontinuous then symbol is made from that
single character: */
if(!(iscontinuous(string))) { string++; }
else /* Otherwise all the following continuous characters are */
{ /* taken to the symbol: */
while(iscontinuous(string)) { string++; }
}
lineptr = string; /* Parsing continues from this onward */
save = *string; /* Save the first non-continuous character */
*string = '\0'; /* So that it can be overwritten with zero */
/* so that intern works... */
if(*nil_flag && !strcmp(start,"nil")) { result = NIL; }
else { result = ((*internfun)(start)); }
*string = save;
return(result);
}