-
Notifications
You must be signed in to change notification settings - Fork 2
/
Copy pathmanual.ms
2519 lines (1843 loc) · 144 KB
/
manual.ms
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
@Comment{-*- Mode: Text; Fonts: tr10, tr10i, tr10b, gach10, gach10b, gach10i; VSP: 0; Tab-width: 5 -*-
ZETA-C User's Guide
This document has been placed in the public domain.
This file is set up for the FinalWord Formatter, v2.0. By now it is pretty totally wired in to the Apple Laserwriter.}
@Make(Manual)
@Style(TabSize 5)
@Define(st, font 12)
@Define(lt, font Helvetica250.bold)
@Define(it, font 12.italic)
@TCT("<<" "<<")
@TCT(">>" ">>")
@TCT(' "' "@case{font, 12, Helvetica250.bold ' "', else "@set(inquote 1)@char(0AAH)"}")
@TCT('("' "@case{font, 12, Helvetica250.bold '("', else "@set(inquote 1)(@char(0AAH)"}")
@TCT('"' "@case{font, 12, Helvetica250.bold '"', else "@set(inquote +1)@oddvalue(inquote,y "@char(0AAH)",n "@char(0BAH)")"}")
@TCT(" '" "@case{font, 12, Helvetica250.bold " '", else "`"}")
@Comment(Customizing manual for keyboard and other variables)
@String(Brand "TI")@Comment(or "Symbolics" or "LMI")
@String(Class "LMITI")@Comment(or "Symbolics")
@String(Machine "Explorer")@Comment(or "3600" or "LAMBDA")
@Case(Brand, LMI {@Form(BreakKey = "[Break]")@Form(SystemKey = "[System]")@~
@Form(RuboutHandlerTerm = "rubout handler")@Form(Qfasl = "@st<.QFASL>")@Form(CCFile = "cc-file")},
TI {@Form(BreakKey = "[Break]")@Form(SystemKey = "[System]")@~
@Form(RuboutHandlerTerm = "rubout handler")@Form(Qfasl = "@st<.XFASL>")@Form(CCFile = "zeta-c:c-compile-file")},
Symbolics {@Form(BreakKey = "[Suspend]")@Form(SystemKey = "[Select]")@~
@Form(RuboutHandlerTerm = "input editor")@Form(Qfasl = "@st<.BIN>")@Form(CCFile = "zeta-c:c-compile-file")})
@String(ManualEdition "1.10")
@String(Release "1.1")
@String(System "TI Explorer Release 2.0")
@String(ZCSysVersion "15.0")
@Comment(Title page)
@PageFooting()
@Blankspace(1.33 in)
@MajorHeading{ZETA-C@+<(TM)> User's Guide}
@Blankspace(1 in)
@Center{This document has been placed in the public domain.
Manual edition @Value(ManualEdition)
for ZETA-C Release @Value(Release) (version @Value(ZCSysVersion))
running under @Value(System)
@Value(Day) @MonthName 19@Value(Year)}
@Comment(Inner title page)
@NewPage
@Begin(Text, Margins 1.75 in)
@Blankspace(2.5 in)
This document was formatted with the FinalWord(TM) v2.2 by Mark of the Unicorn, Inc., and printed on an Apple
LaserWriter(R).
Scott Layson Burson, the author of ZETA-C, wishes to acknowledge: the M.I.T. Artificial Intelligence Laboratory, for supporting
the original creation of Lisp Machines; the once-thriving Atari Cambridge Research Laboratory, for reintroducing him to
Lisp Machines and for providing an environment where the value of a C compiler for them could be clearly seen; LISP
Machines, Inc., for their generous assistance during the development of ZETA-C; and Thinking Machines Corp., especially
John Rose, for daring to be the first beta-test site.
@End(Text)
@Set(Page = 0)
@Comment{LaserWriter wizardry here, courtesy of BNH}
@Pageheading(left "ZETA-C User's Guide", right "@Value(ChapterTitle)",
line "@Escape(send ')p gsave 70 setlinewidth 1800 18675 moveto 13500 18675 lineto stroke 15 setlinewidth 1800 18787 moveto 13500 18787 lineto stroke grestore (')")
@Pagefooting(right "Page @Value(Page)",
line "@Escape(send ')p gsave 15 setlinewidth 1800 1800 moveto 13500 1800 lineto stroke grestore (')")
@String(ChapterTitle "Introduction")
@NewPage
@PrefaceSection(Introduction and obligatory hype)
Lisp Machines -- the Symbolics 3600(R) series, LMI LAMBDA(R), and TI Explorer(R) -- provide the best software
development environments in the world, but to date they have not been very useful for cross-development: it has been
difficult to take a program created and debugged on a Lisp Machine and transfer it to some other environment, as this
usually requires translating the program from Lisp to some other language. Conversely, programs written in other
languages in other environments could not be run on a Lisp Machine.
ZETA-C(TM) helps bridge this portability gap by bringing C -- the popular systems language of UNIX(R) -- to the Lisp
Machine. With ZETA-C, it is possible to develop programs in C and still make use of the power of the Lisp Machine
environment.
C, as traditionally implemented, is @i<unsafe>:@Index(safety of a C implementation) it is possible for an erroneous procedure
to damage data structures to which it is not intended to have access, typically by storing through an invalid pointer or
storing into an array at an invalid index. Indeed, the greater part of debugging a C program often consists of tracking
down such errors. Also, errors like these are often especially hard to find, as it will only be sometime later that the
damaged data structure will cause the process to crash, and by the time the crash finally comes, a lot of information
may have been lost that would be useful in diagnosing the error.
ZETA-C, on the other hand, is @i<safe>: the automatic array-bounds and pointer-validity checking which are built into the
Lisp Machine ensure that no procedure can damage a data sructure to which it doesn't explicitly have access. An
attempt to store through an uninitialized pointer, or into an array at an invalid index (whether by way of a pointer or
an explicit @lt<array[index]> reference) will be trapped immediately, giving the user the full power of the Lisp Machine's
sophisticated debugger. The user can then examine the context in which the damage was about to be done, rather than
the unrelated context in which it would, in the traditional scenario, have been discovered. The time required to
diagnose the problem is thus reduced from hours or days to minutes.
Another time-saving feature of the Lisp Machine system is its facility for incremental compilation@Index(incremental
compilation) and dynamic linking. Traditionally, when one makes a change to a single procedure, the entire file
containing the procedure must be recompiled, and the entire program (which may consist of several files) relinked, before
the change can be tested. For even medium-sized programs, this debugging turnaround can easily run to 10 minutes.
Under ZETA-C, all of the "symbol tables" and intermediate data structures (which a traditional system must recreate
from scratch for every compilation and linking) are maintained incrementally; so only the procedures changed need be
recompiled, and there is no link phase. The turnaround is thus a few tens of @i<seconds>, independent of the size of the
program.
ZETA-C programs live in the Lisp world, and can call Lisp functions and access some kinds of Lisp data structures
directly. Thus, it is possible to incrementally convert a program from Lisp to C or vice versa. For instance, one might
prototype a program in Lisp, then convert its modules one by one into C, testing the whole system as each module is
converted. Conversely, it is easy to interface existing C programs to the Lisp world.
The price of the runtime array-bounds checking is, unavoidably, a certain performance penalty for array- and
pointer-intensive C code (and, of course, most C code is array- and pointer-intensive). More subtly, algorithms are
written very differently in C than in Lisp, and Lisp Machine architectures are, obviously, optimized for the Lisp way
of doing things. As a result, @Case(Machine, 3600 "a 3600/3670/3640", Explorer "an Explorer", LAMBDA "a LAMBDA")
runs a typical C program about @Case(Machine, Explorer "1/3 to 1/2", Symbolics "1/2 to 2/3", LMIT "1/3 to 1/2") the
speed of a VAX 11/750(R). So we do not expect all CPU-intensive C programs to run acceptably under ZETA-C without
some hand-tuning.
Compatibility of ZETA-C with other C implementations is very good. We have used as our reference @i<C: A Reference
Manual> by Samuel P. Harbison and Guy L. Steele Jr. (Prentice-Hall, 1984). Chapter @Ref(IncompatibilitiesChapter)
documents the differences between ZETA-C and that standard.
@PrefaceSection(How to use this guide)
This User's Guide is organized into five chapters. The first provides an overview of ZETA-C and some examples of its
use. The second describes important details of the ZETA-C implementation and its interface to the Lisp Machine
environment. The third discusses the extensions that have been made to Zmacs for editing C files. The fourth describes
in detail the differences between ZETA-C and the Harbison & Steele standard. (These first four are probably of immediate
interest to the first-time user or prospective purchaser.) The fifth is a reference manual for the library of I/O routines
and "system calls".
@Begin(Comment)
Need a chapter for system installers/maintainers... Needn't go into tremendous detail, but should list all the
customization variables and mention the possibility of locally different defaults...
Also, eventually, a chapter on how to use ZETA-C internals for analyzing C programs for your own purposes.
I was going to have a chapter summarizing portability and performance issues, but the portability part seems to have
been absorbed into the ZETA-C dialect chapter, and I don't think there's really a lot to say about performance. (Even if
there is, I don't know what it is yet!)
@End(Comment)@~
This guide assumes throughout that the reader has some familiarity with the Lisp Machine software system and the
Common Lisp language. It also assumes a working acquaintance with C.
@Chapter(Overview and examples)@Tag(HelloPage = Page)@Index(overview of ZETA-C)@Index(examples of, ZETA-C use)
ZETA-C is a fully @i<integrated> implementation of C within the Lisp Machine environment. Its design philosophy has
been, not to "glue" a distinct C editing/compilation/execution system onto the side, as it were, of the Lisp Machine
software, but rather to @i<extend> the existing Lisp programming system to incorporate C. Thus, Lisp and C functions can
freely call each other; Lisp can access all C data structures directly (no new fundamental datatypes have been created),
and C can access many Lisp data structures; C code, like Lisp code, is edited with Zmacs, to which commands specific
to C have been added; debugging is done with the same facilities; in fact, ZETA-C compiles a C function by translating it
into Lisp and handing the result to the existing Lisp compiler.
To see how all this works in practice, let's run through a simple example. (This example is designed for you to follow
along at your own console, but it will still be comprehensible if you don't. Following along, of course, assumes that
ZETA-C has been installed at your site.) First, see if ZETA-C is loaded into your world; if not or if you don't know how
to tell, type at a Lisp listener @st<(make-system 'zeta-c :noconfirm)>. Second, get a Zmacs window, and edit a new file
named "@st<hello.c>" (in your home directory). As the first line of the file, type
@Begin(Display)
@st</* -*- Mode: C; Package: (hello C) -*- */>
@End(Display)
Issue the Zmacs command @lt<meta-X Reparse Attribute List>; you will notice that the Zmacs mode line now says
@NoTCT<@lt<(C)>>, indicating that C mode is active, and the wholine at the bottom of the screen now shows the current
package as @lt<HELLO:>. Next, enter the following C function.
@Begin(Display)@Index(example of, hello world)
@st<main()
{
printf("\nHello, world!\n");
}>
@End(Display)
Now give the Zmacs command @lt<control-shift-C>. You will see in the echo area, first @Case(Class, LMITI
{"@st<C-compiling MAIN>"}, Symbolics {"@st<Compiling MAIN>"}), then "@st<-- compiled.>" Now get to a C listener
by typing @st<@BreakKey>, and type "@st<main();>". You will see@Index(example of, C listener)
@Display{
@st<Hello, world!>
}
Type @st<[Resume]> or @st<[Abort]> to return to Zmacs. Now let's save this program as a file and compile it to produce
a @Qfasl file. Save the file with @lt<control-X control-S>, then select a Lisp listener (with @st<@SystemKey L>) and
type the form
@Display{@st<(@CCFile "@it<directory> hello.c")>}
@NoHinge
where @it<directory> is the name of your home directory. The value returned will be the pathname of the @Qfasl file;
type "@st<(load *)>" to load it, and "@st<(hello:|main|)>" to run the program. Note the vertical bars around the symbol @st<main>.
These are necessary to suppress the normal conversion of letters to uppercase.@Foot{The Lisp reader's uppercase
conversion allows the strings "@st<foo>", "@st<Foo>", and "@st<fOo>" (for example) all to be read as the symbol @st<FOO>; so Lisp code can
normally be written in upper, lower, or mixed case. C, on the other hand, requires that such strings be read as distinct
identifiers.} ZETA-C,@Index(identifiers)@Index(case of identifiers) unlike Lisp, is @i<case-sensitive>, and will not recognize
"MAIN" or "Main" as a version of "main". Instead these are three different symbols, and in our example, only the last
one has been defined. Be careful @i<not> to extend the upright bars around the package prefix, or Lisp will not recognize it
as such. If you wish to avoid using upright bars when calling C from Lisp, simply use all-uppercase names in your C
code.
Now let's try a fancier example. Still in Zmacs, find the file "@st<zeta-c:source;turtle.c>".@Index(turtle graphics) Give
the command @lt<meta-X @Case(Class, LMITI "C ")Compile Buffer>@Case(Brand, Symbolics { (you will see a message like
"@st<Warning: the package TURTLE failed the validation function; the standard value for it will not be
changed.>"; ignore it)}). When the compilation is complete, again hit @st<@BreakKey>, and type "@st<init();>". The mouse cursor
will change to an inverted-L shape, indicating that you are being asked to designate the corners of a window. Make a
small (2") square window which does not overlap with the editor window (this may not be possible, in which case after
you make the small window you should use the Edit Screen option on the system menu to reshape the editor window so
it does not overlap the new window; in this case type "@st<init();>" again after you uncover the new window). You will
see a small triangle (the "turtle") in the center of your window. Those of you who have ever played with the kids'
programming language Logo will recognize the commands available:
@Begin(Description, fill n, spread 0 lines, indent -1.2 in)
@st<fd(@it<dist>);>@\Move the turtle forward @it<dist> pixels, drawing a line.
@st<bk(@it<dist>);>@\Move the turtle back @it<dist> pixels, drawing a line.
@st<rt(@it<angle>);>@\Turn the turtle right by @it<angle> degrees.
@st<lt(@it<angle>);>@\Turn the turtle left by @it<angle> degrees.
@st<pu();>@\("Pen Up") Raise the turtle's "pen", so that it does not leave a line when it moves.
@st<pd();>@\("Pen Down") Lower the turtle's "pen", so that it @i<does> leave a line when it moves.
@End(Description)
These primitives are sufficient for drawing many kinds of pictures, from simple to quite complex. You can define
procedures using the C listener, just by typing in the definition as if you were entering it into a C source file. Try, for
instance, defining a procedure that draws a square of specified size:
@Begin(Display)@Index(example of, C listener)
@st<square(len) int len; { int i; for (i = 0; i < 4; ++i) { fd(len); rt(90); } }>
@End(Display)
Call it with various arguments. (You may notice that round-off error causes the squares to be slightly distorted.
Rewriting the arithmetic in @st<turtle.c> to prevent this is left as an exercise for the reader.) Write another procedure that
displays several squares of different sizes and/or at different orientations or origins. Play! The C listener is a very
important tool for interacting with your ZETA-C program, and it is worthwhile to spend a few moments simply getting
comfortable with it.
@Begin(Comment) I want to print this now...
[[Other examples to go in here: how to set up a full-blown C program, with @lt<argc>, @lt<argv>, and a current
directory; how to set up a @lt<defsystem> for a C program. -- Is this stuff really needed here?]]
@End(Comment)
@Chapter(The ZETA-C Implementation)@Index(ZETA-C implementation)@Index(implementation)
This chapter discusses details of the ZETA-C implementation and its interface to the Lisp Machine environment, both in
terms of the user side (how one goes about compiling and running C programs) and the Lisp side (how one connects Lisp
programs to C programs). Because of the open nature of the Lisp Machine software system, these two aspects are often
deeply intertwined.
@Section(Packages)@Tag(PackagesPage = Page)
It is important to understand how ZETA-C makes use of Lisp @b<packages>.@Index(package, C:)@Index(package, C program)
(The following discussion assumes an understanding of the package system; if you are not familiar with its use, you
should read the appropriate section of the Lisp Machine documentation). It is important that names (of variables,
functions, etc.) in a C program be kept distinct from those in the Lisp world as well as those in other C programs. For
instance, the ZETA-C user must be allowed to define a function @lt<car> without it conflicting with the Lisp function of
that name. To accomplish this, first, ZETA-C itself defines a package @lt<C:> which @i<does not> inherit from the @lt<GLOBAL:>
package; then, users define packages which inherit from @lt<C:> in which to intern their programs (we will call these latter
"C program packages").
@Case(Class, Symbolics {The Standard Value system@Index(standard value)@Index(validation function) checks,
whenever you enter a Lisp Listener (by entering the Debugger because of an error, or by hitting @st<[Suspend]>), that the
current package inherits from @lt<GLOBAL:>; if it doesn't (no C program package does) then it will choose some other package
-- often @lt<USER:> -- to make current. So on entering the debugger you will see a message like "@st<Binding> @st<PACKAGE to
#<Package USER 16600000> (old value was> @st<#<Package CPROG 20560347>).>" So when you're in the Debugger or a
Break loop, you will have to type an explicit package prefix to access symbols in your C program package.
Also, in ZMACS, whenever you select a buffer in C mode, you will see a message like "@st<Warning: the package CPROG
failed the validation function; the standard value for it will not be changed.>" These messages can be
ignored.}, LMITI {A consequence of this arrangement is that when one is typing Lisp forms at a Lisp listener or the
Debugger, and the current package (the value of the system variable @lt<package>) is a C program package, explicit
package prefixes are necessary to access the built-in Lisp functions, as they are all kept in @lt<GLOBAL:>. This takes some
getting used to. To save typing, notice that the nickname @lt<GL:> is available for @lt<GLOBAL:>. So, for instance, if
the current package is a C program package -- say, @lt<CFOOD:> -- and you wish to inspect one of the program's data
structures -- say the value of @lt<frobarray> -- you can type
@Display{@st<(gl:inspect frobarray)>}
However, to do the same thing when the current package is @lt<USER:> (or some other non-C package), type
@Display{@st<(inspect cfood:frobarray)>}})@Comment(End of @Case)
Of course, what usually happens if one omits a needed package prefix is an undefined-function or unbound-symbol
error, which can easily be fixed either with one of the fancy Debugger options or by simply hitting @st<[Abort]> and
retyping the form.
See p. @Ref(ProgramConstructionPage) to see how to create a C program package.
C identifiers may also contain package prefixes@Index(package, prefix)@Index(example of, package prefix), delimited
with the "@st<$>" character (which is otherwise unused in C). So, for instance, the C statement "@st<TV$BEEP();>", equivalent to
the Lisp "@st<(tv:beep)>", would beep the console beeper (and/or flash the screen).
@Section(Data structures)@Tag(DataStructuresPage = Page)@Index(data structures)@Index(C data structures)
To interface C and Lisp code, or just to understand some of the performance issues inherent in ZETA-C, it is very
handy to know how ZETA-C implements C data structures in terms of those provided by Lisp.
@SubSection(Numbers)@Tag(NumbersPage = Page)@Index(numbers)@Index(integer types)@Index(character types)
ZETA-C does not make any distinction between types @lt<int> and @lt<long>, or between @lt<unsigned int> and @lt<unsigned long>.
These are all implemented with the numeric type most natural to the Lisp Machine, namely arbitrary-precision
integers.@Index(arbitrary-precision integer)@Index(integer, arbitrary-precision)@Index(precision, integer)@Index(word
length)@Index(representation, integer) We do not restrict the widths of these types to, say, 32 bits, because doing so
would make ZETA-C object code decidedly @i<slower>.@Index(performance issues)
The treatment of unsigned arithmetic@Index(integer, unsigned) in ZETA-C was problematic. What should be the value,
for instance, of @lt<(unsigned)-1>? Since the "word length" of arbitrary-precision integers is effectively infinite, there is no
particular positive integer that it makes sense to use in this case. What we do is this@Foot{I am indebted to John Rose
of Thinking Machines for this solution.}: we use the negative fixnum @lt<-1> as a representation of the unsigned value
@lt<@Infinity-1>, and so on. The only operation that's actually affected by this interpretation is that of comparison: we
simply arrange that any unsigned value implemented as a negative integer is treated as @i<greater> than any value
implemented as a positive integer.
The types @lt<short>@Index(integer, short) (equivalent to @lt<signed short>) and @lt<unsigned short> are truncated to 16 bits.
This truncation is inefficient on the Lisp Machine, and so for optimum performance@Index(performance issues) we do
not recommend the use of the short types for variables or structure components; arrays of them work better (see below).
Similarly for @lt<char>@Index(character) (equivalent to @lt<unsigned> @lt<char>) and @lt<signed> @lt<char>, which are truncated to 8 bits.
The @lt<char> type is unsigned by default not only because of this efficiency difference, but also because C requires that all
characters in the host character set be represented by positive values of @lt<char> variables, and the Lisp Machine character
set defines several control characters above 0200 octal.
Variables of all integer types are stored so that their actual values are equal to their "apparent" values (as seen from
Lisp). This means that any value greater than @Case(Class, Symbolics "2@+<31>-1", LMITI "2@+<24>-1") will require a
bignum to represent it.
@Tag(FastFloatPage = Page)
@Case(Class, Symbolics {The @lt<float> type@Index(floating-point precision)@Index(precision, floating-point)
@Index(representation, floating-point) is implemented with single-precision floating-point numbers, which have a 24-bit
mantissa and an 8-bit exponent; @lt<double> uses double-precision (53-bit mantissa, 11-bit exponent). Double-precision
arithmetic is rather less efficient than single-precision -- not just because the computation takes longer, but also because
double-floats are consed in the heap rather than fitting in a pointer, as single-floats do -- so ZETA-C provides an option
to suppress the automatic conversion of @lt<float>s to @lt<double>s before performing any arithmetic. Just put the line
@Display{@st<#define ZETA_C_SUPPRESS_AUTO_FLOAT_TO_DOUBLE>} at the beginning of your program.}, LMITI {The @lt<float>
type@Index(floating-point precision)@Index(precision, floating-point)@Index(representation, floating-point) is
implemented with small-floats, which have an 18-bit mantissa and a 7-bit exponent; @lt<double> uses single-floats (31-bit
mantissa, 11-bit exponent). Single-float arithmetic is rather less efficient than with small-floats, because single-floats
are consed in the heap rather than fitting in a pointer, as small-floats do; so ZETA-C provides an option to suppress the
automatic conversion of @lt<float>s (small-) to @lt<double>s (single-) before performing any arithmetic. Just put the line
@Display{@st<#define ZETA_C_SUPPRESS_AUTO_FLOAT_TO_DOUBLE>} at the beginning of your program.})
@SubSection(Pointers)@Tag(PointersPage = Page)
The choice of representations for pointers@Index(pointer representation)@Index(representation, pointer) is constrained on
the one hand by the ways that pointers can be used in C programs, and on the other by the design goal that ZETA-C be
a @i<safe> implementation. For instance, on the one hand, it is necessary that pointer arithmetic be possible: that one be
able to create a pointer to an element of an array, and then add an integer to that to get a pointer to a different
element; on the other hand, if in doing this one creates a pointer to a non-existent element, an attempt to assign or
reference through that pointer must be trapped.
To satisfy these constraints, it is clearly insufficient that a pointer be, as in C, merely an address. The system must
keep track of the array-bounds information that goes with the address. We accomplish this by representing a pointer as
a pair <@i<array>, @i<index>>, where the @i<array> is a Lisp array object representing a C array or structure (see the next section),
and the @i<index> specifies an element thereof. How the pointer is actually represented depends on where it is stored.
Pointer variables are implemented as pairs of Lisp variables, named @i<ptr@lt<.array>> and @i<ptr@lt<.index>>,@Index(@st<.array> and
@st<.index> variables) where @i<ptr> is the name of the C pointer variable. Pointers as array or structure elements take up two
consecutive elements of the Lisp array; the first is @i<array> and the second is @i<index>. These implementation matters are of
course entirely invisible to C programs, provided it is not assumed that a pointer and an @lt<int> are the same size.
When a pointer is passed to a function, it is passed as two consecutive arguments@Index(@w<arguments, pointer>); just
like a pointer variable, a pointer parameter in a function definition turns into a pair of parameters, which appear
consecutively in the lambda-list. A pointer is returned from a function as two values, the array and
index@Index(@w<return value, pointer>). Again, this is completely invisible to C code, provided all functions that
accept and return pointers are correctly declared.
In order to provide for the creation of pointers by taking the address (unary @lt<&>) of scalar variables (as opposed to
elements of aggregates), ZETA-C creates "address arrays".@Index(address array)@Index(pointer to variable) The address
array of variable @i<var> is kept in a variable @i<var@lt<.address>>. (Address arrays are always created for external and static
variables, but only if needed for automatic variables.) So, a pointer to @i<var> is the pair <@i<var@lt<.address>>, @st<0>>.
An example should make all of this clear@st<.> The C function@Index(example of, pointer implementation)
@Begin(Display)
@st<gubbish(ipp)
int **ipp;
{
static int i;
int *ip;
ip = &i;
*ipp = ip;
frobozz(ip);
return ip;
}>
@End(Display)
would be implemented in Lisp something like this (much irrelevant detail, notably the initialization of @st<i> and
@st<i.address>, has been omitted):
@Begin(Display)
@st<(defun gubbish (ipp.array ipp.index)
(let ((ip.array nil) (ip.index 0))
(setq ip.array i.address)
(setq ip.index 0)
(setf (aref ipp.array ipp.index) ip.array)
(setf (aref ipp.array (1+ ipp.index)) ip.index)
(frobozz ip.array ip.index)
(values ip.array ip.index)))>
@End(Display)
Some obvious consequences of these decisions: to increment a pointer we increment its index part; two pointers are equal
iff their array parts are @lt<eq> and their index parts are equal; the difference of two pointers is the difference of their index
parts (assuming they point into the same array; an error occurs otherwise), scaled down if necessary by the size of the
objects they point to.
Special cases: the null pointer (of any type) is represented as having array part @lt<nil> and index part @lt<0>. Any attempt to
dereference it will of course cause an error to be signalled, since @lt<nil> is not an array. A
pointer-to-function@Index(representation, function pointer) is the exception to @i<all> of this -- it's not a pair, it's just a
single value: the symbol that names the function. (A null function pointer is the symbol
@lt<zeta-c:null-function-pointer>@Index(@st<zeta-c:null-function-pointer>)@Index(@st<null-function-pointer>).)
@SubSection(Arrays, structures, and unions)@Tag(AggregatesPage = Page)@Index(aggregates)@Index(arrays)
@Index(structures)@Index(unions)@Index(packed_struct)
C arrays are Lisp arrays.@Index(representation, array) Since C and Lisp use the same bounds convention -- an array of
size @i<n> contains elements numbered 0 through @i<n>-1, inclusive -- no subscript translation is necessary.
The representation chosen for an array depends on the type of the elements to be stored in it. Arrays of @lt<int>, @lt<long>,
@lt<unsigned int>, @lt<unsigned long>, any kind of pointer, or of structures or unions are implemented with Lisp array type
@lt<art-q>. Arrays of @lt<short> and @lt<unsigned short> are implemented as @lt<art-16b> arrays; arrays of @lt<char> and @lt<signed char> are
implemented as @lt<art-8b> arrays. There is no extra cost associated with using these to hold unsigned values, since that is
the interpretation the microcode imposes, but @lt<signed char>s and (@lt<signed>) @lt<short>s must be sign-extended after being loaded
from an array; this renders the use of the signed types slightly slower.
Lisp Machines are fundamentally word-addressed machines. However, in order to accomodate programs that take, for
instance, a pointer to @lt<short>, cast it to a pointer to @lt<char>, store two characters at successive locations through that
pointer, and then expect both characters to have fit in a single @lt<short> -- a nonportable but all too common practice --
ZETA-C simulates byte-addressing by means of displaced arrays. To continue this example, consider a pointer, of type
"pointer to @lt<short>", which at runtime points to element @i<i> of an array @i<a16b> of type @lt<art-16b>. Casting this pointer to a
@lt<char>-pointer causes the creation (at runtime) of an @lt<art-8b> array @i<a8b>, whose length is twice that of @i<a16b> and whose
contents are displaced to overlay those of @i<a16b>; the result of the cast is a pointer to element 2@i<i> of @i<a8b>. If one stores
characters through successive values of this pointer (i.e., to elements 2@i<i>, 2@i<i>+1, ... of @i<a8b>) and then looks at the result
through the original @lt<short>-pointer, the characters will be seen to have been stored two-per-halfword starting at the
low-order end of the halfword.
@Case(Class, Symbolics {Types stored in @lt<art-q> arrays can take part in this pointer casting also. However, there is a
slight complication, since @lt<art-q> arrays can hold non-numeric objects, and it would not make sense to load or store bytes
or halfwords out of or into a Lisp object pointer. Fortunately, the 36xx microcode takes care of this case very nicely. If
you try, for instance, to load a byte out of a word that contains the array part of a ZETA-C pointer, you will get an
error to the effect that @st<The AR-1 microcode encountered an ARRAY-WORD that was not a fixnum>. One way to do
this is (you can try this in a C listener):
@Begin(Display)
@st<char *cp, *cparray[1] = { "Hello there" };
cp = (char *)cparray;
*cp;>
@End(Display)}, LMITI {While this pointer casting works for @lt<char> and @lt<short> types, it doesn't work with @lt<int> or other
types stored in @lt<art-q> arrays. The problem is that since @lt<art-q> arrays can hold any Lisp object, they must be stored in
"boxed" or tagged form, wherein the high-order 7 bits of each word hold a type code. An @lt<art-8b> displaced onto an
@lt<art-q> would allow the inadvertent modification of those bits, which could easily crash the Lisp garbage collector. Also,
the high-order byte of an integer would appear to contain an incorrect value. So if you cast an @lt<int> pointer to a @lt<char>
pointer, the two will @i<not> point to the same storage (although if you cast the result back to an @lt<int> pointer, you will get
the same thing you started with).})
Structures are represented as @lt<art-q> arrays@Index(representation, structure); the elements of the structure occupy
successive elements of the array. ZETA-C, like traditional C implementations, uses a "flat" representation for nested
aggregates, such that the storage occupied by an inner aggregate is part of that occupied by the outer one. So, for
instance, the declaration@Index(example of, nested aggregates)
@Begin(Display)
@st<struct foo {
int foovals[3];
struct foo *nextfoo;
} fooarray[20];>
@End(Display)
allocates a single @lt<art-q> array of length 100 (remember, a pointer takes up two cells). Furthermore, arrays of @lt<short>s or
@lt<char>s within a struct will be implemented using the same displaced-array machinery that handles pointer casts; so
the declaration@Index(example of, struct implementation)
@Begin(Display)
@st<struct bar {
int a;
struct foo *foop;
char name[20];
} abar;>
@End(Display)
allocates an @lt<art-q> of length 8: 1 for @lt<a>, plus 2 for @lt<foop>, plus 5 for @lt<name>. It also creates and caches (see below) an
@lt<art-8b> of length 32, @Case(Class, Symbolics "displaced onto the @lt<art-q,> ")so that @lt<name> is accessible as elements 12
through 21 thereof. @Case(Class, LMITI {Thus every struct has both a "boxed" or @lt<art-q> part, and an "unboxed" part
consisting of an @lt<art-16b> and an @lt<art-8b> that share storage.})
Normally, ZETA-C uses an "unpacked" representation for structures, in the sense that all scalar elements of numeric
type are allocated an entire word each. (Arrays within structs are always packed, as we have just discussed.) So, for
instance, the declaration
@Begin(Display)
@st<struct zot {
unsigned short z1;
char z2, z3;
struct foo *foop;
} azot;>
@End(Display)
creates an @lt<art-q> of length 5, not 3 as one might imagine (expecting @st<z1>, @st<z2>, and @st<z3> all to fit in the first cell). This is
done for performance reasons: we don't want waste a lot of time switching representations to load structure elements. If
for some reason it's important to your application that structs be "packed" (so that @st<z1>, @st<z2>, and @st<z3> all @i<would> fit in the
first cell and the total length @i<would> be 3), use the keyword @lt<packed_struct>@Index(representation, packed structure) in
place of @lt<struct> for declaring all structs that need to be packed. (@lt<packed_struct>s can be nested inside @lt<struct>s and
conversely, with complete freedom, though we can't imagine why this would be useful.)
The implementation of unions is very much like that of structures@Index(representation, union). A union of aggregates
is an @lt<art-q> array whose size is the size of the largest aggregate in the union, and each of whose elements can be
referenced as the corresponding element of any of the aggregates. For example, given the declaration
@Begin(Display)@Index(example of, union implementation)
@st<union point {
struct rect_pt {
float x, y;
} rp;
struct polar_pt {
float r, theta;
} pp;
} pnt;>
@End(Display)
@st<pnt> will be an array of length 2; @st<pnt.rp.x> and @st<pnt.pp.r> both refer to element 0 of this array; @st<pnt.rp.y> and
@st<pnt.pp.theta> both refer to element 1.
When ZETA-C allocates a Lisp array to represent a C aggregate, it sets it up with a
named-structure-symbol@Index(named structure symbol) and other information in the array-leader so the Lisp printer
will print it recognizably; e.g., the declaration @DisplayOne{@st<char buffer[256];>} creates an array that will print as
@st<@w<#{(char [256]) BUFFER}>>. Slots are also allocated in the array-leader to cache the displaced-arrays created by
pointer-casting. Specifically, here is how ZETA-C uses each element of the array-leader:@Index(@w<leader slots,
reserved>)@Index(array leader)
@Begin(Text, Indent -6)
0:@\Normally, a list (@i<name type env>), where @i<name> is the name with which the aggregate was declared (or @lt<nil> if it was
dynamically allocated), and @i<type> and @i<env> are the ZETA-C internal representations for the type of the aggregate and the
contents of the environment in which it was declared, respectively. However, if the named-structure-symbol is
@lt<zeta-c:cast-array>, element 0 contains the original array that the cast-array is displaced to; element 0 of @i<that> array will
contain this descriptor-list.
1:@\The named-structure-symbol. For a structure or union whose type was declared with a tag, the tag is used as the
named-structure-symbol. Otherwise, there appears one of the symbols @lt<zeta-c:array>, @lt<zeta-c:struct>, @lt<zeta-c:union>,
@lt<zeta-c:value-cell> (used for address arrays of variables), @lt<zeta-c:cast>-@lt<array> (used for arrays, created by casting, that
are displaced onto other arrays, as discussed above), or @lt<zeta-c:restarg> (used internally similarly to @lt<&rest> arguments
in Lisp; see page @Ref(varargsPage)).
2:@\Reserved for ZETA-C internal use.
3:@\When an @lt<art-q> cast-array for this aggregate is created, it is cached here; otherwise @lt<nil>.
4:@\Cache for the @lt<art-16b> version.
5:@\Cache for the @lt<art-8b> version.
@End(Text)
Note that one of the last three slots will always contain the array itself, since it has to be in one of the three
representations.
@SubSection(Strings)@Index(strings)
String constants in C code are written, of course, according to the standard C conventions@Index(representation, string).
However, if you look at a string in the C listener, you will see that it doesn't look quite the same when printed out as it
does in your code. The special @lt<\>-sequences will have been converted to the appropriate single characters, and a @lt<NUL>
character (which displays as a raised dot, @Dot) will have been appended. So, for instance:
@Begin(Display)
What you write in your C code:
@st<@NoTCT<"Hello, world!\n">>
What is printed:
@st<@NoTCT<"Hello, world
@Dot">>
@End(Display)
Note that if you pass a Lisp string to a C function, you must be sure to have appended the @lt<NUL> yourself. (If you don't,
the C function will get an array-bounds error when it scans off the end of the string, since this is the only way C code
has of knowing where a string ends.) Conversely, for Lisp code to make proper use of a C string, the @lt<NUL> must be
stripped and the character-pointer converted to a Lisp string. The following functions exist for this purpose.
@FunctionDoc(Name "@lt<zeta-c:string-to-C>@Index(@st<zeta-c:string-to-C>)@Index(@st<string-to-C>)@Index(converting
strings between C and Lisp)", Arglist "@it<str>", Doc "Given a Lisp string, returns a C character pointer (as
two values: array and index) that points to the beginning of a copy of the string. Appends a NUL to the copy.")
@FunctionDoc(Name "@lt<zeta-c:string-to-lisp>@Index(@st<zeta-c:string-to-lisp>)@Index(@st<string-to-lisp>)", arglist
"@it<str.array str.index> &optional@it< case>", Doc "Given a C character pointer <@it<str.array>, @it<str.index>>, returns a copy of
its contents as a Lisp string. @it<case>, if supplied, may be @lt<:upcase> or @lt<:downcase>, requesting a forced conversion to upper
or lower case respectively.")
The Lisp Machine's character set@Index(character set) is unusual in that the first 128 characters (0 through 177 octal)
are all printing characters; the control characters are octal 200 through 237. See your Lisp manual for more details. As
long as you use the predefined escape sequences @lt<\r>, @lt<\n>, @lt<\b>, @lt<\t>, @lt<\f>, and @lt<\v>, this will not make any difference to your
programs, unless you are using the high-order bits of characters for some special purpose. The sequences @lt<\r> and @lt<\n> both
name the @st<[Return]> character, octal 215; @lt<\b> is @st<[Overstrike]>, octal 208; @lt<\t> is @st<[Tab]>, octal 209; and @lt<\f> and @lt<\v> are both
@st<[Page]>, octal 214.
@Comment(More in ANSI spec?)
@Section(Debugging hints)@Index(debugging)
This section contains explanations of the error messages@Index(error messages) issued by ZETA-C, along with some
material that will help you interpret them and find the problem efficiently.
@SubSection(Syntax errors)@Index(errors, syntax)
When the ZETA-C parser encounters a syntax error, it displays three lines of context with a marker at the point where
the error was detected, like this:
@Begin(Display)
@st<<< Error in reading >>
Error while parsing line 58 of ED-BUFFER: CTEST.C#> GYRO.ZETA-C; ASTARTE::
Expression syntax
Error happened somewhere before the point indicated by> @st<"->HERE<-" in:
{
*junkp += c
} ->HERE<- >
@End(Display)
In this case, as you see, the error was a missing semicolon. Here are the error messages the parser can emit whose
interpretations may not be obvious:
@ErrorDoc(Message "@st<Expression syntax>", Doc "An error was found at the expression level. Look for a missing semicolon,
unbalanced parentheses, or the like.")
@ErrorDoc(Message "@st<External definition syntax>", Doc "An error was found in an external variable declaration or
function definition. Look for a mistyped type name, a missing semicolon or comma, or mismatched delimiters.")
@ErrorDoc(Message "@st<Statement syntax>", Doc "An error was found at the statement level. Look for an incorrectly written
@lt<if>, @lt<for>, @lt<while>, etc.")
When a syntax error occurs, the parser will attempt to recover and continue. In the case of something simple, like a
missing semicolon, this will usually work, but many errors will throw the parser off completely. When this happens,
there are likely to be more syntax errors; just fix the first error and the rest will probably go away by themselves.
@Subsection(Compilation errors)@Index(errors, compilation)
When an error is encountered in semantic analysis or "code generation", a message is issued which displays the
offending structures in ZETA-C's internal representations. So, clearly, in order to be able to fully understand such a
message, one should know how to interpret those representations.@Foot{This is not a deficiency on ZETA-C's part
vis-a-vis other compilers, since the latter don't have such detailed error messages in the first place.} There are two
important representational systems: that used for the parsed input expressions, and that used to describe the types of
values.
@Paragraph(Representation of expressions)@Index(representation, expression)@Index(expressions)
Expressions (and statements) are represented quite straightforwardly as Lisp forms; for instance, the C statement
@Display{@st<a = b + 3*foo((c == 0) ? d : e) + f[g++];>}
is represented as the Lisp form
@Display{@st<(= A (+ B (+ (* 3 (FOO (|?:| (== C 0) D E))) ([] F (X++ G)))))>}
From this example, several points should be visible immediately:
@Begin(Itemize)
Operators have names which are identical to, or at least strongly suggestive of, their C notations.
Calls to user functions appear just as they do in Lisp.
Variable names are converted to upper case (see p. @Ref(IdentifiersPage)).@Comment{This will change!}
@End(Itemize)
@Begin(Figure)
@Begin(Comment) I don't want to lose the old font information...
@Begin(Description, fill 0, indent -1 in)
@lt<+>@\Addition (one argument may be a pointer).
@lt<->@\Subtraction (one or both arguments may be pointers).
@lt<*>@\With one argument, pointer dereferencing; with two, multiplication.
@lt</> (@lt<//>)@Foot{Slashified representations are given in parentheses when appropriate.}@\Division.
@lt<%>@\Remainder.
@lt<<<>@\Shift left.
@lt<>>>@\Shift right.
@lt<&>@\Bitwise AND.
@lt<|> (@lt</|>)@\Bitwise OR.
@lt<^>@\Bitwise XOR.
~@\Bitwise NOT (one argument).
@Hinge@Blankspace(1 line)
@lt<==>@\Equality comparison.
@lt<!=>@\Inequality comparison.
@lt<<>@\Less-than comparison.
@lt<>>@\Greater-than comparison.
@lt<<=>@\Less-than-or-equal comparison.
@lt<>=>@\Greater-than-or-equal comparison.
@lt<!>@\Logical NOT.
@lt<&&>@\Logical AND.
@lt<|| >(@lt</|/|>)@\Logical OR.
@Hinge@Blankspace(1 line)
@lt<=>@\Assignment.
@lt<++x>@\Preincrement.
@lt<x++>@\Postincrement.
@lt<@NoTCT<--x>>@\Predecrement.
@lt<@NoTCT<x-->>@\Postdecrement.
@lt<+=>@\Add and assign (first argument may be a pointer).
@lt<-=>@\Subtract and assign (first argument may be a pointer).
@lt<*=>@\Multiply and assign.
@lt</=> (@lt<//=>)@\Divide and assign.
@lt<%=>@\Take remainder and assign.
@lt<<<=>@\Shift left and assign.
@lt<>>=>@\Shift right and assign.
@lt<&=>@\Bitwise AND and assign.
@lt<|=> (@lt</|=>)@\Bitwise OR and assign.
@lt<^=>@\Bitwise XOR and assign.
@Hinge@Blankspace(1 line)
@lt<[]>@\Array reference.
@lt<.> (@lt</.>)@\Structure element reference.
@lt<@NoTCT{->}>@\Indirect structure element reference.
@Hinge@Blankspace(1 line)
@lt<progn+>@\The comma operator (which acts like the Lisp @lt<progn>).
@lt<?:> (@lt<?/:>)@\The expression conditional.
@Hinge@Blankspace(1 line)
@lt<if>@\The statement conditional.
@lt<block+>@\Encloses statements in a block (see text).
@lt<goto>@\Go to the specified label.
@lt<label+>@\The first argument is a label; the second is a statement.
@lt<while>@\@st<(while @i<looptest> @i<body>)>: iterate.
@lt<do>@\@st<(do @i<body> @i<looptest>)>: iterate, doing @i<body> at least once.
@lt<for>@\@st<(for @i<init> @i<looptest> @i<increment> @i<body>)>: iterate with syntactic sugar.
@lt<break>@\Skip to the end of this @lt<while>, @lt<do>, @lt<for>, or @lt<switch>.
@lt<continue>@\Skip to the next iteration of this @lt<while>, @lt<do>, or @lt<for>.
@lt<return>@\Return from this function (argument, if any, is value to return).
@lt<switch>@\@st<(switch @i<exp> @i<body>)>: go to the @lt<case> in @i<body> matching @i<exp>.
@lt<case>@\@st<(case @i<value>)>: meaningful only in @lt<switch> bodies.
@Hinge@Blankspace(1 line)
@lt<cast+>@\@st<(cast>+@st< @i<type> @i<expression>)>: cast the type of @i<expression> to @i<type>.
@lt<sizeof>@\The size of a type or instance.
@lt<#lisp> (@lt</#lisp>)@\Encloses a group of Lisp forms introduced with @lt<#lisp> (see p. @Ref(#lispPage)).
@lt<salloc>@\Allocate a structure or union.
@lt<aalloc>@\Allocate an array.
@Hinge@Blankspace(1 line)
@lt<defunc+>@\Function definition (see text for explanation).
@lt<decl+>@\External declaration.
@End(Description)
The following two symbols can appear in the representations of declarations, but not in expressions:
@Begin(Description, fill 0, indent -1 in)
@lt<fcn+>@\Indicates a function declaration.
@lt<list+>@\Encloses a list (written with braces in the source) of initializer values.
@End(Description)
@End(Comment)
@Begin(Description, fill n, spread 0 lines, indent -.75 in, font small)@Comment{"fill 0" used to make blank lines
unnecessary, sigh...}
+@\Addition (one argument may be a pointer).
-@\Subtraction (one or both arguments may be pointers).
*@\With one argument, pointer dereferencing; with two, multiplication.
/ (//)@Foot{Slashified representations are given in parentheses when appropriate.}@\Division.
%@\Remainder.
<<@\Shift left.
>>@\Shift right.
&@\Bitwise AND.
| (/|)@\Bitwise OR.
^@\Bitwise XOR.
~@\Bitwise NOT (one argument).
@Blankspace(0.5 line)
==@\Equality comparison.
!=@\Inequality comparison.
<@\Less-than comparison.
>@\Greater-than comparison.
<=@\Less-than-or-equal comparison.
>=@\Greater-than-or-equal comparison.
!@\Logical NOT.
&&@\Logical AND.
|| (/|/|)@\Logical OR.
@Blankspace(0.5 line)
=@\Assignment.
++x@\Preincrement.
x++@\Postincrement.
--x@\Predecrement.
x--@\Postdecrement.
+=@\Add and assign (first argument may be a pointer).
-=@\Subtract and assign (first argument may be a pointer).
*=@\Multiply and assign.
/= (//=)@\Divide and assign.
%=@\Take remainder and assign.
<<=@\Shift left and assign.
>>=@\Shift right and assign.
&=@\Bitwise AND and assign.
|= (/|=)@\Bitwise OR and assign.
^=@\Bitwise XOR and assign.
@Blankspace(0.5 line)
[]@\Array reference.
. (/.)@\Structure element reference.
->@\Indirect structure element reference.
@Blankspace(0.5 line)
progn+@\The comma operator (which acts like the Lisp progn).
?: (?/:)@\The expression conditional.
@Blankspace(0.5 line)
if@\The statement conditional.
block+@\Encloses statements in a block (see text).
goto@\Go to the specified label.
label+@\The first argument is a label; the second is a statement.
while@\(while @i<looptest> @i<body>): iterate.
do@\(do @i<body> @i<looptest>): iterate, doing @i<body> at least once.
for@\(for @i<init> @i<looptest> @i<increment> @i<body>): iterate with syntactic sugar.
break@\Skip to the end of this while, do, for, or switch.
continue@\Skip to the next iteration of this while, do, or for.
return@\Return from this function (argument, if any, is value to return).
switch@\(switch @i<exp> @i<body>): go to the case in @i<body> matching @i<exp>.
case@\(case @i<value>): meaningful only in switch bodies.
@Blankspace(0.5 line)
cast+@\(cast+ @i<type> @i<expression>): cast the type of @i<expression> to @i<type>.
sizeof@\The size of a type or instance.
#lisp (/#lisp)@\Encloses a group of Lisp forms introduced with #lisp (see p. @Ref(LispInclPage)).
@Blankspace(0.5 line)
defunc+@\Function definition (see text for explanation).
decl+@\External declaration.
@Text{The following two symbols can appear in the representations of declarations, but not in expressions:}
fcn+@\Indicates a function declaration.
list+@\Encloses a list (written with braces in the source) of initializer values.
@End(Description)
@Caption{ZETA-C primitives.}@Tag(PrimitivesFigure = Figure)@~
@End(Figure)
A complete list of the ZETA-C primitives appears in Figure @Ref(PrimitivesFigure). These are all symbols in package
@lt<C:>; they name macros which invoke the ZETA-C analysis and translation apparatus. Some of the names end in plus
signs to avoid conflict with legal C identifiers (those which are alphabetic, but do not end in "+", are ZETA-C reserved
words).
@Begin(Group)
The syntax of two of these primitive macros deserves examples. First, let's look at function definition. Here
is a sample C function:@Index(example of, function representation)
@Begin(Display)
@st<char *
foo(x, y)
int x, y;
{
int quux;
bar(x + y);
}>
@End(Display)
Here is its ZETA-C internal representation:
@Begin(Display)
@st<(DEFUNC+ ((CHAR) (* (FCN+ FOO X Y))) (((INT) X Y)) (BLOCK+ (((INT) QUUX)) (BAR (+ X Y))))>
@End(Display)
@Hinge
And here are some sample declarations:@Index(example of, declaration representation)
@Begin(Display)
@st<char foo(), *bar, *baz[47];
struct thing {>
@st<int who, *why;>
@st<struct thing *this, *that;>
@st<} thingarray[128];>
@End(Display)
And here are their internal representations:
@Begin(Display)
@st<(DECL+ (CHAR) (FCN+ FOO) (* BAR) (* ([] BAZ 47)))
(DECL+ ((STRUCT THING ((INT) WHO (* WHY)) (((STRUCT THING)) (* THIS) (* THAT)))) ([] THINGARRAY 128.))>
@End(Display)
@End(Group)
Note some features of this representation:
@Itemize{
The name of the function is embedded inside a type declarator (see below).
The second subform of the @lt<defunc+> form is a list of parameter declarations.
The third subform is the body, and is always a @lt<block+> form.
The first subform of a @lt<block+> form is a list of local variable declarations.
}
@Paragraph(Representation of types)@Index(representation, type)
ZETA-C represents types internally as list structure. Figure @Ref(TypesFigure) shows the type description language.
@Begin(Figure)
@Begin(Description, fill n, spread 0 lines, indent -1 inch, font small)
:char@\A character.
:signed-char@\A signed character.
:short@\A short (16-bit signed).
:unsigned-short@\An unsigned short.
:int@\Used for an int or long: an arbitrary-precision signed integer.
:unsigned@\Used for an unsigned int or unsigned long: an arbitrary-precision unsigned integer.
:float@\A single-precision floating point number.
:double@\A double-precision floating-point number.
:zero@\The constant 0.
:void@\The void type.
:lispval@\A lisp value (can be assigned or passed to and from functions, but nothing else).
:boolean@\The type of an expression evaluated for control, not value.
(:pointer @i<type>)@\A pointer to type @i<type>.
(:pointer @i<type> :null)@\A null pointer to type @i<type>.
(:array @i<type> @i<length>)@\An array of @i<length> elements, each of type @i<type>. @i<length> can be NIL, meaning the length is not known.
(:function @i<type>)@\A function returning type @i<type>.
(:struct . @i<tag-or-elts>)@\A structure. If @i<tag-or-elts> is a symbol, it's a tag; if a list, it's an alist associating element names
with types and accessing information.
(:union . @i<tag-or-elts>)@\A union; like :struct.
(:enum . @i<tag-or-elts>)@\An enumeration type; like :struct.
@End(Description)
@Caption{ZETA-C type descriptions.}@Tag(TypesFigure = Figure)
@End(Figure)
@Paragraph(Compilation error reference)@Index(errors, compilation)
@ErrorDoc(Message "@st<Assignments to structures are not allowed. If you would like to permit them (for
UNIX> @st<compatibility), setq zeta-c:*firstclass-structures* to T.>@Index(struct, assignment)@Index(assignment of
struct)@Index(firstclass structures)@Index(@st<zeta-c:*firstclass-structures*>)@Index(@st<*firstclass-structures*>)", Doc
"See p. @Ref(FirstclassStructuresPage).")
@ErrorDoc(Message "@st<Attempt to call @it<exp> of type @it<type> as a function>@Index(function call)", Doc "Chances are,
either you have a variable with the same name as a function, or you wrote some expression like @lt<(*ftab[ifunc])()>
incorrectly, or you declared something incorrectly.")
@ErrorDoc(Message "@st<Attempt to use expression @it<exp>, of type @it<type>, as a predicate>@Index(predicate)", Doc
"Arrays, structures, and unions may not be used as predicates in conditionals, as in, @i<e.g.>, @lt<if (frob)> ... where @lt<frob> is a
structure.")
@ErrorDoc(Message "@st<BREAK not inside WHILE, FOR, DO, or SWITCH>@Index(@st<break> statement)", Doc "A @lt<break>
statement may only appear lexically inside one of these constructs.")
@ErrorDoc(Message "@st<CASE not inside SWITCH>@Index(@st<case> statement)", Doc "A @lt<case> statement may only appear in the
body of a @lt<switch> statement.")
@ErrorDoc(Message "@st<CONTINUE not inside WHILE, FOR, or DO>@Index(@st<continue> statement)", Doc "A @lt<continue>
statement may only appear lexically inside one of these constructs.")