-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathatlast.html
6867 lines (6528 loc) · 172 KB
/
atlast.html
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
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>Atlast</title>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<meta name="description" content="Atlast" />
<meta name="author" content="John Walker" />
<meta name="keywords" content="Atlast, FORTH, embedded, scripting, threaded, language" />
<meta name="robots" content="index" />
<style type="text/css">
<!--
a:link, a:visited {
background-color: rgb(100%, 100%, 100%);
color: rgb(0%, 0%, 80%);
text-decoration: none;
}
a:hover {
background-color: rgb(30%, 30%, 100%);
color: rgb(100%, 100%, 100%);
}
a:active {
background-color: rgb(30%, 30%, 100%);
color: rgb(100%, 0%, 0%)
}
a.i:link, a.i:visited, a.i:hover {
background-color: inherit;
color: inherit;
text-decoration: none;
}
body {
background-color: #FFFFFF;
color: #000000;
margin-left: 15%;
margin-right: 10%
}
div.primitives {
margin-left: -10%;
margin-right: -5%;
}
div.wbox {
width: 80%;
margin-left: auto;
margin-right: auto;
border: 1px solid black;
padding: 0.3em;
font-size: larger;
color: inherit;
background-color: #E0E0E0;
}
dl.tj dd {
text-align: justify;
}
dl.tj dt {
margin-top: 0.5ex;
font-family: monospace;
font-weight: bold;
}
h1.title {
text-align: center;
font-size: 36pt;
font-weight: normal;
margin-bottom: 0pt;
}
h2.subtitle {
border-top: 1px solid black;
border-bottom: 1px solid black;
text-align: center;
font-family: sans-serif;
font-size: 18pt;
font-weight: normal;
font-style: italic;
margin-top: 0pt;
}
h3.author {
font-size: larger;
text-align: center;
font-weight: normal;
}
h3.progname {
font-size: 200%;
font-family: monospace;
text-align: center;
border: 1px solid black;
}
p {
text-align: justify;
}
p.abstract {
margin-left: 2em;
margin-right: 2em;
font-style: italic;
font-size: larger;
}
p.hang {
margin-left: 3em;
text-indent: -3em;
margin-top: 1ex;
}
pre.c {
margin-left: 2em;
font-weight: bold;
}
pre.c i {
font-family: serif;
font-style: italic;
font-weight: normal;
}
span.a { /* Atlast logo */
font-variant: small-caps;
border-bottom: double black;
}
table.primitives td.c1 i {
font-style: italic;
font-family: serif;
font-weight: normal;
font-size: 80%;
}
table.benchmark {
color: inherit;
background-color: #E0E0E0;
margin-left: auto;
margin-right: auto;
}
table.benchmark td, th {
padding-left: 8px;
padding-right: 8px;
}
table.benchmark td.n {
text-align: right;
}
table.primitives {
margin-left: auto;
margin-right: auto;
}
table.primitives td {
vertical-align: top;
}
table.primitives td.c1 {
font-family: monospace;
font-weight: bold;
font-size: 180%;
}
table.primitives td.c1 i {
font-style: italic;
font-family: serif;
font-weight: normal;
font-size: 80%;
}
table.primitives td.c2 {
text-align: right;
}
table.primitives td.c5 {
text-align: justify;
}
table.primitives td.c6 {
font-family: monospace;
font-weight: bold;
}
tt {
font-weight: bold;
}
.ctr {
text-align: center;
}
.rgt {
text-align: right;
}
-->
</style>
</head>
<body>
<h1 class="title">ATLAST</h1>
<h2 class="subtitle">Autodesk
Threaded Language Application System Toolkit</h2>
<p class="abstract">
Open, programmable products are superior to and
displace even the best designed closed applications. A threaded
language, implemented in a single portable C file, allows virtually
any program, existing or newly developed, to be made programmable,
extensible, and open to user enhancement.
</p>
<h3 class="author">
John Walker<br />
March 9th, 1990
</h3>
<p>
You'd think we'd have learned by now. It was Autodesk's
strategy for AutoCAD<sup>®</sup>
from inception that it should be an open, extensible system.
We waged a five-year uphill battle to bring such a heretical idea to
eventual triumph. Today, virtually every industry analyst agrees
that AutoCAD's open architecture was, more than any other single
aspect of its design, responsible for its success and the success
that Autodesk has experienced.
</p>
<p>
And yet, even today, we write program after program that is
closed—that its users cannot program—that admits of no
extensions without our adding to its source code. If we believe
intellectually, from a sound understanding of the economic incentives
in the marketplace, that open systems are better, and have confirmed
this supposition with the success of AutoCAD, then the only question
that remains is <i>why?</i> Why not make every program an open
program?</p>
<p>
Well, because it's <i>hard</i>! Writing a closed program has
traditionally been much less work at every stage of the development
cycle: easier to design, less code to write, simpler documentation,
and far fewer considerations in the test phase. In addition, closed
products are believed to be less demanding of support, although I'll
argue later that this assumption may be incorrect.</p>
<h3>The painful path to programmability</h3>
<p>
Most programs start out as nonprogrammable, closed applications, then
painfully claw their way to programmability through the introduction
of a limited script or macro facility, succeeded by an increasingly
comprehensive interpretive macro language which grows like topsy and
without a coherent design as user demands upon it grow. Finally,
perhaps, the program is outfitted with bindings to existing languages
such as C.</p>
<p>
An alternative to this is adopting a standard language as the macro
language for a product. After our initial foray into the awful menu
macro language that still burdens us, AutoCAD took this approach,
integrating David Betz’ XLISP, a simple Lisp interpreter which
was subsequently extended by Autodesk to add floating point, many
additional Common Lisp functions, and, eventually, access to the
AutoCAD database.</p>
<p>
This approach has many attractions. First, choosing a standard
language allows users to avail themselves of existing books and
training resources to learn its basics. The developer of a dedicated
macro language must create all this material from scratch. Second,
an interpretive language, where all programs are represented in ASCII
code, is inherently portable across computers and operating systems.
Once the interpreter is gotten to work on a new system, all the
programs it supports are pretty much guaranteed to work. Third, most
existing languages have evolved to the point that most of the rough
edges have been taken off their design. Extending an existing
language along the lines laid down by its designers is much less
likely to result in an incomprehensible disaster than growing an
ad-hoc macro language feature by neat-o feature.</p>
<p>
Unfortunately, interpreters are <i>slow</i>, <i>slow</i>, <i>slow</i>.
A simple calculation of the number of instructions of overhead per
instruction that furthers the execution of the program quickly
demonstrates that no interpreter is suitable for serious computation.
As long as the interpreter is deployed in the role of a macro
language, this may not be a substantial consideration. Most early
AutoLISP®
programs, for example, spent most of their time submitting commands
to AutoCAD with the <tt>(command)</tt>
function. The execution time of the program was overwhelmingly
dominated by the time AutoCAD took to perform the commands, not the
time AutoLISP spent constructing and submitting them. However, as
soon as applications tried to do substantial computation, for example
the parametric object calculations in AutoCAD AEC, the overhead of
AutoLISP became a crushing burden, verging on intolerable. The
obvious alternative was to provide a compiled language. But that,
too, has its problems.</p>
<h2>Introducing <span class="a">Atlast</span></h2>
<p>
<span class="a">Atlast</span>™ is a toolkit that makes
applications programmable. Deliberately designed to be easy to
integrate both into existing programs and newly-developed ones,
<span class="a">Atlast</span> provides any program that incorporates it most
of the benefits of programmability with very little explicit effort on
the part of the developer. Indeed, once you begin to “think
<span class="a">Atlast</span>” as part of the design cycle,
you'll probably find that the way you design and build programs
changes substantially. I'm coming to think of
<span class="a">Atlast</span> as the “monster that feeds on
programs,” because including it in a program tends to shrink the
amount of special-purpose code that would otherwise have to be written
while resulting in finished applications that are open, extensible,
and more easily adapted to other operating environments such as the
event driven paradigm.</p>
<p>
The idea of a portable toolkit, integrated into a wide variety of
products, all of which thereby share a common programming language
seems obvious once you consider its advantages. It's surprising that
such packages aren't commonplace in the industry. In fact, the only
true antecedent to <span class="a">Atlast</span> I've encountered in
my whole twisted path through this industry was the universal macro
package developed in the mid 1970s by Kern Sibbald and Ben Cranston
at the University of Maryland. That package, implemented on Univac
mainframes, provided a common macro language shared by a wide variety
of University of Maryland utilities, including a text editor,
debugger, file dumper, and typesetting language. While <span
class="a">Atlast</span> is entirely different in structure and
operation from the Maryland package, which was an interpretive string
language, the concept of a cross-product macro language and
appreciation of the benefits to be had from such a package are
directly traceable to those roots.</p>
<p>
So what <i>is</i> <span class="a">Atlast</span>? Well…it's
FORTH, more or less. Now I'm well aware that the mere mention of
FORTH stimulates a violent immune reaction in many people second,
perhaps, only to that induced by the utterance of the dreaded word
“LISP.” Indeed, more that 12 years after my first
serious encounter with FORTH, I am only now coming to feel that I am
truly beginning to “get it”—to understand what it's
really about, what its true strengths (and weaknesses) are, and to
what problems it can offer uniquely effective solutions. PostScript
had a lot to do with my coming to re-examine FORTH, as did my failed
attempt in early 1988 to separate AutoCAD's user interface from the
geometry engine. That project, <i>The Leto Protocol</i>, ended with
my concluding that to succeed: to create an interface that would not
grow to unbounded size, bewildering complexity, and glacial
performance, it would be necessary to embed programmability within
the core—to provide a set of primitives that could be composed,
by the user interface module, into higher-level operators that could
be invoked across the link between the two components. This
programmability would, of course, have to be in a portable form and
not involve linking user code into the AutoCAD core.</p>
<p>
In looking for parallels to the problem I faced, PostScript seemed
similarly motivated and reasonably effective in accomplishing its
goals. (One can certainly attack PostScript on performance, although
I suspect its performance problems stem more from the underlying
execution speed of the graphics primitives and the inefficient ASCII
representation of input than any inherent aspect of the language.)
Certainly PostScript blew away its competitors, such as Impress and
DDL, almost without taking notice of them. Further, it seemed
apparent that PostScript's success was another example in the long
list of open, programmable products that triumphed over “more
comprehensive” but non-extensible ones.</p>
<p>
Looking at PostScript inevitably brings one back to the language that
inspired it, FORTH. Although FORTH has a reputation for obscurity
and seems to attract an unusually high percentage of flaky adherents,
it has many attributes that recommend it as a candidate for a
portable tool to make any application programmable.</p>
<p>
<b>It is small.</b> A minimal implementation of
FORTH is a tiny thing indeed, since most of the language can be
defined in itself, using only a small number of fundamental
primitives. Even a rich implementation, with extensions such as
floating point and mathematical functions, strings, file I/O,
compiler writing facilities, user-defined objects, arrays, debugging
tools, and runtime instrumentation, is still on the order of one
fifth the number of source lines of a Lisp interpreter with far fewer
built-in functions, and occupies less than of 70% the object code
size. Runtime data memory requirements are a tiny fraction (often
one or two percent) of those required by Lisp, and frequently
substantially less that compiled languages such as C. It's kind of
startling to discover that an entire interpretive and compiled
language, including floating point, all the math functions of C, file
I/O, strings, etc., can be built, in large model, into a DOS
executable of 50964 bytes. It can.</p>
<p>
<b>It is fast.</b> Because it is a threaded
language, execution of programs consists not of source level
interpretation but simple memory loads and indirect jumps. Even for
compute-bound code, the speed penalty compared to true compilers is
often in the range of 5 to 8. While this may seem a serious price to
pay, bear in mind that tokenising Lisp interpreters often exhibit
speed penalties of between 60 and 70 to 1 on similar code, and
source-level interpreters, such as the macro languages found in many
application programs, are often much, much worse than that. In most
programs, the execution speed of FORTH and compiled code will be
essentially identical, particularly when FORTH is used largely in the
role of a macro language, calling primitives within an application
coded in a compiled language.</p>
<p>
<b>It is portable.</b> If the implementation
rigidly specifies the memory architecture and data types used (and
this can be done with essentially no sacrifice in speed), FORTH
programs can be made 100% compatible among implementations. Programs
can be transferred as ASCII files, universally interchangeable across
systems. Application data types defined in FORTH, using its object
creation facilities, automatically gain the portability of the
underlying data types.</p>
<p>
<b>It is easy to extend.</b> Because the
underlying architecture is very simple (unlike, for example, that of
a Lisp interpreter), any competent C programmer with a minimum of
indoctrination can begin adding C-coded primitives to a C-implemented
FORTH within hours. These C primitives will run at full speed, yet
be able to be parameterised, placed in definitions, used in loops,
etc., from any FORTH construct. This leads to a different way of
building applications. Rather than programming the structure and
primitives as a unified process, one builds the application-unique
primitives that are needed, tests them interactively as they are
built, then assembles the application with glue code written either
in FORTH or C depending upon considerations of efficiency, security,
and the extent to which one wishes to make the underlying primitives
visible to and accessible by the user. Unlike conventional program
development processes, these considerations are not yes-or-no
decisions but, for the most part, continua along which the product
may be positioned at the point desired and subsequently adjusted
based upon market feedback.</p>
<p>
<b>It is interactive.</b> While most portions of
a FORTH program are compiled into a form equally compact and
comparable in execution speed to machine code, direct user
interaction can always be furnished simply by providing a connection
from the user's keyboard to the interpreter (or conversely, blocked
by denying the user that access). That such interactivity expedites
program development compared to the normal edit, compile, link, debug
cycle is well known. That FORTH can provide it without sacrificing
execution speed is one of its major attractions.</p>
<p>
<b>It supports multiple operating paradigms.</b>
Once the technique of encapsulating the functionality of a product in
primitives accessible from the FORTH environment is mastered, it is
possible to build programs in which the core facilities (for example,
database access, geometric calculations, graphical display of
results, calculating mass properties) can be composed into sequences
that can be invoked from a program, called interactively from a
command line, triggered by a menu selection or pick of a button in a
dialogue, or virtually any other form of interaction imaginable.
Further, since any stimulus that affects the program simply executes
a FORTH word, and such words can be easily redefined with a small
amount of FORTH text, any of these operating modes can be rendered
programmable by the implementor, third party developer, or user, at
the discretion of the designer.</p>
<p>
<b>It is surprisingly modern.</b> Although FORTH
appears to be an artifact of the bygone days of 64K computers and
teletype machines, many of its concepts, viewed through contemporary
eyes, are remarkably up to date. For example, few languages share
its ability to define new fundamental data types, along with methods
that operate upon them. The multiple dictionary facility of FORTH
permits one to create objects that inherit, by default, properties of
their parents, and to implement such structures in an efficient
manner.</p>
<h3><span class="a">Atlast</span> and FORTH</h3>
<p>
All of these advantages do not erase some substantial shortcomings of
FORTH, particularly in the modern programming environment. In
defining <span class="a">Atlast</span>, I have attempted to conform to
FORTH wherever possible, without compromising my overall goal of
creating a system that would allow a developer to factor out the
programmability from an application and hand it to a standard module
to manage, precisely as C programmers delegate I/O and mathematical
function evaluation to library routines provided for those
purposes.</p>
<p>
<span class="a">Atlast</span> is based on the FORTH-83 standard and
incorporates many of the optional extensions and supplementary words
defined in that standard. Once the basic differences between FORTH and
<span class="a">Atlast</span> have been mastered, one can use a FORTH
reference manual for most user-level <span class="a">Atlast</span>
programming tasks. The major differences between FORTH-83 and
<span class="a">Atlast</span> are as follows.</p>
<p>
<b>Integers are 32 bits.</b> To bring forth another language burdened
with 16 bit integers in the year 1990 is, to my mind, unthinkable. We
are rapidly entering an era where the vast majority of C language
environments agree that the <tt>int</tt> type is 32 bits, and
applications may be expected to rapidly conform to this standard.
Consequently, in <span class="a">Atlast</span>, all integers are 32
bits and no <tt>short</tt> data type is provided. Note that this does
not imply incompatibility with C environments with 16 bit
<tt>int</tt>s—<span class="a">Atlast</span> works perfectly with
Turbo C on MS-DOS and Microsoft C on OS/2, for example, because all
integers are explicitly declared as <tt>long</tt>.</p>
<p>
<b>Identifiers are arbitrary length.</b> In <span
class="a">Atlast</span>, you need not struggle with the tradeoff
between memory efficiency and uniqueness of identifiers that plagues
the FORTH programmer. Identifiers are limited in length only to the
size of the built-in token assembly buffer, which defaults to 128
characters, and all characters are significant. Again, this change
brings <span class="a">Atlast</span> more closely into conformance
with contemporary language designs. To implement this change, symbol
names were moved from the heap into dynamically allocated buffers,
taking advantage of the underlying C runtime environment. This makes
the task of adjusting heap size easier (and changes some of the arcana
of programs that fiddle with the low-level structure of the system,
but everything you could do in FORTH, you can do in
<span class="a">Atlast</span>, albeit in a slightly different way).</p>
<p>
<b>Floating point is supported.</b> Floating point constants,
variables, operators, scanning and formatting facilities, and a rich
set of mathematical functions are provided as primitives (which can be
turned off at compile time, if not needed). Compatibly with C, the
default floating point type is 64 bit C <tt>double</tt> precision
numbers. The only assumption made by <span class="a">Atlast</span>
about floating point format is that a floating point number is twice
the size of an integer. The rational number facilities of FORTH are
not provided in <span class="a">Atlast</span>.</p>
<p>
<b>Strings are supported.</b> Strings are supported at a much higher
level in <span class="a">Atlast</span> than in FORTH. String literals
are provided in a general and explicit manner using the C syntax for
escaping special characters. A rich set of string processing
functions which closely follow those of C are provided
(<tt>STRCPY</tt>, <tt>STRCAT</tt>, <tt>STRLEN</tt>…). A
mechanism of cyclically allocated temporary string buffers provides
more flexible manipulation of strings in interactive input. Strings
continue to follow the pointer and buffer model used by both C and
FORTH. String-intensive programs should run at about the same speed
as their equivalents in C or FORTH.</p>
<p>
<b>Debugging facilities are provided.</b> <span
class="a">Atlast</span> can be configured at compile time with as much
or as little error checking and debugging support as is appropriate
for the application in which it is being integrated and the
development status of that product. During development and test, one
can configure <span class="a">Atlast</span> with an optional
<tt>TRACE</tt> that follows program execution primitive by primitive,
a <tt>WALKBACK</tt> that prints the active word stack when an error is
detected, precise overflow and underflow checking of both the
evaluation and return stacks, and close to bulletproof pointer
checking that catches attempts to load or store outside the designated
heap area. Although sufficiently crafty programs can still crash
<span class="a">Atlast</span>, errors that slip past the checking and
wreak havoc are extremely rare, even in unprotected environments such
as MS-DOS. This, combined with the fundamental interactivity of
<span class="a">Atlast</span>, makes for a friendly debugging environment.
All the runtime error checking can be disabled to reduce memory and
execution time overhead, when and where appropriate.</p>
<p>
<b>File I/O follows C and Unix conventions.</b> FORTH was developed
before the age of standard operating systems; in its early days, it
<i>was</i> the operating system of many of the minicomputers which ran
it. Now that the Unix file system interface has become a
<i lang="la" xml:lang="la">de facto</i> industry standard, <span
class="a">Atlast</span> conforms to that model of file system
operation. <tt>FILE</tt> variables correspond to C language file
descriptors, and a familiar set of primitives such as <tt>FOPEN</tt>,
<tt>FCLOSE</tt>, <tt>FREAD</tt>, <tt>FSEEK</tt>, etc., are used in the
same manner as in C. Line-level I/O is provided as well, offering
AutoCAD-compatible automatic recognition of ASCII files written with
any of the current end of line conventions.</p>
<p>
<b>Extensive support for embedding is provided.</b> Unlike FORTH,
<span class="a">Atlast</span> is intended to be invisibly embedded
within application programs. Other than providing a common framework
for programmability and extension, the application continues to
“look like” itself, not like <span class="a">Atlast</span>
or FORTH. Thus, <span class="a">Atlast</span> is not “in
control” in the sense that the main loop of a FORTH system is;
it is a slave, called by the application at appropriate times.
Accomplishing this required inverting the control structure from that
of a typical FORTH system and providing a comprehensive set of C
callable linkages by which the application communicates with
<span class="a">Atlast</span>. In addition, primitives are provided which
aid in tuning <span class="a">Atlast</span> to the precise needs of
the host program. The developer can monitor memory usage, note which
primitives are used and which are not, and configure a custom version
of <span class="a">Atlast</span> ideally suited to the needs and
environment of the host program.</p>
<h3>A note on what follows</h3>
<p>
In order to illustrate <span class="a">Atlast</span>, the balance of
this paper employs numerous sample programs and fragments of
<span class="a">Atlast</span> code. A reader with a basic understanding of
FORTH should, along with the definitions of the
<span class="a">Atlast</span> primitives given at the end of the paper, be
able to figure out what is going on in the examples. If you've never
encountered FORTH before, the examples may seem little more than
gibberish. Don't worry—once you get the hang of it, or consult
one of the many excellent FORTH books available (I recommend
<cite><a href="http://www.amazon.com/exec/obidos/ASIN/0893036609/fourmilabwwwfour">Mastering
Forth</a></cite>, by Anderson and Tracy, New York: Brady
Books/Prentice-Hall, 1984), all will become clear.</p>
<p>
Until then, don't be put off by the examples. Just skim over them
<i>as if</i> you understood them. You'll still pick up the flavour of
the package, how it integrates with applications, and what you can do
with it. I'd like to be able to leave my brain and fingers running
overnight and find a complete <span class="a">Atlast</span> reference
manual that could stand by itself sitting on my machine the next day.
Alas, I lack overnight batch capability and have no opportunity to
undertake such a task in prime time at present. I decided to supply
the documentation in this oddly incomplete form to get the essentials
across to those who can understand it rather than defer the entire
effort until I can complete a hundred pages or so of documentation
that largely duplicates a FORTH reference manual.</p>
<h2>Interactive <span class="a">Atlast</span></h2>
<p>
Although <span class="a">Atlast</span> is intended to be embedded in
application programs, for learning the language, experimenting with
small programs, and using it as a desk calculator, it's handy to have
an interactive stand-alone version. The <span class="a">Atlast</span>
source distribution includes a main program, <tt>atlmain.c</tt>, that
can be linked with <span class="a">Atlast</span> to provide such a
utility. The executable, called <tt>atlast</tt> on Unix and
<tt>atlast.exe</tt> on MS-DOS, is built with all error checking
enabled to aid in program development.</p>
<p>
To experiment with <span class="a">Atlast</span>, execute the
interactive program with:</p>
<pre class="c">
atlast
</pre>
<p>
You'll be prompted with:</p>
<pre class="c">
->
</pre>
<p>
as long as <span class="a">Atlast</span> is in the interpretive
state. For example, you might load <span class="a">Atlast</span> and
experiment with various rational approximations of π.</p>
<pre class="c">
% atlast
-> 22.0 7.0 f/ f.
3.14286 -> 377.0 120.0 f/ f.
3.14167 -> ^D
%
</pre>
<p>
Note that <span class="a">Atlast</span> does not explicitly return the
carriage after output; use the <tt>CR</tt> primitive if you wish this
done. Rather than printing each number and comparing it manually
against π, we can define a <i>constant</i> with the value of π
and a new <i>word</i> (or function) that compares a value against it
and prints the error residual. Here's how we might do that:</p>
<pre class="c">
% atlast
-> 1.0 atan 4.0 f* 2constant pi
-> : pierr
:> pi f- fabs f. cr
:> ;
-> 3.0 pierr
.141593
-> 22.0 7.0 f/ pierr
0.00126449
-> 355.0 113.0 f/ pierr
2.66764e-07
-> ^D
%
</pre>
<p>
We can also load programs from files into Interactive
<span class="a">Atlast</span>. Suppose we want to investigate the behaviour
of Leibniz’ famous 1673 series that converges (achingly
slowly) to π The series is:</p>
<p>
π/4 = 1 − 1/3 + 1/5 − 1/7 + 1/9 − …
</p>
<p>
We can create a file, using the text editor of our choice, containing
the following:</p>
<pre class="c">
\ Series approximations of Pi
\ Leibniz: pi/4 = 1 - 1/3 + 1/5 - 1/7 ...
: leibniz ( n -- fpi )
1.0 1.0
4 pick 1 do
2.0 f+ \ denom += 2
2dup
i 1 and if
fnegate
then
1.0 2swap f/
2rot f+
2swap
loop
2drop
rot drop
4.0 f*
;
\ Reference value of Pi
1.0 atan 4.0 f* 2constant pi
\ Calculate and print error
: pierr
pi f- fabs f. cr
;
</pre>
<p>
If this seems like gibberish, don't worry! Remember the first time
you looked at a Lisp or C program. If you want to decode some of the
structure of this program before learning the language, refer to the
definitions of <span class="a">Atlast</span> primitives at the back of
this manual, remember that <span class="a">Atlast</span> is a reverse
Polish stack language, and note that “<tt>\</tt>” is a
comment delimiter that causes the rest of the line to be ignored and
that “<tt>(</tt>” is a comment delimiter that ignores all
text until the next “<tt>)</tt>”.</p>
<p>
If this file is saved as <tt>leibniz.atl</tt>, we can load the program
into Interactive <span class="a">Atlast</span> with the command:</p>
<pre class="c">
atlast -ileibniz
</pre>
<p>
<span class="a">Atlast</span> will compile the program in the file,
report any errors, and if no errors are found enter the interactive
interpretation mode. The definition of <tt>leibniz</tt> performs the
number of iterations specified by the number on the top of the stack
and leaves the resulting series approximation to π on the top of
the stack.</p>
<p>
We can play with this definition as follows:</p>
<pre class="c">
% atlast -ileibniz
10 leibniz f.
3.04184 -> 100 leibniz f.
3.13159 -> 1000 leibniz f.
3.14059 -> 10000 leibniz f.
3.14149 ->
</pre>
<p>
Well, we can see it's converging, but not very fast. Since we can
define new compiled words on the fly, let's improvise a definition
that will print the value and its error for increments of 10000
iterations, then run that program. Continuing our session above:</p>
<pre class="c">
-> : itest 0 do i 1+ 10000 * dup .
:> leibniz 2dup f. pierr loop ;
-> 5 itest
10000 3.14149 0.0001
20000 3.14154 5e-05
30000 3.14156 3.33333e-05
40000 3.14157 2.5e-05
50000 3.14157 2e-05
-> ^D
%
</pre>
<p>
As you can see (even if you don't understand), we've mixed compiled
code, interpreted code, and on-the fly definition of new compiled
functions in a seamless manner.</p>
<p>
You can also run an <span class="a">Atlast</span> program in batch
mode simply by specifying its name on the <span
class="a">Atlast</span> command line. If, for example, you added the
lines:</p>
<pre class="c">
\ Run iteration vs. error report
: itest
0 do
i 1+ 10000 * dup . leibniz
2dup f. pierr
loop
;
10 itest
</pre>
<p>
to the end of the <tt>leibniz.atl</tt> file, creating a new file
called <tt>leibbat.atl</tt>, you could run the program in batch mode
as follows:</p>
<pre class="c">
% atlast leibbat
10000 3.14149 0.0001
20000 3.14154 5e-05
30000 3.14156 3.33333e-05
40000 3.14157 2.5e-05
50000 3.14157 2e-05
60000 3.14158 1.66667e-05
70000 3.14158 1.42857e-05
80000 3.14158 1.25e-05
90000 3.14158 1.11111e-05
100000 3.14158 1e-05
%
</pre>
<p>
(By the way, as is apparent, this is clearly no way to compute π!
Try this, instead, if you're serious about pumping π.)</p>
<pre class="c">
\ Tamura-Kanada fast Pi algorithm
2variable a
2variable b
2variable c
2variable y
: tamura-kanada ( n -- fpi )
1.0 a 2!
1.0 2.0 sqrt f/ b 2!
0.25 c 2!
1.0
rot 1 do
a 2@ 2dup y 2!
b 2@ f+ 2.0 f/ a 2!
b 2@ y 2@ f* sqrt b 2!
c 2@ 2over a 2@ y 2@ f-
2dup f* f* f- c 2! 2.0 f*
loop
2drop
a 2@ b 2@ f+ 2dup f* 4.0 c 2@ f* f/
;
</pre>
<h2>Debugging</h2>
<p>
As befits an interactive language, <span class="a">Atlast</span>
provides debugging support. You can trace through the execution of a
program word by word by enabling the <tt>TRACE</tt> facility. To turn
tracing on, enter the sequence:</p>
<pre class="c">
1 trace
</pre>
<p>
If you've loaded a definition of the factorial function as follows:</p>
<pre class="c">
: factorial
dup 0= if
drop 1
else
dup 1- factorial *
then
;
</pre>
<p>
and execute it under trace, you'll see output as follows:</p>
<pre class="c">
% atlast -ifact
-> 1 trace
-> 3 factorial .
Trace: FACTORIAL
Trace: DUP
Trace: 0=
Trace: ?BRANCH
Trace: DUP
Trace: 1-
Trace: FACTORIAL
Trace: DUP
Trace: 0=
Trace: ?BRANCH
Trace: DUP
Trace: 1-
Trace: FACTORIAL
Trace: DUP
Trace: 0=
Trace: ?BRANCH
Trace: DUP
Trace: 1-
Trace: FACTORIAL
Trace: DUP
Trace: 0=
Trace: ?BRANCH
Trace: DROP
Trace: (LIT) 1
Trace: BRANCH
Trace: EXIT
Trace: *
Trace: EXIT
Trace: *
Trace: EXIT
Trace: *
Trace: EXIT
Trace: . 6 -> ^D
%
</pre>
<p>
You can turn off tracing with “<tt>0
trace</tt>”.</p>
<p>
When an error occurs, a walkback is normally printed that lists the
active words starting with the one in which the error occurred,
proceeding through levels of nesting to the outermost, interpretive
level. If the <a href="#wback"><tt>WALKBACK</tt> package</a> is
configured, the walkback is printed by default. You can disable it
with “<tt>0 walkback</tt>”. Here is a sample error
walkback report:</p>
<pre class="c">
% atlast -ileibniz
-> leibniz
Stack underflow.
Walkback:
ROT
LEIBNIZ
->
</pre>
<h2>Integrating <span class="a">Atlast</span></h2>
<p>
Unlike most languages, <span class="a">Atlast</span> is not structured
as a main program; it is a subroutine. You can invoke it when and
where you like within your application, providing as much or as little
programmability as is appropriate. Before we get into the details of
the interface between an application and
<span class="a">Atlast</span>, it's worth showing, by example, just how
simple a program can be that accesses all the facilities of
<span class="a">Atlast</span> mentioned so far. The following main program,
linked with the <span class="a">Atlast</span> object module,
constitutes a fully-functional interactive
<span class="a">Atlast</span> interpreter. It lacks the refinements of
Interactive <span class="a">Atlast</span> such as console break
processing, batch mode, loading definition files, prompting with
compilation state, and the like, but any program that Interactive
<span class="a">Atlast</span> will run can be run by this program, if
submitted to it by input redirection.</p>