2 # This is a shell archive (produced by GNU sharutils 4.6.3).
3 # To extract the files from this archive, save it to some FILE, remove
4 # everything before the `#!/bin/sh' line above, then type `sh FILE'.
7 # Made on 2010-12-08 20:37 UTC by <ying@althonx4>.
8 # Source directory was `/mnt/rd1/lithp'.
10 # Existing files will *not* be overwritten, unless `-c' is specified.
14 # ------ ---------- ------------------------------------------
15 # 2166 -rw-r--r-- lithp/version.nw
16 # 7067 -rw-r--r-- lithp/vars.nw
17 # 624 -rw-r--r-- lithp/TODO
18 # 6103 -rw-r--r-- lithp/samples.nw
19 # 5106 -rw-r--r-- lithp/README
20 # 5109 -rw-r--r-- lithp/parser.nw
21 # 3526 -rw-r--r-- lithp/main.nw
22 # 13471 -rw-r--r-- lithp/lists.nw
23 # 24480 -rw-r--r-- lithp/LICENSE
24 # 1824 -rw-r--r-- lithp/intro.nw
25 # 2611 -rw-r--r-- lithp/GNUmakefile
26 # 52035 -rw-r--r-- lithp/eval.nw
28 MD5SUM
=${MD5SUM-md5sum}
29 f
=`${MD5SUM} --version | egrep '^md5sum .*(core|text)utils'`
30 test -n "${f}" && md5check
=true || md5check
=false
32 echo 'Note: not verifying md5sums. Consider installing GNU coreutils.'
40 if test "$gettext_dir" = FAILED
&& test -f $dir/gettext \
41 && ($dir/gettext --version >/dev
/null
2>&1)
43 case `$dir/gettext --version 2>&1 | sed 1q` in
44 *GNU
*) gettext_dir
=$dir ;;
47 if test "$locale_dir" = FAILED
&& test -f $dir/shar \
48 && ($dir/shar --print-text-domain-dir >/dev
/null
2>&1)
50 locale_dir
=`$dir/shar --print-text-domain-dir`
54 if test "$locale_dir" = FAILED ||
test "$gettext_dir" = FAILED
58 TEXTDOMAINDIR
=$locale_dir
62 echo="$gettext_dir/gettext -s"
64 if (echo "testing\c"; echo 1,2,3) |
grep c
>/dev
/null
65 then if (echo -n test; echo 1,2,3) |
grep n
>/dev
/null
68 else shar_n
=-n shar_c
= ; fi
69 else shar_n
= shar_c
='\c' ; fi
73 st2tr
=123123592001.5 # old SysV 14-char limit
76 if touch -am -t ${st1} ${f} >/dev
/null
2>&1 && \
77 test ! -f ${st1} && test -f ${f}; then
78 shar_touch
='touch -am -t $1$2$3$4$5$6.$7 "$8"'
80 elif touch -am ${st2} ${f} >/dev
/null
2>&1 && \
81 test ! -f ${st2} && test ! -f ${st2tr} && test -f ${f}; then
82 shar_touch
='touch -am $3$4$5$6$1$2.$7 "$8"'
84 elif touch -am ${st3} ${f} >/dev
/null
2>&1 && \
85 test ! -f ${st3} && test -f ${f}; then
86 shar_touch
='touch -am $3$4$5$6$2 "$8"'
91 ${echo} 'WARNING: not restoring timestamps. Consider getting and'
92 ${echo} 'installing GNU `touch'\'', distributed in GNU coreutils...'
95 rm -f ${st1} ${st2} ${st2tr} ${st3} ${f}
97 if test ! -d ${lock_dir}
98 then : ; else ${echo} 'lock directory '${lock_dir}' exists'
102 then ${echo} 'x - created lock directory `'${lock_dir}\''.'
103 else ${echo} 'x - failed to create lock directory `'${lock_dir}\''.'
106 # ============= lithp/version.nw ==============
107 if test ! -d 'lithp'; then
110 then ${echo} 'x - created directory `lithp'\''.'
111 else ${echo} 'x - failed to create directory `lithp'\''.'
115 if test -f 'lithp/version.nw' && test "$first_param" != -c; then
116 ${echo} 'x -SKIPPING lithp/version.nw (file already exists)'
118 ${echo} 'x - extracting lithp/version.nw (text)'
119 sed 's/^X//' << 'SHAR_EOF' > 'lithp/version.nw' &&
121 \section
{Version information
}
124 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
126 <<version build version>>=
130 <<version build date>>=
134 <<version build tpotc>>=
138 2001-10-16 "Baloo" 0.06
140 \item set and setq combined to one helper function to reduce code size
141 \item fixed single parameter defun calls
142 \item fixed parsing over tabs
143 \item new: gc, garbage-collect (return "T")
144 \item new: enum, select
145 \item added a hello, world to the sample. (type 'make test')
146 \item added version information into main.nw
149 2001-10-10 "Storm" 0.5
151 \item Changed the parser to use a pair of callbacks.
(more flexible
)
155 2001-10-10 "Trebuchet" 0.4
158 \item List tagging functions
(list.nw
) added
for the above
161 2001-10-09 "Collasping" 0.3
163 \item new
: set, setf
, setq
(new version
)
168 2001-10-08 "Uakti" 0.2
170 \item Philip Glass album
, and Brazillian band
171 \item added
'quote' parsing
172 \item converted over to full list passing
(setq hello
'(0 1 1 3 4)) works
173 \item fixed the evaluation of a variable name as a return valuE
174 \item new: and, or, not, null, atom, car, cdr, cons, list
175 \item new: if, unless, when, cond
176 \item new: eval, prog1, prog2, progn
177 \item new: printc, terpri
180 2001-10-07 "In The Window"
182 \item basics of setq done. integrated and debugged the variable mechanism
183 \item it does not yet do things like: (setq hello '(0 1 1 3 4))
186 2001-10-03 "Building A Wall" 0.1
188 \item Orbital
- "Illuminate"
189 \item initial
file parser
190 \item initial tree builder
191 \item variable list tools
192 \item beginnings of the evaluator
193 \item add
, subtract
, multiply
, divide added
196 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
197 \subsection
{The Source File
[[version.h
]]}
198 \label
{sec
:version.h
}
202 #define VER_BUILD_DATE <<version build date>>
203 #define VER_BUILD_VER <<version build version>>
204 #define VER_BUILD_TPOTC <<version build tpotc>>
208 (set 20 01 12 23 03 00 40 'lithp/version.nw'; eval "$shar_touch") &&
209 chmod 0644 'lithp/version.nw'
211 then ${echo} 'restore of lithp/version.nw failed'
215 ${MD5SUM} -c >/dev
/null
2>&1 ||
${echo} 'lithp/version.nw: MD5 check failed'
217 0f5d90aff3e067588987355b08e5eac5 lithp/version.nw
220 test `LC_ALL=C wc -c < 'lithp/version.nw'` -ne 2166 && \
221 ${echo} 'restoration warning: size of lithp/version.nw is not 2166'
224 # ============= lithp/vars.nw ==============
225 if test ! -d 'lithp'; then
228 then ${echo} 'x - created directory `lithp'\''.'
229 else ${echo} 'x - failed to create directory `lithp'\''.'
233 if test -f 'lithp/vars.nw' && test "$first_param" != -c; then
234 ${echo} 'x -SKIPPING lithp/vars.nw (file already exists)'
236 ${echo} 'x - extracting lithp/vars.nw (text)'
237 sed 's/^X//' << 'SHAR_EOF' > 'lithp/vars.nw' &&
239 \section
{The Variable Mechanisms
}
240 \label
{sec
:variablemechanisms
}
242 Rather than using another structure and linked-list system
, we will just
243 use the same list structure that we use
for the files itself. This also
244 gives us the flexibility of having a variable point to a structure or
247 We will basically assume we have another list
, called
[[varlist
]] in
248 these methods
, which will basically be a single backbone with all of the
249 variable names. Their
[[branch
]] element will contain a pointer to the
250 data that the variable defines.
252 All of these basic methods will interact with the list
at the level of
253 the list itself. That is to say
, with the exception of macros
, when you
254 add a new variable or retrieve a variable
, you will be handing around
257 Any data passed
in will be duplicated internally where storage is involved.
258 Any returned elements will be the new stored data bits. That is to say
,
259 that you should not free any pointers returned by these methods.
261 <<Variable list definition>>=
262 extern le * mainVarList;
264 <<Variable list initialization>>=
265 le * mainVarList = NULL;
268 Since the mechanisms are identical for working with user-defined
269 functions, we will store those lists in here as well, even though
272 <<Defun list definition>>=
273 extern le * defunList;
275 <<Defun list initialization>>=
276 le * defunList = NULL;
279 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
280 \subsection {List Manips}
281 \label{sec:listmanips}
283 Some functions for working specifically with the variable lists.
284 Since these use the same [[le]] structure as defined previously,
285 but it is used a little differently, we need some functions for
286 working with the lists. These are those functions.
288 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
289 \subsubsection {variableFind}
291 This will return the [[le]] element whose [[data]] matches
292 the [[key]] passed in, in the variable list, [[varlist]].
294 If it was not found, a [[NULL]] is returned.
296 <<Variable find proto>>=
297 X le * variableFind( le * varlist, char * key )
300 <<Variable find implementation>>=
301 X <<Variable find proto>>
303 X le * temp = varlist;
305 X if (!varlist || !key) return( NULL );
309 X if (!strcmp(key, temp->data))
313 X temp = temp->list_next;
320 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
321 \subsubsection {variableFree}
323 Since we're using [[le]] lists for the variable system, the
324 ``free'' function is just a macro that calls the appropriate
325 [[le]] function, as seen here:
327 <<Variable free macro>>=
328 #define variableFree( L ) \
332 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
333 \subsection {Get and Set Variables}
334 \label{sec:getandsetvariables}
336 And, of course, some simple methods for dealing with setting
337 and getting of variables in the variable list.
340 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
341 \subsubsection {variableSet}
343 This will add a variable with the [[key]] and [[value]] passed in onto
344 the end of the [[varlist]], and then return the resulting list.
346 This is used when we set lists for variable values.
348 <<Variable set proto>>=
349 X le * variableSet( le * varlist, char * key, le * value )
352 <<Variable set Implementation>>=
353 X <<Variable set proto>>
357 X if (!key || !value) return( varlist );
359 X temp = variableFind( varlist, key );
362 X leWipe( temp->branch );
363 X temp->branch = leDup( value );
365 X temp = leNew( key );
366 X temp->branch = leDup( value );
367 X varlist = leAddHead( varlist, temp );
373 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
374 \subsubsection {variableSetString}
376 This will add a variable with the [[key]] and [[value]] passed in onto
377 the end of the [[varlist]], and then return the resulting list.
379 This is used when we set strings for variable values.
381 <<Variable set string proto>>=
382 X le * variableSetString( le * varlist, char * key, char * value )
385 <<Variable set string Implementation>>=
386 X <<Variable set string proto>>
390 X if (!key || !value) return( varlist );
392 X temp = leNew(value);
394 X varlist = variableSet( varlist, key, temp );
402 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
403 \subsubsection {variableGet}
405 This will retrieve a variable with the [[key]] from the [[varlist]].
406 It will return the variable data, or a [[NULL]] if it was not found.
408 This is used when we want to retrieve list values.
410 <<Variable get proto>>=
411 X le * variableGet( le * varlist, char * key )
414 <<Variable get Implementation>>=
415 X <<Variable get proto>>
417 X le * temp = variableFind(varlist, key);
418 X if (temp && temp->branch)
419 X return( temp->branch );
424 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
425 \subsubsection {variableGetString}
427 This will retrieve a variable with the [[key]] from the [[varlist]].
428 It will return the variable data, or a [[NULL]] if it was not found.
430 This is used when we want to retrieve string values.
432 <<Variable get string proto>>=
433 X char * variableGetString( le * varlist, char * key )
436 <<Variable get string Implementation>>=
437 X <<Variable get string proto>>
439 X le * temp = variableFind(varlist, key);
442 X && temp->branch->data
443 X && countNodes(temp->branch) == 1
445 X return( strdup(temp->branch->data) );
446 X return( strdup("-1") );
451 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
452 \subsection {Debug functions}
453 \label{sec:varsdebugtools}
455 A simple iterator to print out all of the variables in the variable
456 list [[varlist]] passed in.
458 <<Variable dump proto>>=
459 X void variableDump( le * varlist )
462 <<Variable dump Implementation>>=
463 X <<Variable dump proto>>
465 X le * temp = varlist;
468 X if (temp->branch && temp->data)
470 X printf("%s \t", temp->data);
471 X leDumpReformat( stdout, temp->branch );
474 X temp = temp->list_next;
480 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
484 Here we build up all of the above blocks into the .c file.
490 <<Variable list initialization>>
491 <<Defun list initialization>>
493 <<Variable find implementation>>
495 <<Variable set Implementation>>
496 <<Variable set string Implementation>>
497 <<Variable get Implementation>>
498 <<Variable get string Implementation>>
500 <<Variable dump Implementation>>
504 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
508 And we need to do the same for the header file as well.
514 <<Variable list definition>>
515 <<Defun list definition>>
517 <<Variable find proto>>;
518 <<Variable free macro>>;
520 <<Variable set proto>>;
521 <<Variable set string proto>>;
522 <<Variable get proto>>;
523 <<Variable get string proto>>;
525 <<Variable dump proto>>;
528 (set 20 01 10 10 22 08 22 'lithp/vars.nw'; eval "$shar_touch") &&
529 chmod 0644 'lithp/vars.nw'
531 then ${echo} 'restore of lithp/vars.nw failed'
535 ${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'lithp/vars.nw: MD5 check failed'
537 4eee5f7a601f32408e4ff3ee26f007ff lithp/vars.nw
540 test `LC_ALL=C wc -c < 'lithp/vars.nw'` -ne 7067 && \
541 ${echo} 'restoration warning: size of lithp/vars.nw is not 7067'
544 # ============= lithp/TODO ==============
545 if test -f 'lithp/TODO' && test "$first_param" != -c; then
546 ${echo} 'x -SKIPPING lithp/TODO (file already exists)'
548 ${echo} 'x - extracting lithp/TODO (text)'
549 sed 's/^X//' << 'SHAR_EOF' > 'lithp/TODO' &&
562 Recursively load the specified file, and evaluate it.
565 X - returns "T" if successfully loaded
570 Let evaluates the expressions, and sets up local variables with
571 those expressions in them, then executes the body with those
572 expressions. (very similar to 'defun' in a lot of ways, nearly
573 identical to the horribly formatted 'lambda')
575 The last return value from the from the body block gets returned.
577 (let ( (<var1> <exp1>)
581 ) ; vars are local to the body
583 (set 20 01 10 16 18 11 36 'lithp/TODO'; eval "$shar_touch") &&
584 chmod 0644 'lithp/TODO'
586 then ${echo} 'restore of lithp/TODO failed'
590 ${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'lithp/TODO: MD5 check failed'
592 8a3e332e102e3da22eb6eca3d739f4ac lithp/TODO
595 test `LC_ALL=C wc -c < 'lithp/TODO'` -ne 624 && \
596 ${echo} 'restoration warning: size of lithp/TODO is not 624'
599 # ============= lithp/samples.nw ==============
600 if test -f 'lithp/samples.nw' && test "$first_param" != -c; then
601 ${echo} 'x -SKIPPING lithp/samples.nw (file already exists)'
603 ${echo} 'x - extracting lithp/samples.nw (text)'
604 sed 's/^X//' << 'SHAR_EOF' > 'lithp/samples.nw' &&
606 \section{Sample files}
609 This is a bunch of sample files to test the system with.
612 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
613 \subsection {Sample 01}
616 (setq world "world" hi "Hello" comma "," exclamation "!")
617 (list hi comma world exclamation)
622 (setq world "world" hi "Hello" comma "," exclamation "!")
623 (list hi comma world exclamation)
627 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
628 \subsection {Sample 02}
632 ; this should be a comment
635 ; first some simple math functions
641 ; some nests and paren testing.
642 (+ (- 4 5) ( + 3 4) 10)
643 ( * ( + 3 4 ( - 10 7) 9) 17)
644 (* ( + 3 4 ( - 10 7) 9) 17)
645 (*(+ 3 4(- 10 7)9)17)
649 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
650 \subsection {Sample 03}
653 ; this is a bunch of supported stuff. it's good regression testing material...
654 ; uncomment the part you want to try...
657 ; some simple math functions
677 ;(and (< 100 (setq a 1)) (> 300 (setq a 2)) (setq a 3) )
679 ;(and (> 100 (setq a 1)) (> 300 (setq a 2)) (setq a 3) )
681 ;(and (> 100 (setq a 1)) (> 300 (setq a 2)) (setq a 400) )
683 ;(and (> 100 (setq a 1)) (> 300 (setq a 2)) )
686 (or (< 100 (setq a 1)) (< 300 (setq a 2)) NIL)
713 ;(setq hello '(0 1 1 3 4))
717 ;(atom (setq foo (+ 2 3)))
718 ;(atom (setq bar '(+ 2 3)))
724 ;(setq hi quote (H E L L O))
725 ;(setq hi2 '(H E L L O))
728 (setq cheese "cheese is quite yummy")
733 ;(setq e '(3)) ; these don't currently get handled properly in eval
734 ;(setq r '((3))) ; these don't currently get handled properly in eval
735 ;(setq t '(())) ; these don't currently get handled properly in eval
737 ;(setq foo '(+ (- 3 4 5) (* 2 3 4)))
738 ;(setq bar (+ (- 3 4 5) (* 2 3 4)))
739 ;(+ 2 (setq p (+ 5 3)))
743 ;(+ 2 (setq x (* 3 4)))
750 ;(+ 4 '(+ 3 4 '5 6 7))
751 ;(+ 4 quote (+ 3 4 '5 6 7))
753 ;(setq mud "dirt" smog "smoke")
768 ;(car (car '((a b))))
769 ;(cdr '((a b) (c d))))
772 ;(car (cdr '(a b c d e)))
773 ;(car '( (a b c) (d e f) (g h i) ) )
774 ;(cdr '( (a b c) (d e f) (g h i) ) )
776 ;(car (cdr '((a b) (c d)) ))
777 ;(cdr (car '((a b) (c d)) ))
779 ;(atom (cdr '((a b) (c d)) ))
781 ;(cdr (car '((a b) (c d))))
783 ;(cdr (car '((a b c) (d e f))))
784 ;(car (car '((a b c) (d e f))))
785 ;(car (cdr '((a b c) (d e f))))
786 ;(car (car (cdr '((a b c) (d e f)))))
787 (cdr (car (cdr '((a b c) (d e f)))))
788 (car (cdr (car (cdr '((a b c) (d e f))))))
791 ;(setq x (cons 'a '(b c)))
795 ;(cons '(a b) '(c d))
796 ;(cons 'a (cons 'b '(c d)))
799 ;(cons (car x) (cons (car (cdr x)) '(c d)) )
806 ;(car (setq x '(a b c)))
807 ;(car '(setq x '(a b c)))
815 (setq result (if (< 3 4) (setq a '(t r o o)) (setq b '(f a l e s))) )
817 (setq result (if (> 3 4) (setq c '(t r o o)) (setq d '(f a l e s))) )
820 ;(setq result (if (< 3 4) (setq a '(t r o o)) ) )
822 ;(setq result (if (> 3 4) (setq c '(t r o o)) ) )
825 ;(unless (< 3 4) (setq x (+ 3 4)) (setq y '(+ 9 8)) )
826 ;(unless (> 3 4) (setq w (+ 3 4)) (setq z '(+ 9 8)) )
828 ;(when (< 3 4) (setq a (+ 3 4)) (setq d '(+ 9 8)) )
829 ;(when (> 3 4) (setq s (+ 3 4)) (setq f '(+ 9 8)) )
831 ;(cond ( (> 3 4) (setq a 'one1) (setq b 'one2) )
832 ; ( (= 3 4) (setq c 'two1) (setq d 'two2) )
833 ; ( (< 3 4) (setq e 'three1) (setq f 'three2) )
836 ;(cond ( (> 3 4) (setq g 'one1) (setq h 'one2) )
837 ; ( (= 3 4) (setq i 'two1) (setq j 'two2) )
841 ;(princ '"hello world")
843 ;(princ "this is also a test");
851 ;(eval (cons '+ '(2 3)))
853 ;(prog1 (car '(a b c)) (cdr '(a b c)) (cdr '(d e f)) (cdr '(g h i)))
854 ;(prog2 (car '(a b c)) (cdr '(a b c)) (cdr '(d e f)) (cdr '(g h i)))
855 ;(progn (car '(a b c)) (cdr '(a b c)) (cdr '(d e f)) (cdr '(g h i)))
857 ;(setq hello '(0 1 1 3 4))
863 ;(setq c (+ 3 4) d (1+ b) e '(4 5 6))
864 ;(setq f (+ 3 4) g (1+ b) h)
869 ;(set (car g) (cdr g))
881 ;(defun addthree (x) (+ x 3))
883 ;(defun addtwoto3 (x y) (+ x y 3))
891 ;(addthree (* 4 (1- 7)))
893 ;(defun average (x y) (/ (+ x y) 2))
894 ;(average 7 (car '(21 3 4 5)))
897 ;(setq foo '(7 21 34 22 99))
898 ;(car foo) (car (cdr foo))
899 ;(/ (+ (car foo) (car (cdr foo))) 2)
901 ;(defun averagel (x) (/ (+ (car x) (car (cdr x))) 2))
902 ;(averagel '(7 21 34 22 99))
903 ;(averagel '(9 31 34 22 99))
905 (defun three (x) (+ 2 1))
909 ;(defun addthree (x) (+ x 3))
916 ;(defun seven () '(7))
917 ;(defun seven2 () (7))
925 ;(enum z y (e r t y) x)
935 ; (3 (setq a 'three))
954 (set 20 01 11 10 05 31 41 'lithp/samples.nw'; eval "$shar_touch") &&
955 chmod 0644 'lithp/samples.nw'
957 then ${echo} 'restore of lithp/samples.nw failed'
961 ${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'lithp/samples.nw: MD5 check failed'
963 ea1a3c621540afb3a8eb86cb2dc14195 lithp/samples.nw
966 test `LC_ALL=C wc -c < 'lithp/samples.nw'` -ne 6103 && \
967 ${echo} 'restoration warning: size of lithp/samples.nw is not 6103'
970 # ============= lithp/README ==============
971 if test -f 'lithp/README' && test "$first_param" != -c; then
972 ${echo} 'x -SKIPPING lithp/README (file already exists)'
974 ${echo} 'x - extracting lithp/README (text)'
975 sed 's/^X//' << 'SHAR_EOF' > 'lithp/README' &&
976 ----------------------------------------
978 X A small simple LISP interpreter
980 X Scott "Jerry" Lawrence
984 X http://www.cis.rit.edu/~jerry
987 ----------------------------------------
990 This is a basic, tiny LISP implementation. It was created to be a
991 configuration/logic file format for a game I am working on. It is
992 easily extendable enough to be used for other projects as well.
994 This project is meant to be included within your own work. There is a
995 sample executable that gets built that reads in from a file, and
996 interprets it, but it is very easy to integrate this source into your
999 It is also very easy to add your own methods into the evaluation core.
1002 ----------------------------------------
1003 X Supported Commands
1007 # # foo comment - skipped during parsing
1008 ; ; foo comment - skipped during parsing
1010 A (A) returns the value
1012 Variables, Functions:
1013 set (set A B ... ) sets A to B, evaluating both. Returns B.
1014 setf (setf A B ... ) sets A to B, evaluating only B. Returns B.
1015 setq (setq x 4 y 3) same as 'setf'
1016 defun (defun A B C) defines a function called A with parameter list B
1017 X and code block C. Returns A.
1018 X (A X Y) Calling the above (if there were two parameters.)
1019 X Wrong number of parameters returns NIL w/o evaluating
1020 enum (enum a b c) sets up N variables with incrementing values.
1024 + (+ A B C) add a list
1025 - (- A B C) subtract a list
1026 * (* A B C) multiply a list
1027 / (/ A B C) divide a list
1028 % (% A B) After A is divided by B, what's the leftover?
1030 1+ (1+ A) returns the number plus one
1031 1- (1- A) returns the number minus one
1036 < (< A B) returns T if A < B, otherwise NIL
1037 <= (<= A B) returns T if A <= B, otherwise NIL
1038 > (> A B) returns T if A > B, otherwise NIL
1039 >= (>= A B) returns T if A >= B, otherwise NIL
1040 = (= A B) returns T if A == B, otherwise NIL
1042 and (and A B) eval's the arguments until it hits a NIL
1043 or (or A B) eval's the arguments while args are NIL
1044 not (not A) returns the opposite of A (T->NIL),(NIL->T)
1045 null (null A) same as 'not'
1047 if (if A B C) if A is true, then B else C. if there's no C, return NIL
1048 unless (unless A B C) unless A is true, do B, C and any others.
1049 when (when A B C) when A is true, do B, C and any others.
1050 cond (cond (A B C)) if A is true then do B,C... otherwise, try the next set
1051 select (select A B C) case statement. Evaluates 'A', then compares it to
1052 X the first values of lists B and C. If they were equal,
1053 X the rest of the list gets evaluated, and last return
1059 eval (eval (A B)) evaluates (A B) as if it were directly input
1060 prog1 (prog1 A B C) evaluates all parts, returns the first's return value
1061 prog2 (prog2 A B C) evaluates all parts, returns the second's return value
1062 progn (progn A B C) evaluates all parts, returns the last's return value
1067 quote quote (A B) returns the element instead of evaluating it
1068 ' '(A B) same as 'quote'
1070 atom (atom E) returns T if E evaluates to an atom, not a list
1071 equal (equal A B) returns T if A and B have the same structure and atoms
1073 car (car E) returns the head of list E
1074 cdr (cdr E) returns all but the head of list E
1075 cons (cons A B) returns a appended to the head of list B
1076 list (list A B) returns a list of the elements as passed in
1081 princ (princ A B) print out the list entries and atoms
1082 terpri (terpri) print out a new line (terminate printing)
1087 gc (gc) garbage collect. Returns "T". (does nothing)
1088 garbage-collect same as 'gc'
1090 ----------------------------------------
1093 You should be able to just type 'make' or 'gmake' or whatever your
1094 GNU make is called. The Build process depends on:
1095 X noweb literate programming toolset
1097 If you want the document, you also need:
1101 To build the doc, type:
1104 The build process will also generate a few sample LISP test files.
1107 ----------------------------------------
1110 The latest version of this should be available off of
1112 X http://www.cis.rit.edu/~jerry/Software/lithp
1114 Be sure you're using the latest version.
1118 ----------------------------------------
1122 This program is free software; you can redistribute it and/or modify it
1123 under the terms of the GNU Lesser General Public License as published
1124 by the Free Software Foundation; either version 2 of the License, or
1125 (at your option) any later version.
1127 This program is distributed in the hope that it will be useful,
1128 but WITHOUT ANY WARRANTY; without even the implied warranty of
1129 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
1130 Lesser General Public License for more details.
1132 You should have received a copy of the GNU Lesser General Public
1133 License along with this program; if not, write to the Free Software
1134 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
1137 (set 20 01 10 16 18 31 16 'lithp/README'; eval "$shar_touch") &&
1138 chmod 0644 'lithp/README'
1140 then ${echo} 'restore of lithp/README failed'
1144 ${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'lithp/README: MD5 check failed'
1146 2c2938983b9ff976a3bb4c5bde232ae9 lithp/README
1149 test `LC_ALL=C wc -c < 'lithp/README'` -ne 5106 && \
1150 ${echo} 'restoration warning: size of lithp/README is not 5106'
1153 # ============= lithp/parser.nw ==============
1154 if test -f 'lithp/parser.nw' && test "$first_param" != -c; then
1155 ${echo} 'x -SKIPPING lithp/parser.nw (file already exists)'
1157 ${echo} 'x - extracting lithp/parser.nw (text)'
1158 sed 's/^X//' << 'SHAR_EOF' > 'lithp/parser.nw' &&
1160 \section{The File Parser}
1163 The File Parser is basically a simple tokenizer of the file passed in.
1164 These tokens are pulled from the file stream in \S\ref{sec:tokenizer},
1165 and added to the list in \S\ref{sec:listbuilder}.
1169 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1170 \subsection {List Builder}
1171 \label{sec:listbuilder}
1173 This is the main engine of the parser. It will use the below
1174 tokenizer to read in all elements of the file.
1176 We will be passing in two pointers to functions. These two functions
1177 will be used to get and unget characters to the buffer or stream, or
1178 whatever input device you are using.
1180 For the ``get a character'' function, we will be using this format:
1182 <<Parse get character callback typedef>>=
1190 And to ``unget a character'', we will use this format:
1192 <<Parse unget character callback typedef>>=
1200 <<Parse in file proto>>=
1203 X getcCallback getachar,
1204 X ungetcCallback ungetachar,
1210 <<Parse in file implementation>>=
1211 X <<Parse in file proto>>
1213 X char * temp = NULL;
1214 X enum tokenname tokenid = T_NONE;
1217 X if (!getachar || !ungetachar) return( NULL );
1221 X temp = snagAToken(getachar, ungetachar, &tokenid);
1229 X case (T_OPENPAREN):
1230 X list = leAddBranchElement(
1232 X parseInFile(getachar,
1247 X list = leAddDataElement(
1256 X case (T_CLOSEPAREN):
1266 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1267 \subsection {Tokenizer}
1268 \label{sec:tokenizer}
1270 Different handlings for different tokens:
1272 [[whitespace]]: skip over
1273 [[comment]]: skip to end of line
1274 [[(]]: return NULL, tokenid gets [[OPENPAREN]]
1275 [[)]]: return NULL, tokenid gets [[CLOSEPAREN]]
1276 [[newline]]: return NULL, tokenid gets [[NEWLINE]]
1277 [["foo"]]: return "foo", tokenid gets [[WORD]]
1278 [[number]]: return number in a string, tokenid gets [[WORD]]
1280 buffers returned need to be freed later.
1282 <<Parse token enum>>=
1294 <<Parse snag a token proto>>=
1297 X getcCallback getachar,
1298 X ungetcCallback ungetachar,
1299 X enum tokenname * tokenid
1303 <<Parse snag a token implementation>>=
1304 X <<Parse snag a token proto>>
1306 X unsigned int pos = 0;
1308 X int doublequotes = 0;
1313 X if (!getachar || !ungetachar)
1319 X /* chew space to next token */
1324 X /* munch comments */
1331 X } while (c != '\n');
1342 X ) && ( c != ' ') && ( c != '\t') )
1351 X *tokenid = T_OPENPAREN;
1357 X *tokenid = T_CLOSEPAREN;
1363 X *tokenid = T_QUOTE;
1369 X *tokenid = T_NEWLINE;
1379 X /* oh well. it looks like a string. snag to the next whitespace. */
1390 X temp[pos++] = (char) c;
1392 X if (!doublequotes)
1405 X temp[pos-1] = '\0';
1407 X if ( !strcmp(temp, "quote") )
1409 X *tokenid = T_QUOTE;
1412 X *tokenid = T_WORD;
1413 X return( strdup(temp) );
1424 X temp[pos-1] = '\0';
1425 X *tokenid = T_WORD;
1426 X return( strdup(temp) );
1438 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1444 <<Parse in file implementation>>
1445 <<Parse snag a token implementation>>
1453 <<Parse token enum>>
1455 <<Parse get character callback typedef>>
1456 <<Parse unget character callback typedef>>
1458 <<Parse snag a token proto>>;
1459 <<Parse in file proto>>;
1462 (set 20 01 10 15 21 37 35 'lithp/parser.nw'; eval "$shar_touch") &&
1463 chmod 0644 'lithp/parser.nw'
1465 then ${echo} 'restore of lithp/parser.nw failed'
1469 ${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'lithp/parser.nw: MD5 check failed'
1471 cf54dabd5c37013611d982731efe8449 lithp/parser.nw
1474 test `LC_ALL=C wc -c < 'lithp/parser.nw'` -ne 5109 && \
1475 ${echo} 'restoration warning: size of lithp/parser.nw is not 5109'
1478 # ============= lithp/main.nw ==============
1479 if test -f 'lithp/main.nw' && test "$first_param" != -c; then
1480 ${echo} 'x -SKIPPING lithp/main.nw (file already exists)'
1482 ${echo} 'x - extracting lithp/main.nw (text)'
1483 sed 's/^X//' << 'SHAR_EOF' > 'lithp/main.nw' &&
1485 \section{The Lithp Interpreter's Main Program}
1488 This is a sample main program that uses the lithp functions to read in
1489 all files contained on the command line, and interpret each one
1492 Once the lists have been evaluated using the [[leDumpEval]] function,
1493 it dumps out the variable and defun lists as well.
1495 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1496 \subsection{Parser Callbacks}
1498 These are the callbacks so that we can read in from a file. You can
1499 probably write your own callbacks to read in from a buffer or the
1500 like. It expects a stdio [[EOF]] at the end of the file to be
1503 <<main parser globals>>=
1507 First, the callback for the getc function...
1509 <<main parser getc callback proto>>=
1510 X int mygetc( void )
1512 <<main parser getc callback implementation>>=
1513 X <<main parser getc callback proto>>
1515 X return( getc( fp ) );
1520 And our callback for the ungetc function...
1522 <<main parser ungetc callback proto>>=
1523 X void myungetc( int c )
1525 <<main parser ungetc callback implementation>>=
1526 X <<main parser ungetc callback proto>>
1532 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1535 And now the main function itself.
1537 <<main function variables>>=
1540 X struct le * list = NULL;
1543 <<main check commandline>>=
1546 X fprintf(stderr, "ERROR: You must specify a .lsp file!\n");
1552 What we're basically going to do is that for each file loaded in,
1554 If it can open the file, we will parse it in using our [[mygetc]]
1555 and [[myungetc]] utility functions. We will then evaluate and dump
1556 the main list, then dump out all of the variables and user defined
1559 we're going to start off with a new set of variables for the next
1560 file, so we wipe them when we're done with them.
1562 <<main function body>>=
1563 X for (fileno = 0 ; fileno < argc-1 ; fileno ++)
1565 X /* parse in the file */
1566 X printf("==== File %02d: %s\n", fileno, argv[fileno+1]);
1567 X fp = fopen(argv[fileno+1], "r");
1571 X fprintf(stderr, "ERROR: Couldn't open \"%s\".\n", argv[fileno+1]);
1575 X list = parseInFile(mygetc, myungetc, list, &lineno);
1579 X /* evaluate the read-in lists and free */
1580 X leDumpEval(list, 0);
1583 X /* display the variables and free */
1584 X printf("Variables:\n");
1585 X variableDump( mainVarList );
1586 X variableFree( mainVarList );
1588 X /* display the user-defined functions and free */
1589 X printf("defun's:\n");
1590 X variableDump( defunList );
1591 X variableFree( defunList );
1595 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1596 \subsection{The Source File [[main.c]]}
1599 The source file for the main program simply includes the headers for
1600 the standard C headers it uses.
1605 #include "version.h"
1610 All of the stuff for the parser callbacks...
1612 <<main parser globals>>
1614 <<main parser ungetc callback implementation>>
1615 <<main parser getc callback implementation>>
1618 Then, it includes the main routine.
1621 main( int argc, char* argv[] )
1623 X <<main function variables>>
1625 X printf( "lithp sample executable by jsl.lithp@absynth.com\n" );
1626 X printf( "Version " VER_BUILD_VER
1627 X " " VER_BUILD_DATE
1628 X " \"" VER_BUILD_TPOTC
1630 X <<main check commandline>>
1631 X <<main function body>>
1636 (set 20 01 10 15 06 21 40 'lithp/main.nw'; eval "$shar_touch") &&
1637 chmod 0644 'lithp/main.nw'
1639 then ${echo} 'restore of lithp/main.nw failed'
1643 ${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'lithp/main.nw: MD5 check failed'
1645 19819f7590b84017364362c2d046191a lithp/main.nw
1648 test `LC_ALL=C wc -c < 'lithp/main.nw'` -ne 3526 && \
1649 ${echo} 'restoration warning: size of lithp/main.nw is not 3526'
1652 # ============= lithp/lists.nw ==============
1653 if test -f 'lithp/lists.nw' && test "$first_param" != -c; then
1654 ${echo} 'x -SKIPPING lithp/lists.nw (file already exists)'
1656 ${echo} 'x - extracting lithp/lists.nw (text)'
1657 sed 's/^X//' << 'SHAR_EOF' > 'lithp/lists.nw' &&
1659 \section{List Manipulations}
1662 The internal storage system that we're using for both parsed in LISP
1663 trees, as well as variables, and user-defined functions are all stored
1664 using the structures and mechanisms contained in this section.
1667 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1668 \subsection {Structure}
1669 \label{sec:structure}
1671 This is the basic, multipurpose structure that we are using in this
1674 If for example this node is a list of other items, then the [[branch]]
1675 item will be a pointer. If it is an atom of data, then the [[data]]
1676 item will be a pointer. In the case of the variable list, then both of
1677 these items are used.
1679 If the data or item is quoted, then the [[quoted]] flag should be set
1682 The [[tag]] field is used exclusively for the tagging functions, when a
1683 tree is to be marked up in some way for future processing.
1685 This structure creates doubly-linked list, although there is nothing
1686 currently that requires this... that is to say that the [[list_prev]]
1687 references in this project can probably be removed with no harm done.
1689 The [[list_next]] points to the next [[le]] structure on the same level
1690 of nesting as the current one.
1693 X typedef struct le{
1694 X /* either data or a branch */
1695 X struct le * branch;
1700 X /* for the next in the list in the current parenlevel */
1701 X struct le * list_prev;
1702 X struct le * list_next;
1707 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1708 \subsection {Creation and Destruction}
1709 \label{sec:createdestroy}
1711 We need ways to create and destroy these structures, and that is done
1712 here with the following functions:
1714 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1715 \subsubsection {leNew}
1717 This creates a new [[le]] structure with the passed in [[text]] as the
1718 data string. If no [[text]] is passed in, then a NULL pointer is set
1719 for it. The elements of this new item are initialized to something
1723 X le * leNew(char * text)
1726 <<List new implementation>>=
1727 X <<List new proto>>
1729 X le * new = (le *) malloc (sizeof(le));
1732 X new->branch = NULL;
1733 X new->data = (text)?strdup(text):NULL;
1736 X new->list_prev = NULL;
1737 X new->list_next = NULL;
1744 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1745 \subsubsection {leDelete}
1747 To delete an element, all that we need to do is to free the data
1748 pointed to in the element, and then free itself.
1750 The [[branch]] and [[list_prev]] of the items around this will either
1751 be invalid or unreachable after this is called. This is really only
1752 useful for deleting known atoms.
1754 <<List delete proto>>=
1755 X void leDelete(le * element)
1758 <<List delete implementation>>=
1759 X <<List delete proto>>
1763 X if (element->data) free( element->data );
1770 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1771 \subsubsection {leWipe}
1773 To delete an entire list, we will recursively call this function to
1774 delete all of the [[branch]]es, and [[next]] elements in turn. This is
1775 a post-order iterator so that pointers don't get munged as we try to
1776 traverse the tree. We will free ourself after all of our descendants
1779 <<List wipe proto>>=
1780 X void leWipe(le * list)
1783 <<List wipe implementation>>=
1784 X <<List wipe proto>>
1788 X /* free descendants */
1789 X leWipe(list->branch);
1790 X leWipe(list->list_next);
1792 X /* free ourself */
1793 X if (list->data) free( list->data );
1801 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1802 \subsection {Basic List Manips}
1803 \label{sec:basiclistmanips}
1805 The last thing we need are a few functions to add things onto the list for
1806 callers outside of this section.
1808 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1809 \subsubsection {leAddHead}
1811 This will add a new [[element]] onto the head of the list.
1813 This simply takes the new [[element]], appends the current [[list]]
1814 onto its [[list_next]] item, patches the [[list]]'s [[list_prev]] to
1815 point to the element, then return the element. It's just a simple
1816 insertion to the beginning of the list.
1818 <<List add head proto>>=
1819 X le * leAddHead(le * list, le * element)
1822 <<List add head implementation>>=
1823 X <<List add head proto>>
1825 X if (!element) return( list );
1827 X element->list_next = list;
1828 X if (list) list->list_prev = element;
1829 X return( element );
1834 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1835 \subsubsection {leAddTail}
1837 This will add a new [[element]] onto the end of the list.
1839 We will simply go to the end of the [[list]] (if it exists) then tack
1840 ourselves on, modifying the [[list_prev]] of the [[element]], as well
1841 as the [[list_next]] of the end of the list. Then we return the new
1842 list and we're all good.
1844 <<List add tail proto>>=
1845 X le * leAddTail(le * list, le * element)
1848 <<List add tail implementation>>=
1849 X <<List add tail proto>>
1853 X /* if neither element or list don't
1854 X exist return the 'new' list */
1855 X if (!element) return( list );
1856 X if (!list) return( element );
1858 X /* find the end element of the list */
1859 X while (temp->list_next)
1861 X temp = temp->list_next;
1864 X /* tack ourselves on */
1865 X temp->list_next = element;
1866 X element->list_prev = temp;
1868 X /* return the list */
1874 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1875 \subsection {Derived List Manips}
1876 \label{sec:derivedlistmanips}
1878 And for ease of use, we have the following functions, which use the
1881 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1882 \subsubsection {leAddBranchElement}
1884 This will add on a new element onto the end of the [[list]] passed in,
1885 containing the [[branch]] passed in, with its [[quoted]] flag set
1888 <<List add branch proto>>=
1889 X le * leAddBranchElement( le * list, le * branch, int quoted )
1892 <<List add branch implementation>>=
1893 X <<List add branch proto>>
1895 X le * temp = leNew(NULL);
1896 X temp->branch = branch;
1897 X temp->quoted = quoted;
1898 X return leAddTail(list, temp);
1903 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1904 \subsubsection {leAddDataElement}
1906 This will add on a new element onto the end of the [[list]] passed in,
1907 containing the [[data]] passed in, with its [[quoted]] flag set
1910 <<List add data proto>>=
1911 X le * leAddDataElement( le * list, char * data, int quoted )
1914 <<List add data implementation>>=
1915 X <<List add data proto>>
1917 X le * newdata = leNew(data);
1920 X newdata->quoted = quoted;
1921 X return leAddTail(list, newdata);
1927 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1928 \subsubsection {leDup}
1930 There are some cases where we want to duplicate an [[le]] tree. This
1931 function does exactly that.
1933 It simply iterates over the current list, recursing down for branches,
1934 duplicating the [[list]] passed in. It returns the duplicated tree.
1937 X le * leDup( le * list )
1940 <<List dup implementation>>=
1941 X <<List dup proto>>
1944 X if (!list) return( NULL );
1947 X temp = leNew(list->data);
1948 X temp->branch = leDup(list->branch);
1949 X temp->list_next = leDup(list->list_next);
1951 X if (temp->list_next)
1953 X temp->list_next->list_prev = temp;
1960 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1961 \subsection {List Tagging}
1963 For search and replace of items in a tree (for the implementation
1964 of the ``defun'' evaluator for example) we need a way to tag
1965 elements in a tree, and work based on these tags. The following
1966 functions accomplish this.
1968 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1969 \subsubsection {leClearTag}
1971 Set all of the tags in a list to -1.
1973 <<List tag clear proto>>=
1974 X void leClearTag( le * list )
1977 <<List tag clear implementation>>=
1978 X <<List tag clear proto>>
1980 X if (!list) return;
1982 X leClearTag( list->branch );
1983 X leClearTag( list->list_next );
1987 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1988 \subsubsection {leTagData}
1990 Sets all data that matches [[data]] with the tag numbered [[tagval]].
1992 <<List tag data proto>>=
1993 X void leTagData(le * list, char * data, int tagval)
1995 <<List tag data implementation>>=
1996 X <<List tag data proto>>
1998 X if (!data || !list) return;
2004 X if (!strcmp( list->data, data ))
2006 X list->tag = tagval;
2009 X leTagData( list->branch, data, tagval );
2011 X list = list->list_next;
2017 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2018 \subsubsection {leTagReplace}
2020 Sets all nodes whose tag matches [[tagval]] and replaces the data/branch
2021 with the data/branch information from [[newinfo]].
2023 <<List tag replace proto>>=
2024 X void leTagReplace(le * list, int tagval, le * newinfo)
2026 <<List tag replace implementation>>=
2027 X <<List tag replace proto>>
2029 X if (!list || !newinfo) return;
2033 X if( list->tag == tagval )
2035 X /* free any existing stuff */
2038 X free( list->data );
2039 X list->data = NULL;
2042 X /* NOTE: This next comparison might be flawed */
2043 X if ( newinfo->list_next || newinfo->branch )
2045 X list->branch = leDup( newinfo );
2048 X else if ( newinfo->data )
2050 X list->data = strdup( newinfo->data );
2054 X leTagReplace( list->branch, tagval, newinfo );
2056 X list = list->list_next;
2062 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2063 \subsection {Debug Tools}
2064 \label{sec:debugtools}
2066 These are for dubug output, and can probably be removed if you're
2069 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2070 \subsubsection {leDump}
2072 Dump out the entire list, all pretty-like.
2074 <<List dump proto>>=
2075 X void leDump( le * list, int indent )
2078 <<List dump implementation>>=
2079 X <<List dump proto>>
2088 X for( c=0 ; c<indent ; c++ ) printf( " " );
2089 X printf( "%s %s\n",
2091 X (temp->quoted == 1) ? "quoted" : ""
2094 X leDump(temp->branch, indent + 4);
2097 X temp=temp->list_next;
2102 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2103 \subsubsection {leDumpEvalTree}
2105 Dump out the entire list, all pretty-like, while evaluating each node.
2108 <<List dump eval tree proto>>=
2109 X void leDumpEvalTree( le * list, int indent )
2112 <<List dump eval tree implementation>>=
2113 X <<List dump eval tree proto>>
2120 X for( c=0 ; c<indent ; c++ ) printf( " " );
2123 X printf( "%s %s\n",
2125 X (temp->quoted == 1) ? "quoted" : ""
2128 X le * le_value = evaluateBranch(temp->branch) ;
2129 X printf( "B: %s", (temp->quoted) ? "quoted " : "");
2130 X leDumpReformat( stdout, le_value );
2134 X leDump(temp->branch, indent + 4);
2137 X temp=temp->list_next;
2142 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2143 \subsubsection {leDumpEval}
2145 Dump out the entire list, all pretty-like, while evaluating each node.
2147 <<List dump eval proto>>=
2148 X void leDumpEval( le * list, int indent )
2151 <<List dump eval implementation>>=
2152 X <<List dump eval proto>>
2156 X le * le_value = NULL;
2163 X leDumpReformat( stdout, temp->branch );
2165 X printf ("\n==> ");
2166 X le_value = evaluateBranch(temp->branch) ;
2167 X leDumpReformat( stdout, le_value );
2172 X temp=temp->list_next;
2174 X printf("=======\n");
2178 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2179 \subsubsection {leDumpReformat}
2181 Print out the tree as a standard s-expression list (as originally read
2182 in from a file) to the [[FILE]] as defined by [[of]].
2184 <<List dump reformat proto>>=
2185 X void leDumpReformat(FILE * of, le * tree)
2188 <<List dump reformat implementation>>=
2189 X <<List dump reformat proto>>
2191 X le * treetemp = tree;
2196 X if (!tree) return;
2198 X fprintf( of, "(" );
2201 X if (treetemp->data)
2203 X fprintf( of, "%s%s", notfirst?" ":"", treetemp->data);
2207 X if (treetemp->branch)
2209 X fprintf( of, " %s", (treetemp->quoted)? "\'":"");
2210 X leDumpReformat( of, treetemp->branch );
2213 X treetemp = treetemp->list_next;
2215 X fprintf( of, ")" );
2220 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2221 \subsection {lists.c}
2223 And finally, glue it all together in the .c file.
2230 <<List new implementation>>
2231 <<List delete implementation>>
2232 <<List wipe implementation>>
2234 <<List add head implementation>>
2235 <<List add tail implementation>>
2237 <<List add branch implementation>>
2238 <<List add data implementation>>
2239 <<List dup implementation>>
2241 <<List tag clear implementation>>
2242 <<List tag data implementation>>
2243 <<List tag replace implementation>>
2245 <<List dump implementation>>
2246 <<List dump eval tree implementation>>
2247 <<List dump eval implementation>>
2248 <<List dump reformat implementation>>
2251 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2252 \subsection {lists.h}
2254 And the header file as well.
2265 <<List delete proto>>;
2266 <<List wipe proto>>;
2268 <<List add head proto>>;
2269 <<List add tail proto>>;
2271 <<List add branch proto>>;
2272 <<List add data proto>>;
2275 <<List tag clear proto>>;
2276 <<List tag data proto>>;
2277 <<List tag replace proto>>;
2279 <<List dump proto>>;
2280 <<List dump eval proto>>;
2281 <<List dump eval tree proto>>;
2282 <<List dump reformat proto>>;
2286 (set 20 01 10 10 18 15 10 'lithp/lists.nw'; eval "$shar_touch") &&
2287 chmod 0644 'lithp/lists.nw'
2289 then ${echo} 'restore of lithp/lists.nw failed'
2293 ${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'lithp/lists.nw: MD5 check failed'
2295 ca3deb18e86d777c25122a1592cac774 lithp/lists.nw
2298 test `LC_ALL=C wc -c < 'lithp/lists.nw'` -ne 13471 && \
2299 ${echo} 'restoration warning: size of lithp/lists.nw is not 13471'
2302 # ============= lithp/LICENSE ==============
2303 if test -f 'lithp/LICENSE' && test "$first_param" != -c; then
2304 ${echo} 'x -SKIPPING lithp/LICENSE (file already exists)'
2306 ${echo} 'x - extracting lithp/LICENSE (text)'
2307 sed 's/^X//' << 'SHAR_EOF' > 'lithp/LICENSE' &&
2308 X GNU LESSER GENERAL PUBLIC LICENSE
2309 X Version 2.1, February 1999
2311 X Copyright (C) 1991, 1999 Free Software Foundation, Inc.
2312 X 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
2313 X Everyone is permitted to copy and distribute verbatim copies
2314 X of this license document, but changing it is not allowed.
2316 [This is the first released version of the Lesser GPL. It also counts
2317 X as the successor of the GNU Library Public License, version 2, hence
2318 X the version number 2.1.]
2322 X The licenses for most software are designed to take away your
2323 freedom to share and change it. By contrast, the GNU General Public
2324 Licenses are intended to guarantee your freedom to share and change
2325 free software--to make sure the software is free for all its users.
2327 X This license, the Lesser General Public License, applies to some
2328 specially designated software packages--typically libraries--of the
2329 Free Software Foundation and other authors who decide to use it. You
2330 can use it too, but we suggest you first think carefully about whether
2331 this license or the ordinary General Public License is the better
2332 strategy to use in any particular case, based on the explanations below.
2334 X When we speak of free software, we are referring to freedom of use,
2335 not price. Our General Public Licenses are designed to make sure that
2336 you have the freedom to distribute copies of free software (and charge
2337 for this service if you wish); that you receive source code or can get
2338 it if you want it; that you can change the software and use pieces of
2339 it in new free programs; and that you are informed that you can do
2342 X To protect your rights, we need to make restrictions that forbid
2343 distributors to deny you these rights or to ask you to surrender these
2344 rights. These restrictions translate to certain responsibilities for
2345 you if you distribute copies of the library or if you modify it.
2347 X For example, if you distribute copies of the library, whether gratis
2348 or for a fee, you must give the recipients all the rights that we gave
2349 you. You must make sure that they, too, receive or can get the source
2350 code. If you link other code with the library, you must provide
2351 complete object files to the recipients, so that they can relink them
2352 with the library after making changes to the library and recompiling
2353 it. And you must show them these terms so they know their rights.
2355 X We protect your rights with a two-step method: (1) we copyright the
2356 library, and (2) we offer you this license, which gives you legal
2357 permission to copy, distribute and/or modify the library.
2359 X To protect each distributor, we want to make it very clear that
2360 there is no warranty for the free library. Also, if the library is
2361 modified by someone else and passed on, the recipients should know
2362 that what they have is not the original version, so that the original
2363 author's reputation will not be affected by problems that might be
2364 introduced by others.
2366 X Finally, software patents pose a constant threat to the existence of
2367 any free program. We wish to make sure that a company cannot
2368 effectively restrict the users of a free program by obtaining a
2369 restrictive license from a patent holder. Therefore, we insist that
2370 any patent license obtained for a version of the library must be
2371 consistent with the full freedom of use specified in this license.
2373 X Most GNU software, including some libraries, is covered by the
2374 ordinary GNU General Public License. This license, the GNU Lesser
2375 General Public License, applies to certain designated libraries, and
2376 is quite different from the ordinary General Public License. We use
2377 this license for certain libraries in order to permit linking those
2378 libraries into non-free programs.
2380 X When a program is linked with a library, whether statically or using
2381 a shared library, the combination of the two is legally speaking a
2382 combined work, a derivative of the original library. The ordinary
2383 General Public License therefore permits such linking only if the
2384 entire combination fits its criteria of freedom. The Lesser General
2385 Public License permits more lax criteria for linking other code with
2388 X We call this license the "Lesser" General Public License because it
2389 does Less to protect the user's freedom than the ordinary General
2390 Public License. It also provides other free software developers Less
2391 of an advantage over competing non-free programs. These disadvantages
2392 are the reason we use the ordinary General Public License for many
2393 libraries. However, the Lesser license provides advantages in certain
2394 special circumstances.
2396 X For example, on rare occasions, there may be a special need to
2397 encourage the widest possible use of a certain library, so that it becomes
2398 a de-facto standard. To achieve this, non-free programs must be
2399 allowed to use the library. A more frequent case is that a free
2400 library does the same job as widely used non-free libraries. In this
2401 case, there is little to gain by limiting the free library to free
2402 software only, so we use the Lesser General Public License.
2404 X In other cases, permission to use a particular library in non-free
2405 programs enables a greater number of people to use a large body of
2406 free software. For example, permission to use the GNU C Library in
2407 non-free programs enables many more people to use the whole GNU
2408 operating system, as well as its variant, the GNU/Linux operating
2411 X Although the Lesser General Public License is Less protective of the
2412 users' freedom, it does ensure that the user of a program that is
2413 linked with the Library has the freedom and the wherewithal to run
2414 that program using a modified version of the Library.
2416 X The precise terms and conditions for copying, distribution and
2417 modification follow. Pay close attention to the difference between a
2418 "work based on the library" and a "work that uses the library". The
2419 former contains code derived from the library, whereas the latter must
2420 be combined with the library in order to run.
2422 X GNU LESSER GENERAL PUBLIC LICENSE
2423 X TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
2425 X 0. This License Agreement applies to any software library or other
2426 program which contains a notice placed by the copyright holder or
2427 other authorized party saying it may be distributed under the terms of
2428 this Lesser General Public License (also called "this License").
2429 Each licensee is addressed as "you".
2431 X A "library" means a collection of software functions and/or data
2432 prepared so as to be conveniently linked with application programs
2433 (which use some of those functions and data) to form executables.
2435 X The "Library", below, refers to any such software library or work
2436 which has been distributed under these terms. A "work based on the
2437 Library" means either the Library or any derivative work under
2438 copyright law: that is to say, a work containing the Library or a
2439 portion of it, either verbatim or with modifications and/or translated
2440 straightforwardly into another language. (Hereinafter, translation is
2441 included without limitation in the term "modification".)
2443 X "Source code" for a work means the preferred form of the work for
2444 making modifications to it. For a library, complete source code means
2445 all the source code for all modules it contains, plus any associated
2446 interface definition files, plus the scripts used to control compilation
2447 and installation of the library.
2449 X Activities other than copying, distribution and modification are not
2450 covered by this License; they are outside its scope. The act of
2451 running a program using the Library is not restricted, and output from
2452 such a program is covered only if its contents constitute a work based
2453 on the Library (independent of the use of the Library in a tool for
2454 writing it). Whether that is true depends on what the Library does
2455 and what the program that uses the Library does.
2457 X 1. You may copy and distribute verbatim copies of the Library's
2458 complete source code as you receive it, in any medium, provided that
2459 you conspicuously and appropriately publish on each copy an
2460 appropriate copyright notice and disclaimer of warranty; keep intact
2461 all the notices that refer to this License and to the absence of any
2462 warranty; and distribute a copy of this License along with the
2465 X You may charge a fee for the physical act of transferring a copy,
2466 and you may at your option offer warranty protection in exchange for a
2469 X 2. You may modify your copy or copies of the Library or any portion
2470 of it, thus forming a work based on the Library, and copy and
2471 distribute such modifications or work under the terms of Section 1
2472 above, provided that you also meet all of these conditions:
2474 X a) The modified work must itself be a software library.
2476 X b) You must cause the files modified to carry prominent notices
2477 X stating that you changed the files and the date of any change.
2479 X c) You must cause the whole of the work to be licensed at no
2480 X charge to all third parties under the terms of this License.
2482 X d) If a facility in the modified Library refers to a function or a
2483 X table of data to be supplied by an application program that uses
2484 X the facility, other than as an argument passed when the facility
2485 X is invoked, then you must make a good faith effort to ensure that,
2486 X in the event an application does not supply such function or
2487 X table, the facility still operates, and performs whatever part of
2488 X its purpose remains meaningful.
2490 X (For example, a function in a library to compute square roots has
2491 X a purpose that is entirely well-defined independent of the
2492 X application. Therefore, Subsection 2d requires that any
2493 X application-supplied function or table used by this function must
2494 X be optional: if the application does not supply it, the square
2495 X root function must still compute square roots.)
2497 These requirements apply to the modified work as a whole. If
2498 identifiable sections of that work are not derived from the Library,
2499 and can be reasonably considered independent and separate works in
2500 themselves, then this License, and its terms, do not apply to those
2501 sections when you distribute them as separate works. But when you
2502 distribute the same sections as part of a whole which is a work based
2503 on the Library, the distribution of the whole must be on the terms of
2504 this License, whose permissions for other licensees extend to the
2505 entire whole, and thus to each and every part regardless of who wrote
2508 Thus, it is not the intent of this section to claim rights or contest
2509 your rights to work written entirely by you; rather, the intent is to
2510 exercise the right to control the distribution of derivative or
2511 collective works based on the Library.
2513 In addition, mere aggregation of another work not based on the Library
2514 with the Library (or with a work based on the Library) on a volume of
2515 a storage or distribution medium does not bring the other work under
2516 the scope of this License.
2518 X 3. You may opt to apply the terms of the ordinary GNU General Public
2519 License instead of this License to a given copy of the Library. To do
2520 this, you must alter all the notices that refer to this License, so
2521 that they refer to the ordinary GNU General Public License, version 2,
2522 instead of to this License. (If a newer version than version 2 of the
2523 ordinary GNU General Public License has appeared, then you can specify
2524 that version instead if you wish.) Do not make any other change in
2527 X Once this change is made in a given copy, it is irreversible for
2528 that copy, so the ordinary GNU General Public License applies to all
2529 subsequent copies and derivative works made from that copy.
2531 X This option is useful when you wish to copy part of the code of
2532 the Library into a program that is not a library.
2534 X 4. You may copy and distribute the Library (or a portion or
2535 derivative of it, under Section 2) in object code or executable form
2536 under the terms of Sections 1 and 2 above provided that you accompany
2537 it with the complete corresponding machine-readable source code, which
2538 must be distributed under the terms of Sections 1 and 2 above on a
2539 medium customarily used for software interchange.
2541 X If distribution of object code is made by offering access to copy
2542 from a designated place, then offering equivalent access to copy the
2543 source code from the same place satisfies the requirement to
2544 distribute the source code, even though third parties are not
2545 compelled to copy the source along with the object code.
2547 X 5. A program that contains no derivative of any portion of the
2548 Library, but is designed to work with the Library by being compiled or
2549 linked with it, is called a "work that uses the Library". Such a
2550 work, in isolation, is not a derivative work of the Library, and
2551 therefore falls outside the scope of this License.
2553 X However, linking a "work that uses the Library" with the Library
2554 creates an executable that is a derivative of the Library (because it
2555 contains portions of the Library), rather than a "work that uses the
2556 library". The executable is therefore covered by this License.
2557 Section 6 states terms for distribution of such executables.
2559 X When a "work that uses the Library" uses material from a header file
2560 that is part of the Library, the object code for the work may be a
2561 derivative work of the Library even though the source code is not.
2562 Whether this is true is especially significant if the work can be
2563 linked without the Library, or if the work is itself a library. The
2564 threshold for this to be true is not precisely defined by law.
2566 X If such an object file uses only numerical parameters, data
2567 structure layouts and accessors, and small macros and small inline
2568 functions (ten lines or less in length), then the use of the object
2569 file is unrestricted, regardless of whether it is legally a derivative
2570 work. (Executables containing this object code plus portions of the
2571 Library will still fall under Section 6.)
2573 X Otherwise, if the work is a derivative of the Library, you may
2574 distribute the object code for the work under the terms of Section 6.
2575 Any executables containing that work also fall under Section 6,
2576 whether or not they are linked directly with the Library itself.
2578 X 6. As an exception to the Sections above, you may also combine or
2579 link a "work that uses the Library" with the Library to produce a
2580 work containing portions of the Library, and distribute that work
2581 under terms of your choice, provided that the terms permit
2582 modification of the work for the customer's own use and reverse
2583 engineering for debugging such modifications.
2585 X You must give prominent notice with each copy of the work that the
2586 Library is used in it and that the Library and its use are covered by
2587 this License. You must supply a copy of this License. If the work
2588 during execution displays copyright notices, you must include the
2589 copyright notice for the Library among them, as well as a reference
2590 directing the user to the copy of this License. Also, you must do one
2593 X a) Accompany the work with the complete corresponding
2594 X machine-readable source code for the Library including whatever
2595 X changes were used in the work (which must be distributed under
2596 X Sections 1 and 2 above); and, if the work is an executable linked
2597 X with the Library, with the complete machine-readable "work that
2598 X uses the Library", as object code and/or source code, so that the
2599 X user can modify the Library and then relink to produce a modified
2600 X executable containing the modified Library. (It is understood
2601 X that the user who changes the contents of definitions files in the
2602 X Library will not necessarily be able to recompile the application
2603 X to use the modified definitions.)
2605 X b) Use a suitable shared library mechanism for linking with the
2606 X Library. A suitable mechanism is one that (1) uses at run time a
2607 X copy of the library already present on the user's computer system,
2608 X rather than copying library functions into the executable, and (2)
2609 X will operate properly with a modified version of the library, if
2610 X the user installs one, as long as the modified version is
2611 X interface-compatible with the version that the work was made with.
2613 X c) Accompany the work with a written offer, valid for at
2614 X least three years, to give the same user the materials
2615 X specified in Subsection 6a, above, for a charge no more
2616 X than the cost of performing this distribution.
2618 X d) If distribution of the work is made by offering access to copy
2619 X from a designated place, offer equivalent access to copy the above
2620 X specified materials from the same place.
2622 X e) Verify that the user has already received a copy of these
2623 X materials or that you have already sent this user a copy.
2625 X For an executable, the required form of the "work that uses the
2626 Library" must include any data and utility programs needed for
2627 reproducing the executable from it. However, as a special exception,
2628 the materials to be distributed need not include anything that is
2629 normally distributed (in either source or binary form) with the major
2630 components (compiler, kernel, and so on) of the operating system on
2631 which the executable runs, unless that component itself accompanies
2634 X It may happen that this requirement contradicts the license
2635 restrictions of other proprietary libraries that do not normally
2636 accompany the operating system. Such a contradiction means you cannot
2637 use both them and the Library together in an executable that you
2640 X 7. You may place library facilities that are a work based on the
2641 Library side-by-side in a single library together with other library
2642 facilities not covered by this License, and distribute such a combined
2643 library, provided that the separate distribution of the work based on
2644 the Library and of the other library facilities is otherwise
2645 permitted, and provided that you do these two things:
2647 X a) Accompany the combined library with a copy of the same work
2648 X based on the Library, uncombined with any other library
2649 X facilities. This must be distributed under the terms of the
2652 X b) Give prominent notice with the combined library of the fact
2653 X that part of it is a work based on the Library, and explaining
2654 X where to find the accompanying uncombined form of the same work.
2656 X 8. You may not copy, modify, sublicense, link with, or distribute
2657 the Library except as expressly provided under this License. Any
2658 attempt otherwise to copy, modify, sublicense, link with, or
2659 distribute the Library is void, and will automatically terminate your
2660 rights under this License. However, parties who have received copies,
2661 or rights, from you under this License will not have their licenses
2662 terminated so long as such parties remain in full compliance.
2664 X 9. You are not required to accept this License, since you have not
2665 signed it. However, nothing else grants you permission to modify or
2666 distribute the Library or its derivative works. These actions are
2667 prohibited by law if you do not accept this License. Therefore, by
2668 modifying or distributing the Library (or any work based on the
2669 Library), you indicate your acceptance of this License to do so, and
2670 all its terms and conditions for copying, distributing or modifying
2671 the Library or works based on it.
2673 X 10. Each time you redistribute the Library (or any work based on the
2674 Library), the recipient automatically receives a license from the
2675 original licensor to copy, distribute, link with or modify the Library
2676 subject to these terms and conditions. You may not impose any further
2677 restrictions on the recipients' exercise of the rights granted herein.
2678 You are not responsible for enforcing compliance by third parties with
2681 X 11. If, as a consequence of a court judgment or allegation of patent
2682 infringement or for any other reason (not limited to patent issues),
2683 conditions are imposed on you (whether by court order, agreement or
2684 otherwise) that contradict the conditions of this License, they do not
2685 excuse you from the conditions of this License. If you cannot
2686 distribute so as to satisfy simultaneously your obligations under this
2687 License and any other pertinent obligations, then as a consequence you
2688 may not distribute the Library at all. For example, if a patent
2689 license would not permit royalty-free redistribution of the Library by
2690 all those who receive copies directly or indirectly through you, then
2691 the only way you could satisfy both it and this License would be to
2692 refrain entirely from distribution of the Library.
2694 If any portion of this section is held invalid or unenforceable under any
2695 particular circumstance, the balance of the section is intended to apply,
2696 and the section as a whole is intended to apply in other circumstances.
2698 It is not the purpose of this section to induce you to infringe any
2699 patents or other property right claims or to contest validity of any
2700 such claims; this section has the sole purpose of protecting the
2701 integrity of the free software distribution system which is
2702 implemented by public license practices. Many people have made
2703 generous contributions to the wide range of software distributed
2704 through that system in reliance on consistent application of that
2705 system; it is up to the author/donor to decide if he or she is willing
2706 to distribute software through any other system and a licensee cannot
2709 This section is intended to make thoroughly clear what is believed to
2710 be a consequence of the rest of this License.
2712 X 12. If the distribution and/or use of the Library is restricted in
2713 certain countries either by patents or by copyrighted interfaces, the
2714 original copyright holder who places the Library under this License may add
2715 an explicit geographical distribution limitation excluding those countries,
2716 so that distribution is permitted only in or among countries not thus
2717 excluded. In such case, this License incorporates the limitation as if
2718 written in the body of this License.
2720 X 13. The Free Software Foundation may publish revised and/or new
2721 versions of the Lesser General Public License from time to time.
2722 Such new versions will be similar in spirit to the present version,
2723 but may differ in detail to address new problems or concerns.
2725 Each version is given a distinguishing version number. If the Library
2726 specifies a version number of this License which applies to it and
2727 "any later version", you have the option of following the terms and
2728 conditions either of that version or of any later version published by
2729 the Free Software Foundation. If the Library does not specify a
2730 license version number, you may choose any version ever published by
2731 the Free Software Foundation.
2733 X 14. If you wish to incorporate parts of the Library into other free
2734 programs whose distribution conditions are incompatible with these,
2735 write to the author to ask for permission. For software which is
2736 copyrighted by the Free Software Foundation, write to the Free
2737 Software Foundation; we sometimes make exceptions for this. Our
2738 decision will be guided by the two goals of preserving the free status
2739 of all derivatives of our free software and of promoting the sharing
2740 and reuse of software generally.
2744 X 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
2745 WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
2746 EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
2747 OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
2748 KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
2749 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
2750 PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
2751 LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
2752 THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
2754 X 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
2755 WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
2756 AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
2757 FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
2758 CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
2759 LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
2760 RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
2761 FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
2762 SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
2765 X END OF TERMS AND CONDITIONS
2767 (set 20 01 10 04 19 48 00 'lithp/LICENSE'; eval "$shar_touch") &&
2768 chmod 0644 'lithp/LICENSE'
2770 then ${echo} 'restore of lithp/LICENSE failed'
2774 ${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'lithp/LICENSE: MD5 check failed'
2776 e11467f1bb5c8af1c961d94891ad5f4a lithp/LICENSE
2779 test `LC_ALL=C wc -c < 'lithp/LICENSE'` -ne 24480 && \
2780 ${echo} 'restoration warning: size of lithp/LICENSE is not 24480'
2783 # ============= lithp/intro.nw ==============
2784 if test -f 'lithp/intro.nw' && test "$first_param" != -c; then
2785 ${echo} 'x -SKIPPING lithp/intro.nw (file already exists)'
2787 ${echo} 'x - extracting lithp/intro.nw (text)'
2788 sed 's/^X//' << 'SHAR_EOF' > 'lithp/intro.nw' &&
2792 Jerry Lawrence & [[jsl.lithp@absynth.com]] \\
2801 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2804 The target audience for this document is those who wish to become more
2805 familiar with the innter workings of the Lithp LISP interpreter.
2807 This is not a users guide for people new to LISP. It is implied that
2808 the reader has some familiarity with C programming as well as LISP
2809 programming, since in essence, this document is the source code to a
2812 People wishing to integrate Lithp into their own projects will probably
2813 want to examine the included ``[[main.c]]'', in \S\ref{sec:main} to see
2814 how it is done. If you wish to expand or reduce the functionality of
2815 Lithp, then \S\ref{sec:listevaluator} will be where you want to look.
2818 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
2819 \section{Introduction}
2822 This document is broken up into a few sections.
2823 In \S\ref{sec:main}, a sample main routine is implemented.
2824 In \S\ref{sec:parser}, the file parser is implemented.
2825 In \S\ref{sec:lists}, all of the list manipulation functions are implemented.
2826 In \S\ref{sec:variablemechanisms}, the same list structures are used to store
2827 variables and user-defined functions.
2828 In \S\ref{sec:listevaluator}, the list interpreter and evaluators are implemented.
2829 And finally, in \S\ref{sec:samples}, a few sample LISP files that work
2830 properly are given out as examples.
2831 \S\ref{sec:version} shows the current version information and changelog.
2835 major sections begins with an introduction describing the internal
2836 layout of that section.
2839 Most of this document is geared toward developers who wish to
2840 understand the internal workings of the interpreter.
2842 (set 20 01 10 10 22 12 06 'lithp/intro.nw'; eval "$shar_touch") &&
2843 chmod 0644 'lithp/intro.nw'
2845 then ${echo} 'restore of lithp/intro.nw failed'
2849 ${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'lithp/intro.nw: MD5 check failed'
2851 0b15f3ef6eeb6f1ac97b2b208d034ee6 lithp/intro.nw
2854 test `LC_ALL=C wc -c < 'lithp/intro.nw'` -ne 1824 && \
2855 ${echo} 'restoration warning: size of lithp/intro.nw is not 1824'
2858 # ============= lithp/GNUmakefile ==============
2859 if test -f 'lithp/GNUmakefile' && test "$first_param" != -c; then
2860 ${echo} 'x -SKIPPING lithp/GNUmakefile (file already exists)'
2862 ${echo} 'x - extracting lithp/GNUmakefile (text)'
2863 sed 's/^X//' << 'SHAR_EOF' > 'lithp/GNUmakefile' &&
2864 ##########################################################
2870 TEX := $(DOC:%.pdf=%.tex)
2872 NWS := intro.nw main.nw parser.nw lists.nw vars.nw eval.nw samples.nw version.nw
2874 SRCS := main.c parser.c lists.c eval.c vars.c
2875 HDRS := parser.h lists.h eval.h vars.h version.h
2876 SAMPLES := sample01.lsp sample02.lsp sample03.lsp
2882 X $(TEX:%.tex=%.aux) \
2883 X $(TEX:%.tex=%.toc) \
2884 X $(TEX:%.tex=%.log) \
2885 X $(TEX:%.tex=%.idx)
2887 OBJS := main.o parser.o lists.o eval.o vars.o
2889 ##########################################################
2892 all: $(TARGET) samples
2894 all2: $(TARGET) docs samples
2903 X rm -f $(GEN_FILES)
2913 X tar -cvf lithp-$(VERSION).tar lithp ;\
2914 X gzip -f lithp-$(VERSION).tar
2917 X ./lithp sample01.lsp
2921 ##########################################################
2925 CXXFLAGS := -g -mt -instances=static
2932 X -lsocket -ldl -lnsl -lgen -lposix4
2934 ##########################################################
2937 X @[ -f $@ ] && chmod u+w $@ || true
2938 X notangle -L -R$@ $(NWS) | cpif $@
2942 X @[ -f $@ ] && chmod u+w $@ || true
2943 X notangle -R$@ $(NWS) | cpif $@
2947 X @[ -f $@ ] && chmod u+w $@ || true
2948 X notangle -L -R$@ $(NWS) | cpif $@
2951 ##########################################################
2953 MKDIR_CMD = test -d $(@D) || mkdir -p $(@D)
2956 X # Ugly hack to run pdflatex as often as needed.
2959 X oldFingerprint="XXX" ; \
2960 X if [ -f $*.aux ]; then \
2961 X fingerprint="`sum $*.aux`" ; \
2963 X fingerprint="YYY" ; \
2965 X while [ ! "$${oldFingerprint}" = "$${fingerprint}" ]; do \
2966 X oldFingerprint="$${fingerprint}" ; \
2968 X fingerprint="`sum $*.aux`" ; \
2976 $(TOP)/doc/pdf/%.pdf: %.pdf
2981 X noweave -x $(NWS) > $@
2984 X $(CXX) -o $@ $(LDFLAGS) $(OBJS) $(LIBS)
2986 ##########################################################
2995 ##########################################################
2997 main.o: parser.h lists.h version.h eval.h vars.h
2998 parser.o: parser.h lists.h
2999 eval.o: eval.h lists.h
3000 vars.o: vars.h lists.h
3002 ##########################################################
3005 (set 20 01 12 23 03 00 03 'lithp/GNUmakefile'; eval "$shar_touch") &&
3006 chmod 0644 'lithp/GNUmakefile'
3008 then ${echo} 'restore of lithp/GNUmakefile failed'
3012 ${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'lithp/GNUmakefile: MD5 check failed'
3014 fcb19a2658f0320795cdf131711d31e6 lithp/GNUmakefile
3017 test `LC_ALL=C wc -c < 'lithp/GNUmakefile'` -ne 2611 && \
3018 ${echo} 'restoration warning: size of lithp/GNUmakefile is not 2611'
3021 # ============= lithp/eval.nw ==============
3022 if test -f 'lithp/eval.nw' && test "$first_param" != -c; then
3023 ${echo} 'x -SKIPPING lithp/eval.nw (file already exists)'
3025 ${echo} 'x - extracting lithp/eval.nw (text)'
3026 sed 's/^X//' << 'SHAR_EOF' > 'lithp/eval.nw' &&
3028 \section{The List Evaluator}
3029 \label{sec:listevaluator}
3031 The list evaluator is basically a callback mechanism that traverses the
3032 list passed in, and returns a char * containing the result.
3034 It will look up the first parameter of a list in the callback registry,
3035 then call that method with the list itself, without removing that head
3036 entry from it, so a list of [[(foo a b c)]] will trigger a callback for
3037 [[foo]], which will receive the list [[(foo a b c)]] as the [[branch]]
3040 Evaluate will also try to dereference variables if they exist.
3042 The [[evaluateBranch()]] method will evaluate a complete list passed
3043 in, while [[evaluateNode()]] method will only evaluate the single
3044 branch passed in. [[evaluateNode()]] is useful for dereferencing
3045 variables or lists in a list when in the callback. It is perfectly
3046 safe to recurse in this manner.
3048 There are also methods in this section relating to casting values to
3049 list nodes and back, as well as the evaluator callbacks for a basic
3050 LISP implementation.
3052 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3053 \subsection {Adding More Functionality}
3055 It is quite easy to add more functionality into this system. All that
3056 you need to do is to create a callback satisfying the prototype as
3057 described in the next section, then add it into the [[evalTable]].
3059 If you look at any of the following callbacks, you will see how it gets
3060 entered into the list, and some basic range checks that are done to
3061 make sure that the callback gets the right number of parameters and the
3065 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3066 \subsection {Callback Registry}
3067 \label{sec:callbackregistry}
3069 The callbacks will get their branch as one parameter. The other parameter
3070 is the number of items on the list, including the first word. All callbacks
3071 must return a newly allocated [[le]] list containing the return value.
3073 For example [[(foo A B)]] will get sent [[3]] as [[argc]] as well as
3074 the list [[(foo A B)]] as the [[branch]] parameter. This list is
3075 stored in [[le]] structures, which are just a simple tree/linked list.
3077 <<Eval callback typedef>>=
3087 This is the lookup structure that we'll use to store all of our
3088 callbacks in. It is simply a list of command strings to match, as well
3089 as the function callbacks as defined above. Do note that the evaluator
3090 is currently case sensitive. That is to say that ``[[foo]]'' and
3091 ``[[FOO]]'' will get evaluated differetntly.
3093 <<Eval lookup struct>>=
3094 X typedef struct evalLookupNode {
3100 And now, here is the list of builtin functions that we support.. The
3101 final element must be a pairing of [[NULL]]s so that the lookup
3102 function knows where to stop when looking through the table.
3104 <<Eval lookup table>>=
3105 X evalLookupNode evalTable[] =
3107 X { "+" , eval_cb_add },
3108 X { "-" , eval_cb_subtract },
3109 X { "*" , eval_cb_multiply },
3110 X { "/" , eval_cb_divide },
3112 X { "1+" , eval_cb_oneplus },
3113 X { "1-" , eval_cb_oneminus },
3115 X { "%" , eval_cb_modulus },
3117 X { "<" , eval_cb_lt },
3118 X { "<=" , eval_cb_lt_eq },
3119 X { ">" , eval_cb_gt },
3120 X { ">=" , eval_cb_gt_eq },
3121 X { "=" , eval_cb_eqsign },
3123 X { "and" , eval_cb_and },
3124 X { "or" , eval_cb_or },
3125 X { "not" , eval_cb_not },
3126 X { "null" , eval_cb_not },
3128 X { "atom" , eval_cb_atom },
3129 X { "car" , eval_cb_car },
3130 X { "cdr" , eval_cb_cdr },
3131 X { "cons" , eval_cb_cons },
3132 X { "list" , eval_cb_list },
3133 X { "equal" , eval_cb_equal },
3135 X { "if" , eval_cb_if },
3136 X { "unless" , eval_cb_unless },
3137 X { "when" , eval_cb_when },
3138 X { "cond" , eval_cb_cond },
3139 X { "select" , eval_cb_select },
3141 X { "princ" , eval_cb_princ },
3142 X { "terpri" , eval_cb_terpri },
3144 X { "eval" , eval_cb_eval },
3145 X { "prog1" , eval_cb_prog1 },
3146 X { "prog2" , eval_cb_prog2 },
3147 X { "progn" , eval_cb_progn },
3149 X { "set" , eval_cb_set },
3150 X { "setq" , eval_cb_setq },
3151 X { "setf" , eval_cb_setq },
3152 X { "enum" , eval_cb_enum },
3154 X { "defun" , eval_cb_defun },
3156 X { "gc" , eval_cb_nothing },
3157 X { "garbage-collect" , eval_cb_nothing },
3163 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3164 \subsection {Evaluator Callbacks}
3165 \label{sec:evaluatorcallbacks}
3167 These callbacks will get the raw branch for which they should process.
3168 The first element on the list is the keyword for which we were called.
3169 The remaining elements are the list parameters to be used. Each
3170 parameter used should get evaulated using the [[evaluateNode()]]
3173 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3174 \subsubsection{ [[nothing]] }
3176 This is a dummy function that does nothing, and always returns "T". This
3177 is for unimplemented placeholder methods like ``gc'' for example.
3179 <<eval cb nothing proto>>=
3180 X le * eval_cb_nothing( const int argc, le * branch )
3182 <<eval cb nothing implementation>>=
3183 X <<eval cb nothing proto>>
3185 X return( leNew( "T" ));
3190 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3191 \subsubsection{ [[set helper]] }
3193 This is basically a method that embodies both the functionalities of
3194 [[setq]] and [[set]], to minimize code space.
3196 Pass in one of these two values to select the functionality set.
3197 <<Eval cb set helper enum>>=
3198 enum setfcn { S_SET, S_SETQ };
3201 <<Eval cb set helper proto>>=
3202 X le * eval_cb_set_helper(
3203 X enum setfcn function,
3208 <<Eval cb set helper implementation>>=
3209 X <<Eval cb set helper proto>>
3215 X if (!branch || argc < 3) return( leNew( "NIL" ) );
3217 X current = branch->list_next;
3220 X if (!current->list_next)
3222 X newvalue = leNew( "NIL" );
3224 X newvalue = evaluateNode(current->list_next);
3227 X if ( function == S_SET )
3228 X newkey = evaluateNode(current);
3230 X mainVarList = variableSet(
3232 X ( function == S_SET )? newkey->data : current->data,
3236 X if ( function == S_SET )
3239 X if (!current->list_next)
3243 X current = current->list_next->list_next;
3246 X return( leDup(newvalue) );
3250 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3251 \subsubsection{ [[set]] }
3253 The basic param list for [[set]] is; [[(set key value key value
3254 X...)]]. So we need to skip to the next element on the list, then start
3255 setting variables. both the key and variable will get evaluated.
3257 <<Eval cb set proto>>=
3258 X le * eval_cb_set( const int argc, le * branch )
3260 <<Eval cb set implementation>>=
3261 X <<Eval cb set proto>>
3263 X return( eval_cb_set_helper( S_SET, argc, branch ) );
3268 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3269 \subsubsection{ [[setq]] }
3271 The basic param list for [[setq]] is; [[(setq key value key value
3272 X...)]]. So we need to skip to the next element on the list, then start
3273 setting variables. The key portion of this pairing is not evaluated,
3276 <<Eval cb setq proto>>=
3277 X le * eval_cb_setq( const int argc, le * branch )
3279 <<Eval cb setq implementation>>=
3280 X <<Eval cb setq proto>>
3282 X return( eval_cb_set_helper( S_SETQ, argc, branch ) );
3286 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3287 \subsubsection{ [[enum]] }
3289 Enum will create a series of variables, incrementing their value for each
3290 one encountered. Any lists will NOT be evaluated, but rather skipped
3291 for now. (Since this is not a valid Common Lisp method, I can implement
3292 it however I like. hehehe.) The final value will be returned.
3294 ie: (enum a b c d e)
3295 will result in (a = 0), (b = 1) ... (e = 4), and will return '4'.
3297 <<Eval cb enum proto>>=
3298 X le * eval_cb_enum( const int argc, le * branch )
3300 <<Eval cb enum implementation>>=
3301 X <<Eval cb enum proto>>
3308 X if (!branch || argc < 2) return( leNew( "NIL" ) );
3310 X current = branch->list_next;
3313 X if (current->data)
3315 X sprintf( value, "%d", ++count);
3317 X mainVarList = variableSetString(
3323 X current = current->list_next;
3327 X return( leNew( "NIL" ) );
3329 X return( evalCastIntToLe(count) );
3334 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3335 \subsubsection{ cumehelper }
3337 Since Add, Subtract, Multiply and Divide are all basically the same
3338 function, with only a small difference, we will abstract out their
3339 commonalities into this ``cume helper'' method. It basically
3340 accumulates in whichever style is defined by the [[function]]
3341 parameter. It starts off by setting the accumulator to the [[value]]
3342 passed in, and works along the [[branch]] passed in. The result value
3345 To define which mathematical function needs to be done, we will pass in
3346 the [[function]] as one of the following enum values. It is pretty
3347 evident which one specifies what.
3349 <<Eval cb cume helper enum>>=
3350 enum cumefcn { C_NONE, C_ADD, C_SUBTRACT, C_MULTIPLY, C_DIVIDE };
3353 <<Eval cb cume helper proto>>=
3356 X enum cumefcn function,
3362 The basic methodology here is that while there is a parameter on the
3363 list, we evaluate it, then cast it to an integer, then accumulate it
3364 onto [[value]]. Once we've run out of parameters, return the
3367 <<Eval cb cume helper implementation>>=
3368 X <<Eval cb cume helper proto>>
3372 X le * temp = branch;
3375 X if (!branch) return( 0 );
3379 X value_le = evaluateNode(temp);
3380 X newvalue = evalCastLeToInt(value_le);
3386 X value += newvalue;
3389 X case( C_SUBTRACT ):
3390 X value -= newvalue;
3393 X case( C_MULTIPLY ):
3394 X value *= newvalue;
3398 X value /= newvalue;
3402 X temp = temp->list_next;
3409 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3410 \subsubsection{ addition }
3412 This handles lists such as [[(+ 2 3)]], [[(+ 9 foo)]], and so on.
3413 We simply check to see how many parameters are passed in, and if
3414 it is valid for our purposes, call the above [[cume helper]].
3416 <<Eval cb add proto>>=
3417 X le * eval_cb_add( const int argc, le * branch )
3419 <<Eval cb add implementation>>=
3420 X <<Eval cb add proto>>
3422 X char * returnval = NULL;
3424 X if (!branch || argc < 2) return( leNew( "NIL" ) );
3426 X return( evalCastIntToLe(
3438 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3439 \subsubsection{ subtraction }
3441 This handles lists such as [[(- 2 3)]], [[(- 9 foo)]], and so on.
3442 We simply check to see how many parameters are passed in, and if
3443 it is valid for our purposes, call the above [[cume helper]].
3445 We have to do an extra check in here to handle items such as [[(- 2)]]
3446 where we just need to multiply the parameter by negative one and return
3449 <<Eval cb subtract proto>>=
3450 X le * eval_cb_subtract( const int argc, le * branch )
3452 <<Eval cb subtract implementation>>=
3453 X <<Eval cb subtract proto>>
3455 X int firstitem = 0;
3459 X if (!branch || argc < 2) return( leNew( "NIL" ) );
3461 X lefirst = evaluateNode( branch->list_next );
3462 X firstitem = evalCastLeToInt( lefirst );
3463 X leWipe( lefirst );
3467 X return( evalCastIntToLe( -1 * firstitem) );
3470 X return( evalCastIntToLe(
3474 X branch->list_next->list_next
3480 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3481 \subsubsection{ multiplication }
3483 This handles lists such as [[(* 2 3)]], [[(* 9 foo)]], and so on. We
3484 simply check to see how many parameters are passed in, and if it is
3485 valid for our purposes, call the above [[cume helper]].
3487 Since we're accumulating multiplications, we need to start this one off
3488 with a [[1]] rather than the [[0]] above, since we must start off the
3489 accumulator with the multiplicative identity, and not the addative
3492 <<Eval cb multiply proto>>=
3493 X le * eval_cb_multiply( const int argc, le * branch )
3495 <<Eval cb multiply implementation>>=
3496 X <<Eval cb multiply proto>>
3498 X if (!branch || argc < 2) return( leNew( "NIL" ) );
3500 X return( evalCastIntToLe(
3512 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3513 \subsubsection{ divide }
3515 This handles lists such as [[(/ 2 3)]], [[(/ 9 foo)]], and so on.
3516 We simply check to see how many parameters are passed in, and if
3517 it is valid for our purposes, call the above [[cume helper]].
3519 Since we're accumulating divisions, we need to start this one off
3520 with the first number passed in as the initial value.
3522 One thing that we do not currently support is [[(/ 2)]] which should
3523 yield [[0.5]] or ``one half''... inverses of numbers. Since all math
3524 is currently integer based, and not real based, it wouldn't make sense
3525 to implement this yet.
3527 <<Eval cb divide proto>>=
3528 X le * eval_cb_divide( const int argc, le * branch )
3530 <<Eval cb divide implementation>>=
3531 X <<Eval cb divide proto>>
3533 X int firstitem = 0;
3535 X if (!branch || argc < 2) return( leNew( "NIL" ) );
3537 X lefirst = evaluateNode( branch->list_next );
3538 X firstitem = evalCastLeToInt( lefirst );
3539 X leWipe( lefirst );
3541 X return( evalCastIntToLe(
3545 X branch->list_next->list_next
3552 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3553 \subsubsection{ oneplus }
3555 This handles lists such as [[(1+ 3)]], [[(1+ foo)]], and so on.
3557 This basically just converts the evaluated parameter to an integer,
3558 increments it, then returns that value back to the caller.
3560 <<Eval cb oneplus proto>>=
3561 X le * eval_cb_oneplus( const int argc, le * branch )
3563 <<Eval cb oneplus implementation>>=
3564 X <<Eval cb oneplus proto>>
3569 X if (!branch || argc < 2) return( leNew( "NIL" ) );
3571 X retle = evaluateNode( branch->list_next );
3572 X value = evalCastLeToInt( retle );
3575 X return( evalCastIntToLe(value + 1) );
3579 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3580 \subsubsection{ oneminus }
3582 This handles lists such as [[(1- 3)]], [[(1- foo)]], and so on.
3584 This basically just converts the evaluated parameter to an integer,
3585 decrements it, then returns an atom containing that value back to the
3588 <<Eval cb oneminus proto>>=
3589 X le * eval_cb_oneminus( const int argc, le * branch )
3591 <<Eval cb oneminus implementation>>=
3592 X <<Eval cb oneminus proto>>
3597 X if (!branch || argc < 2) return( leNew( "NIL" ) );
3599 X retle = evaluateNode( branch->list_next );
3600 X value = evalCastLeToInt( retle );
3603 X return( evalCastIntToLe(value - 1) );
3609 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3610 \subsubsection{ \%: modulus }
3612 This handles lists such as [[(\% 2 3)]], [[(\% 9 foo)]], and so on.
3614 We simply convert the two evaluated parameters to integers, then return
3615 an atom with the modulus of those numbers back to the caller.
3617 <<Eval cb modulus proto>>=
3618 X le * eval_cb_modulus( const int argc, le * branch )
3620 <<Eval cb modulus implementation>>=
3621 X <<Eval cb modulus proto>>
3624 X int value1, value2;
3626 X if (!branch || argc != 3) return( leNew( "NIL" ) );
3628 X letemp = evaluateNode( branch->list_next );
3629 X value1 = evalCastLeToInt( letemp );
3632 X letemp = evaluateNode( branch->list_next->list_next );
3633 X value2 = evalCastLeToInt( letemp );
3636 X return( evalCastIntToLe ( value1 % value2 ) );
3640 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3641 \subsubsection{ lt: A less than B}
3643 This handles lists such as [[(< 2 3)]], [[(< 9 foo)]], and so on.
3645 The values of the two parameters are evaluated, then compared with
3646 eachother. If the first is less than the second, a ``[[T]]'' atom
3647 is returned, otherwise a ``[[NIL]]'' atom is returned.
3649 <<Eval cb lt proto>>=
3650 X le * eval_cb_lt( const int argc, le * branch )
3652 <<Eval cb lt implementation>>=
3653 X <<Eval cb lt proto>>
3656 X int value1, value2;
3658 X if (!branch || argc != 3 ) return( leNew( "NIL" ) );
3660 X letemp = evaluateNode( branch->list_next );
3661 X value1 = evalCastLeToInt( letemp );
3664 X letemp = evaluateNode( branch->list_next->list_next );
3665 X value2 = evalCastLeToInt( letemp );
3668 X return( leNew ( (value1 < value2 )?"T":"NIL" ) );
3672 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3673 \subsubsection{ lteq: A less than or equal to B}
3675 This handles lists such as [[(<= 2 3)]], [[(<= 9 foo)]], and so on.
3677 The values of the two parameters are evaluated, then compared with
3678 eachother. If the first is less than or equal to the second, a
3679 ``[[T]]'' atom is returned, otherwise a ``[[NIL]]'' atom is returned.
3681 <<Eval cb lt eq proto>>=
3682 X le * eval_cb_lt_eq( const int argc, le * branch )
3684 <<Eval cb lt eq implementation>>=
3685 X <<Eval cb lt eq proto>>
3688 X int value1, value2;
3690 X if (!branch || argc != 3 ) return( leNew( "NIL" ) );
3692 X letemp = evaluateNode( branch->list_next );
3693 X value1 = evalCastLeToInt( letemp );
3696 X letemp = evaluateNode( branch->list_next->list_next );
3697 X value2 = evalCastLeToInt( letemp );
3700 X return( leNew ( (value1 <= value2 )?"T":"NIL" ) );
3704 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3705 \subsubsection{ gt: A greater than B}
3707 This handles lists such as [[(> 2 3)]], [[(> 9 foo)]], and so on.
3709 The values of the two parameters are evaluated, then compared with
3710 eachother. If the first is greater than the second, a ``[[T]]'' atom
3711 is returned, otherwise a ``[[NIL]]'' atom is returned.
3713 <<Eval cb gt proto>>=
3714 X le * eval_cb_gt( const int argc, le * branch )
3716 <<Eval cb gt implementation>>=
3717 X <<Eval cb gt proto>>
3720 X int value1, value2;
3722 X if (!branch || argc != 3 ) return( leNew( "NIL" ) );
3724 X letemp = evaluateNode( branch->list_next );
3725 X value1 = evalCastLeToInt( letemp );
3728 X letemp = evaluateNode( branch->list_next->list_next );
3729 X value2 = evalCastLeToInt( letemp );
3732 X return( leNew ( (value1 > value2 )?"T":"NIL" ) );
3736 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3737 \subsubsection{ gteq: A greater than or equal to B}
3739 This handles lists such as [[(>= 2 3)]], [[(>= 9 foo)]], and so on.
3741 The values of the two parameters are evaluated, then compared with
3742 eachother. If the first is greater than or equal to the second, a
3743 ``[[T]]'' atom is returned, otherwise a ``[[NIL]]'' atom is returned.
3745 <<Eval cb gt eq proto>>=
3746 X le * eval_cb_gt_eq( const int argc, le * branch )
3748 <<Eval cb gt eq implementation>>=
3749 X <<Eval cb gt eq proto>>
3752 X int value1, value2;
3754 X if (!branch || argc != 3 ) return( leNew( "NIL" ) );
3756 X letemp = evaluateNode( branch->list_next );
3757 X value1 = evalCastLeToInt( letemp );
3760 X letemp = evaluateNode( branch->list_next->list_next );
3761 X value2 = evalCastLeToInt( letemp );
3764 X return( leNew ( (value1 >= value2 )?"T":"NIL" ) );
3768 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3769 \subsubsection{ eqsign: A equal to B}
3771 This handles lists such as [[(= 2 3)]], [[(= 9 foo)]], and so on.
3773 The values of the two parameters are evaluated, then compared with
3774 eachother. If the first is equal to the second, a ``[[T]]'' atom is
3775 returned, otherwise a ``[[NIL]]'' atom is returned.
3777 <<Eval cb eqsign proto>>=
3778 X le * eval_cb_eqsign( const int argc, le * branch )
3780 <<Eval cb eqsign implementation>>=
3781 X <<Eval cb eqsign proto>>
3784 X int value1, value2;
3786 X if (!branch || argc != 3 ) return( leNew( "NIL" ) );
3788 X letemp = evaluateNode( branch->list_next );
3789 X value1 = evalCastLeToInt( letemp );
3792 X letemp = evaluateNode( branch->list_next->list_next );
3793 X value2 = evalCastLeToInt( letemp );
3796 X return( leNew ( (value1 == value2 )?"T":"NIL" ) );
3800 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3801 \subsubsection{ and }
3803 This handles lists such as [[(and A B)]], [[(and A (...))]], and so on.
3805 Evaluate all of the arguments until one of them yields a [[NIL]], then
3806 return [[NIL]]. The remaining parameters are not evaluated. If none
3807 evaluates to [[NIL]], then the last one's evaluation is returned.
3809 <<Eval cb and proto>>=
3810 X le * eval_cb_and( const int argc, le * branch )
3812 <<Eval cb and implementation>>=
3813 X <<Eval cb and proto>>
3816 X le * result = NULL;
3817 X if (!branch || argc < 2 ) return( leNew( "NIL" ));
3819 X temp = branch->list_next;
3822 X if( result ) leWipe( result );
3824 X result = evaluateNode(temp);
3827 X if (!strcmp ( result->data, "NIL" ))
3832 X temp = temp->list_next;
3838 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3839 \subsubsection{ or }
3841 Evaluate all of the arguments until one of them yields a non-[[NIL]], then
3842 return their value. The remaining arguments are not evaluated. If all
3843 parameters evaluate to [[NIL]], then a [[NIL]] atom is returned.
3845 <<Eval cb or proto>>=
3846 X le * eval_cb_or( const int argc, le * branch )
3848 <<Eval cb or implementation>>=
3849 X <<Eval cb or proto>>
3852 X le * result = NULL;
3853 X if (!branch || argc < 2 ) return( leNew( "NIL" ));
3855 X temp = branch->list_next;
3858 X if( result ) leWipe( result );
3860 X result = evaluateNode(temp);
3863 X if (strcmp ( result->data, "NIL" ))
3868 X temp = temp->list_next;
3874 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3875 \subsubsection{ not }
3877 If the evaluated parameter yields a true value (perhaps [[T]]) then return
3878 a [[NIL]] atom. If the evaluated parameter yields a [[NIL]], then we return
3881 <<Eval cb not proto>>=
3882 X le * eval_cb_not( const int argc, le * branch )
3884 <<Eval cb not implementation>>=
3885 X <<Eval cb not proto>>
3887 X le * result = NULL;
3888 X if (!branch || argc != 2 ) return( leNew( "NIL" ));
3890 X result = evaluateNode(branch->list_next);
3894 X if (!strcmp (result->data, "NIL" ))
3897 X return( leNew( "T" ) );
3900 X return( leNew( "NIL" ) );
3902 X } else if (result->branch) {
3904 X return( leNew( "NIL" ) );
3908 X return( leNew( "T" ));
3912 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3913 \subsubsection{ atom }
3915 If the evaluated parameter is a list, return a [[NIL]] atom, otherwise
3916 return a [[T]] atom.
3918 <<Eval cb atom proto>>=
3919 X le * eval_cb_atom( const int argc, le * branch )
3921 <<Eval cb atom implementation>>=
3922 X <<Eval cb atom proto>>
3924 X le * result = NULL;
3925 X if (!branch || argc != 2 ) return( leNew( "NIL" ));
3927 X result = evaluateNode(branch->list_next);
3929 X if (countNodes(result) == 1)
3932 X return( leNew( "T" ) );
3934 X return( leNew( "NIL" ) );
3939 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3940 \subsubsection{ car }
3942 Return the topmost atom of the list passed in. If an atom was passed in,
3943 then we simply return it.
3945 There is some extra magic in here to dereference nesting by one layer
3946 since we're returning the atoms from the passed in list, rather than
3947 just sublists, like what CDR does.
3949 <<Eval cb car proto>>=
3950 X le * eval_cb_car( const int argc, le * branch )
3952 <<Eval cb car implementation>>=
3953 X <<Eval cb car proto>>
3955 X le * result = NULL;
3957 X if (!branch || argc != 2 ) return( leNew( "NIL" ));
3959 X result = evaluateNode(branch->list_next);
3961 X if( result == NULL ) return( leNew( "NIL" ) );
3963 X if (countNodes(result) <= 1)
3965 X if (result->branch)
3968 X result = result->branch;
3969 X temp->branch = NULL;
3975 X result->list_next->list_prev = NULL;
3976 X leWipe( result->list_next );
3977 X result->list_next = NULL;
3979 X if (result->branch)
3982 X result = result->branch;
3983 X temp->branch = NULL;
3991 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3992 \subsubsection{ cdr }
3994 Return all but the topmost atom of the passed in list after it has been
3995 evaluated. If the list contains just one entry, we instead return a
3998 <<Eval cb cdr proto>>=
3999 X le * eval_cb_cdr( const int argc, le * branch )
4001 <<Eval cb cdr implementation>>=
4002 X <<Eval cb cdr proto>>
4004 X le * result = NULL;
4006 X if (!branch || argc != 2 ) return( leNew( "NIL" ));
4008 X result = evaluateNode(branch->list_next);
4010 X if( result == NULL ) return( leNew( "NIL" ) );
4012 X if (result == NULL || countNodes(result) == 1)
4014 X return( leNew( "NIL" ) );
4018 X temp->list_next->list_prev = NULL;
4019 X result = result->list_next;
4021 X temp->list_next = NULL;
4030 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4031 \subsubsection{ cons }
4033 Evaluate the two parameters, then add the first parameter, an atom, onto
4034 the second parameter, a list. Cons does the opposite of CAR and CDR.
4036 <<Eval cb cons proto>>=
4037 X le * eval_cb_cons( const int argc, le * branch )
4039 <<Eval cb cons implementation>>=
4040 X <<Eval cb cons proto>>
4042 X le * result1 = NULL;
4043 X le * result2 = NULL;
4045 X if (!branch || argc != 3 ) return( leNew( "NIL" ));
4047 X result1 = evaluateNode(branch->list_next);
4048 X if ( result1 == NULL ) return( leNew( "NIL" ));
4050 X result2 = evaluateNode(branch->list_next->list_next);
4051 X if ( result2 == NULL )
4053 X leWipe( result1 );
4054 X return( leNew( "NIL" ));
4057 X if ( countNodes(result1) > 1 )
4059 X le * temp = leNew( NULL );
4060 X temp->branch = result1;
4063 X result1->list_next = result2;
4064 X result2->list_prev = result1;
4066 X return( result1 );
4070 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4071 \subsubsection{ list }
4073 Return a list generated by joining all of the passed in parameters,
4074 after evaluating them. Each of the parameters are treated like atoms
4075 being joined into the final list.
4077 <<Eval cb list proto>>=
4078 X le * eval_cb_list( const int argc, le * branch )
4080 <<Eval cb list implementation>>=
4081 X <<Eval cb list proto>>
4083 X le * currelement = NULL;
4084 X le * finaltree = NULL;
4085 X le * lastadded = NULL;
4086 X le * result = NULL;
4088 X if (!branch) return( leNew( "NIL" ));
4090 X currelement = branch->list_next;
4091 X while (currelement)
4093 X result = evaluateNode(currelement);
4094 X if ( result == NULL )
4096 X leWipe( finaltree );
4097 X return( leNew( "NIL" ));
4100 X if( countNodes(result) > 1)
4102 X le * temp = leNew( NULL );
4103 X temp->branch = result;
4109 X finaltree = result;
4110 X lastadded = result;
4112 X lastadded->list_next = result;
4113 X result->list_prev = lastadded;
4114 X lastadded = result;
4118 X currelement = currelement->list_next;
4123 X return( leNew( "NIL" ));
4125 X return( finaltree );
4130 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4131 \subsubsection{ equal: similar objects? }
4133 This is a helper function for the following [[equal]] callback.
4134 This gets recursively called by itself. It basically traverses
4135 the [[list1]] tree, comparing it to [[list2]], making sure it has
4136 the same structure and elements in it.
4138 If the lists are the same, it returns a [[1]]. If they differ, it will
4142 <<Eval cb equal helper proto>>=
4143 X int eval_cb_lists_same( le * list1, le * list2 )
4145 <<Eval cb equal helper implementation>>=
4146 X <<Eval cb equal helper proto>>
4148 X if (!list1 && !list2) return( 1 );
4152 X /* if list2 ended prematurely, fail */
4153 X if (list2 == NULL)
4158 X /* if one has data and the other doesn't, fail */
4159 X if ( (list1->data && ! list2->data)
4160 X || (list2->data && ! list1->data))
4165 X /* if the data is different, fail */
4166 X if (list1->data && list2->data)
4168 X if (strcmp( list1->data, list2->data ))
4174 X /* if one is quoted and the other isn't, fail */
4175 X if (list1->quoted != list2->quoted)
4180 X /* if their branches aren't the same, fail */
4181 X if (!eval_cb_lists_same( list1->branch, list2->branch ))
4186 X /* try the next in the list */
4187 X list1 = list1->list_next;
4188 X list2 = list2->list_next;
4191 X /* if list2 goes on, fail */
4201 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4202 \subsubsection{ equal: compare two lists }
4204 Evaluate the two parameters, and compare them to see if they have the
4205 same structure and elements. We will just call the above [[...same()]]
4206 method which will return a [[1]] if they are the same.
4208 We then will return a [[T]] atom if they were the same, and a [[NIL]]
4209 if they were different.
4211 <<Eval cb equal proto>>=
4212 X le * eval_cb_equal( const int argc, le * branch )
4214 <<Eval cb equal implementation>>=
4215 X <<Eval cb equal proto>>
4218 X le * list1 = NULL;
4219 X le * list2 = NULL;
4222 X if (!branch || argc != 3 ) return( leNew( "NIL" ) );
4224 X list1 = evaluateNode( branch->list_next );
4225 X list2 = evaluateNode( branch->list_next->list_next );
4227 X retval = eval_cb_lists_same( list1, list2 );
4232 X return( leNew ( (retval == 1) ? "T" : "NIL" ) );
4236 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4237 \subsubsection{ if }
4239 The standard conditional. (if (conditional) (then-block) (else-block))
4241 [[if]] will evaluate the first parameter. If it evaluates to the [[T]]
4242 atom, then [[if]] will then evaluate the following [[then]] block. If
4243 it was non-[[T]], then it will evaluate the [[else]] block.
4245 <<Eval cb if proto>>=
4246 X le * eval_cb_if( const int argc, le * branch )
4248 <<Eval cb if implementation>>=
4249 X <<Eval cb if proto>>
4251 X le * retcond = NULL;
4252 X le * retblock = NULL;
4254 X if (!branch || argc < 3 || argc > 4) return( leNew( "NIL" ));
4257 X retcond = evaluateNode(branch->list_next);
4259 X if (!strcmp ( retcond->data, "NIL" ))
4262 X if (argc == 3) /* no else */
4263 X return( retcond );
4265 X leWipe( retcond );
4266 X return( evaluateNode( branch->list_next->list_next->list_next ) );
4270 X leWipe( retcond );
4271 X return( evaluateNode(branch->list_next->list_next) );
4276 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4277 \subsubsection{ when and unless helper }
4279 This will evaluate the first parameter.
4281 If it evaluates to [[NIL]] and the [[which]] parameter is set to
4282 [[WU_UNLESS]], OR it evaluates to non-[[NIL]] the [[which]] parameter
4283 is set to [[WU_WHEN]] then the body blocks get evaluated, otherwise a
4284 [[NIL]] atom is returned. The final body block to get evaluated has
4287 <<Eval cb when unless helper enum>>=
4288 enum whenunless { WU_WHEN, WU_UNLESS };
4291 <<Eval cb when unless proto>>=
4293 X eval_cb_whenunless_helper(
4294 X enum whenunless which,
4299 <<Eval cb when unless implementation>>=
4300 X <<Eval cb when unless proto>>
4302 X le * retval = NULL;
4303 X le * retblock = NULL;
4304 X le * trythis = NULL;
4306 X if (!branch || argc < 3 ) return( leNew( "NIL" ));
4309 X retval = evaluateNode(branch->list_next);
4311 X if ( which == WU_UNLESS )
4313 X /* unless - it wasn't true... bail */
4314 X if ( strcmp( retval->data, "NIL" ))
4317 X return( leNew( "NIL" ) );
4320 X /* when: it wasn't false... bail */
4321 X if ( !strcmp( retval->data, "NIL" ))
4327 X trythis = branch->list_next->list_next;
4330 X if (retval) leWipe( retval );
4332 X retval = evaluateNode(trythis);
4333 X trythis = trythis->list_next;
4340 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4341 \subsubsection{ unless }
4343 (unless (conditional) (block) (block) ... )
4345 [[unless]] will evaluate the first parameter. If it evaluates to [[NIL]]
4346 then the body blocks get evaluated, otherwise a [[NIL]] atom is returned.
4347 The final body block to get evaluated has its value returned.
4349 <<Eval cb unless proto>>=
4350 X le * eval_cb_unless( const int argc, le * branch )
4352 <<Eval cb unless implementation>>=
4353 X <<Eval cb unless proto>>
4355 X return( eval_cb_whenunless_helper(
4363 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4364 \subsubsection{ when }
4366 (when (conditional) (block) (block) ... )
4368 [[when]] evaluates the first parameter. If it returns a non-[[NIL]] value,
4369 then the remaining body blocks get evaluated, otherwise it will return
4370 a [[NIL]] atom. The last conditional's value gets returned otherwise.
4372 This is basically the same as [[unless]] but with a reversed conditional.
4373 This might be integrated with it into a helper function eventually.
4375 <<Eval cb when proto>>=
4376 X le * eval_cb_when( const int argc, le * branch )
4378 <<Eval cb when implementation>>=
4379 X <<Eval cb when proto>>
4381 X return( eval_cb_whenunless_helper(
4388 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4389 \subsubsection{ cond }
4391 (cond ((conditional) (block) ... )
4392 X ((conditional) (block) ... )
4393 X ((conditional) (block) ... )
4396 [[cond]] checks each conditional in turn. The first one returning
4397 non-[[NIL]] gets its body blocks evaluated. The last block related to
4398 that condtional gets its value returned.
4400 If the succeeding conditional has no block, the return value of the
4401 conditional is returned.
4403 If no conditional satisfies it, a [[NIL]] atom will be returned.
4405 <<Eval cb cond proto>>=
4406 X le * eval_cb_cond( const int argc, le * branch )
4408 <<Eval cb cond implementation>>=
4409 X <<Eval cb cond proto>>
4411 X le * retval = NULL;
4412 X le * retblock = NULL;
4413 X le * trythis = NULL;
4414 X le * tryblock = NULL;
4417 X if (!branch || argc < 2 ) return( leNew( "NIL" ));
4419 X trythis = branch->list_next;
4422 X newargc = countNodes( trythis->branch );
4423 X if (newargc == 0) continue;
4426 X if (retval) leWipe(retval);
4427 X retval = evaluateNode(trythis->branch);
4429 X if ( strcmp(retval->data, "NIL" ))
4436 X tryblock = trythis->branch->list_next;
4439 X if (retblock) leWipe(retblock);
4442 X retblock = evaluateNode(tryblock);
4443 X tryblock = tryblock->list_next;
4445 X return( retblock );
4448 X trythis = trythis->list_next;
4454 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4455 \subsubsection{ select }
4457 (select (expression)
4459 X (value2 <body2>) ...
4463 This acts like the 'switch' or 'case' statements in other languages. It
4464 will evaluate the expression, then look for that value in the list of items
4465 remaining. When it finds the right value, that body block is executed.
4467 If there is none found, the value from the expression is returned.
4469 The last return value from the from the body block gets returned.
4471 <<Eval cb select proto>>=
4472 X le * eval_cb_select( const int argc, le * branch )
4474 <<Eval cb select implementation>>=
4475 X <<Eval cb select proto>>
4479 X if (argc < 2) return( leNew( "NIL" ));
4481 X branch = branch->list_next;
4482 X result = evaluateNode(branch);
4484 X branch = branch->list_next;
4487 X if( branch->branch )
4489 X le * check = branch->branch;
4490 X if (check && check->data
4491 X && (!strcmp( check->data, result->data )))
4493 X /* we're in the right place, evaluate and return */
4494 X le * computelist = check->list_next;
4495 X while( computelist )
4498 X result = evaluateNode( computelist );
4499 X computelist = computelist->list_next;
4505 X branch = branch->list_next;
4514 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4515 \subsubsection{ princ }
4517 Simply print to standard output the parameters passed in.
4519 <<Eval cb princ proto>>=
4520 X le * eval_cb_princ( const int argc, le * branch )
4522 <<Eval cb princ implementation>>=
4523 X <<Eval cb princ proto>>
4526 X le * retblock = NULL;
4527 X if (!branch || argc < 1 ) return( leNew( "NIL" ));
4529 X thisnode = branch->list_next;
4532 X if (retblock) leWipe( retblock );
4533 X retblock = evaluateNode(thisnode);
4534 X leDumpReformat(stdout, retblock);
4536 X thisnode = thisnode->list_next;
4538 X return( retblock );
4542 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4543 \subsubsection{ terpri }
4545 Simply print to standard output a newline characater.
4547 <<Eval cb terpri proto>>=
4548 X le * eval_cb_terpri( const int argc, le * branch )
4550 <<Eval cb terpri implementation>>=
4551 X <<Eval cb terpri proto>>
4554 X le * retblock = NULL;
4555 X if (!branch || argc != 1 ) return( leNew( "NIL" ));
4558 X return( leNew( "NIL" ) );
4563 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4564 \subsubsection{ eval }
4566 [[eval]] evaluates its parameter, and returns the result from the
4567 evaluation. It must basically do a double evaluation due to the way
4568 things are stored internally.
4570 <<Eval cb eval proto>>=
4571 X le * eval_cb_eval( const int argc, le * branch )
4573 <<Eval cb eval implementation>>=
4574 X <<Eval cb eval proto>>
4578 X if (!branch || argc != 2 ) return( leNew( "NIL" ));
4580 X temp = evaluateNode(branch->list_next);
4581 X retval = evaluateBranch(temp);
4587 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4588 \subsubsection{ proghelper }
4590 Since the functions [[prog1]], [[prog2]] and [[progn]] are nearly identical
4591 in nature, we will use the following function to do most of their work.
4592 The only difference is that there is an extra parameter, [[returnit]].
4593 If [[returnit]] is 1, then the first code block's result gets returned.
4594 If [[returnit]] is 2, then the second code block's result gets returned.
4595 If [[returnit]] is negative, then the last code block's result gets returned.
4597 Basically, we will evaluate all body blocks passed in, and return the
4598 appropriate return list.
4600 <<Eval cb prog proto>>=
4601 X le * eval_cb_prog( const int argc, le * branch, int returnit )
4603 <<Eval cb prog implementation>>=
4604 X <<Eval cb prog proto>>
4607 X le * retval = NULL;
4608 X le * tempval = NULL;
4610 X if (!branch || argc < (returnit +1) ) return( leNew( "NIL" ));
4612 X curr = branch->list_next;
4617 X if ( tempval ) leWipe (tempval);
4618 X tempval = evaluateNode( curr );
4620 X if (current == returnit)
4621 X retval = leDup( tempval );
4623 X curr = curr->list_next;
4626 X if (!retval) retval = tempval;
4632 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4633 \subsubsection{ prog1 }
4635 Using the above helper, we want to evaluate all code blocks, returning
4636 the return value from the first block.
4638 <<Eval cb prog1 proto>>=
4639 X le * eval_cb_prog1( const int argc, le * branch )
4641 <<Eval cb prog1 implementation>>=
4642 X <<Eval cb prog1 proto>>
4644 X return( eval_cb_prog( argc, branch, 1 ));
4648 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4649 \subsubsection{ prog2 }
4651 Using the above helper, we want to evaluate all code blocks, returning
4652 the return value from the second block.
4654 <<Eval cb prog2 proto>>=
4655 X le * eval_cb_prog2( const int argc, le * branch )
4657 <<Eval cb prog2 implementation>>=
4658 X <<Eval cb prog2 proto>>
4660 X return( eval_cb_prog( argc, branch, 2 ));
4664 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4665 \subsubsection{ progn }
4667 Using the above helper, we want to evaluate all code blocks, returning
4668 the return value from the final block.
4670 <<Eval cb progn proto>>=
4671 X le * eval_cb_progn( const int argc, le * branch )
4673 <<Eval cb progn implementation>>=
4674 X <<Eval cb progn proto>>
4676 X return( eval_cb_prog( argc, branch, -1 ));
4681 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4682 \subsubsection{ defun }
4684 This stores away a function to be used later. The format for this
4685 is: (defun funcname (parameters) (bodyblock))
4687 None of this gets evaluated when it is called here. It will get
4688 evaulated later on if they get called. We will just store it
4691 The funcname is returned as an atom.
4693 The parameters for this function are not the same as variables in the
4694 system. They are local variables of local scope, and will override any
4695 global variables when the function is called later.
4697 <<Eval cb defun proto>>=
4698 X le * eval_cb_defun( const int argc, le * branch )
4700 <<Eval cb defun implementation>>=
4701 X <<Eval cb defun proto>>
4704 X le * retblock = NULL;
4705 X if (!branch || argc < 4 ) return( leNew( "NIL" ));
4707 X if ( !branch->list_next->data ) return( leNew( "NIL" ));
4709 X defunList = variableSet(
4711 X branch->list_next->data,
4712 X branch->list_next->list_next
4715 X return( leNew( branch->list_next->data ));
4722 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4723 \subsection {Utility methods}
4724 \label{sec:utilitymethods}
4726 We need a few utility functions to help us do all of the above work. Those
4727 utilities follow. They are [[countNodes]], [[evalCastLeToInt]] and
4728 [[evalCastIntToLe]].
4731 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4732 \subsubsection{ [[countNodes()]] }
4734 This simply takes in a branch and returns the number of [[le]] nodes
4735 along its primary list. (Through the [[list next]] pointer). Empty
4736 lists will return [[0]]. This is just a simple iterator, traversing the list.
4738 <<Eval utility counter proto>>=
4739 X int countNodes(le * branch)
4741 <<Eval utility counter implementation>>=
4742 X <<Eval utility counter proto>>
4749 X branch = branch->list_next;
4756 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4757 \subsubsection{cast LE To Int}
4759 This is a simple 'cast' function which takes in a [[le]] atom, converts
4760 its data to an integer using the standard [[atoi()]] call. That value
4763 <<Eval cast le to int proto>>=
4764 X int evalCastLeToInt( const le * levalue )
4766 <<Eval cast le to int implementation>>=
4767 X <<Eval cast le to int proto>>
4769 X if (!levalue) return( 0 );
4770 X if (!levalue->data) return( 0 );
4772 X return( atoi(levalue->data) );
4777 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4778 \subsubsection{cast Int To LE}
4780 This is a simple 'cast' function which takes in an integer, and then
4781 builds a new [[le]] atom using that value as its data. That new atom
4784 <<Eval cast int to le proto>>=
4785 X le * evalCastIntToLe( int intvalue )
4787 <<Eval cast int to le implementation>>=
4788 X <<Eval cast int to le proto>>
4791 X sprintf (buffer, "%d", intvalue);
4793 X return( leNew(buffer) );
4798 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4799 \subsection {Evaluator Valves}
4800 \label{sec:evaluatorvalves}
4803 These two functions are the brains behind the interpreter. They will
4804 traverse lisp trees, and recursively evaluate each part of them. They
4805 look up values in the variable list where necessary.
4808 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4809 \subsubsection{evaluateBranch}
4811 Evaluate branch will for example evaluate all of [[(+ 3 A)]].
4813 It first looks to see if the current entry is a list. If it is,
4814 it will evaluate it to determine the keyword to use. It will then
4815 use this keyword to look up a callback in the [[evalTable]].
4816 If it was found, it will simply return what the callback returns.
4817 If no function had been called, it will try to evaluate the node
4818 using the [[evaluateNode]] function below.
4820 <<Eval evaluateBranch proto>>=
4821 X le * evaluateBranch(le * trybranch)
4824 <<Eval evaluateBranch implementation>>=
4825 X <<Eval evaluateBranch proto>>
4829 X if (!trybranch) return( NULL );
4831 X if (trybranch->branch)
4833 X keyword = evaluateBranch(trybranch->branch);
4836 X keyword = leNew( trybranch->data );
4838 X if (!keyword->data)
4840 X leWipe( keyword );
4841 X return( leNew( "NIL" ));
4844 X for ( tryit=0 ; evalTable[tryit].word ; tryit++)
4846 X if (!strcmp(evalTable[tryit].word, keyword->data))
4848 X leWipe( keyword );
4849 X return( evalTable[tryit].callback(
4850 X countNodes( trybranch ),
4856 X leWipe( keyword );
4857 X return( evaluateNode( trybranch ));
4861 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4862 \subsubsection{evaluateNode}
4864 EvaluateNode will for example evaluate just the [[A]] of [[(+ 3 A)]].
4866 It will look to see if the node has a branch. If it does, it will
4867 evaluate it using the above function. If it had been quoted, then that
4868 branch will just get returned.
4870 If it has no branch, then it will attempt to retrieve the variable with
4871 the name specified in the data. If that was unsuccessful, it will just
4872 return the data itself as an atom.
4874 <<Eval evaluateNode proto>>=
4875 X le * evaluateNode(le * node)
4878 <<Eval evaluateNode implementation>>=
4879 X <<Eval evaluateNode proto>>
4886 X if( node->quoted )
4888 X value = leDup( node->branch );
4890 X value = evaluateBranch( node->branch );
4893 X temp = variableGet( defunList, node->data );
4897 X value = evaluateDefun( temp, node->list_next );
4899 X temp = variableGet( mainVarList, node->data );
4903 X value = leDup( temp );
4906 X value = leNew( node->data );
4916 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
4917 \subsubsection{evaluateDefun}
4919 This is a tricky one. It gets called when a predefined function, set
4920 up with the ``defun'' command earlier, gets called during
4921 interpretation time.
4923 This could be done any number of ways, using a stack based system or the
4924 like for variable lists, but instead I decided to go with a macro-like
4925 pre-processing design.
4927 First both lists passed in, the function definition [[fcn]] as well as
4928 the list of new parameters [[params]] are both non-[[NULL]], and
4929 contain an equal number of parameters. If this is not the case, we
4930 instantly bail out and return a [[NIL]] atom.
4932 Next, we [[leDup]] the function, [[fcn]] into a new structure, [[function]].
4934 Now, we make two passes over this new structure. First we go through
4935 and tag each variable in [[function]] as defined with its variable
4936 list. The first parameter's occurrance in the structure gets tagged
4937 with ``[[1]]'', the second with ``[[2]]'' and so on.
4939 The second pass replaces the items tagged as ``[[1]]'' with the first
4940 parameter in the [[params]] list, ``[[2]]'' with the second in the
4941 [[params]] list, and so on.
4943 Then all we need to do is to evaluate the resulting [[function]] list,
4944 which now has all of its local variables replaced with the passed in
4945 parameters, and return that value.
4947 We do two passes to make sure that any variables in the parameter list
4948 get replaced appropriately, in case their names clash with the global
4949 variable list entries.
4951 <<Eval evaluateDefun proto>>=
4952 X le * evaluateDefun( le * fcn, le * params )
4955 <<Eval evaluateDefun implementation>>=
4956 X <<Eval evaluateDefun proto>>
4963 X /* make sure both lists exist */
4964 X if (!fcn) return( leNew( "NIL" ));
4966 X /* check for the correct number of parameters */
4967 X if (countNodes(fcn->branch) > countNodes(params))
4968 X return( leNew( "NIL" ));
4970 X /* allocate another function definition, since we're gonna hack it */
4971 X function = leDup(fcn);
4973 X /* pass 1: tag each node properly.
4974 X for each parameter: (fcn)
4975 X - look for it in the tree, tag those with the value
4978 X thisparam = fcn->branch;
4981 X leTagData(function, thisparam->data, count);
4982 X thisparam = thisparam->list_next;
4986 X /* pass 2: replace
4987 X for each parameter: (param)
4988 X - evaluate the passed in value
4989 X - replace it in the tree
4992 X thisparam = params;
4995 X result = evaluateNode( thisparam );
4996 X leTagReplace(function, count, result);
4997 X thisparam = thisparam->list_next;
5002 X /* then evaluate the resulting tree */
5003 X result = evaluateBranch( function->list_next );
5005 X /* free any space allocated */
5006 X leWipe( function );
5008 X /* return the evaluation */
5014 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5015 \subsection {eval.c}
5018 Here we build up all of the above blocks into the .c file.
5027 <<Eval lookup table>>
5029 <<Eval evaluateBranch implementation>>
5030 <<Eval evaluateNode implementation>>
5031 <<Eval evaluateDefun implementation>>
5033 <<Eval utility counter implementation>>
5035 <<Eval cast le to int implementation>>
5036 <<Eval cast int to le implementation>>
5038 <<eval cb nothing implementation>>
5039 <<Eval cb cume helper implementation>>
5040 <<Eval cb add implementation>>
5041 <<Eval cb subtract implementation>>
5042 <<Eval cb multiply implementation>>
5043 <<Eval cb divide implementation>>
5044 <<Eval cb oneplus implementation>>
5045 <<Eval cb oneminus implementation>>
5046 <<Eval cb modulus implementation>>
5048 <<Eval cb lt implementation>>
5049 <<Eval cb lt eq implementation>>
5050 <<Eval cb gt implementation>>
5051 <<Eval cb gt eq implementation>>
5052 <<Eval cb eqsign implementation>>
5054 <<Eval cb and implementation>>
5055 <<Eval cb or implementation>>
5056 <<Eval cb not implementation>>
5058 <<Eval cb atom implementation>>
5059 <<Eval cb car implementation>>
5060 <<Eval cb cdr implementation>>
5061 <<Eval cb cons implementation>>
5062 <<Eval cb list implementation>>
5063 <<Eval cb equal helper implementation>>
5064 <<Eval cb equal implementation>>
5066 <<Eval cb if implementation>>
5067 <<Eval cb when unless implementation>>
5068 <<Eval cb unless implementation>>
5069 <<Eval cb when implementation>>
5070 <<Eval cb cond implementation>>
5071 <<Eval cb select implementation>>
5073 <<Eval cb princ implementation>>
5074 <<Eval cb terpri implementation>>
5076 <<Eval cb eval implementation>>
5077 <<Eval cb prog implementation>>
5078 <<Eval cb prog1 implementation>>
5079 <<Eval cb prog2 implementation>>
5080 <<Eval cb progn implementation>>
5082 <<Eval cb set helper implementation>>
5083 <<Eval cb set implementation>>
5084 <<Eval cb setq implementation>>
5085 <<Eval cb enum implementation>>
5087 <<Eval cb defun implementation>>
5091 %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
5092 \subsection {eval.h}
5095 And we need to do the same for the header file as well.
5100 <<Eval callback typedef>>
5101 <<Eval lookup struct>>
5103 <<Eval evaluateBranch proto>>;
5104 <<Eval evaluateNode proto>>;
5105 <<Eval evaluateDefun proto>>;
5107 <<Eval utility counter proto>>;
5109 <<Eval cast le to int proto>>;
5110 <<Eval cast int to le proto>>;
5112 <<eval cb nothing proto>>;
5114 <<Eval cb cume helper enum>>
5115 <<Eval cb cume helper proto>>;
5116 <<Eval cb add proto>>;
5117 <<Eval cb subtract proto>>;
5118 <<Eval cb multiply proto>>;
5119 <<Eval cb divide proto>>;
5120 <<Eval cb oneplus proto>>;
5121 <<Eval cb oneminus proto>>;
5122 <<Eval cb modulus proto>>;
5124 <<Eval cb lt proto>>;
5125 <<Eval cb lt eq proto>>;
5126 <<Eval cb gt proto>>;
5127 <<Eval cb gt eq proto>>;
5128 <<Eval cb eqsign proto>>;
5130 <<Eval cb and proto>>;
5131 <<Eval cb or proto>>;
5132 <<Eval cb not proto>>;
5134 <<Eval cb atom proto>>;
5135 <<Eval cb car proto>>;
5136 <<Eval cb cdr proto>>;
5137 <<Eval cb cons proto>>;
5138 <<Eval cb list proto>>;
5139 <<Eval cb equal helper proto>>;
5140 <<Eval cb equal proto>>;
5143 <<Eval cb if proto>>;
5144 <<Eval cb when unless helper enum>>
5145 <<Eval cb when unless proto>>;
5146 <<Eval cb unless proto>>;
5147 <<Eval cb when proto>>;
5148 <<Eval cb cond proto>>;
5149 <<Eval cb select proto>>;
5151 <<Eval cb princ proto>>;
5152 <<Eval cb terpri proto>>;
5154 <<Eval cb eval proto>>;
5155 <<Eval cb prog proto>>;
5156 <<Eval cb prog1 proto>>;
5157 <<Eval cb prog2 proto>>;
5158 <<Eval cb progn proto>>;
5160 <<Eval cb set helper enum>>
5161 <<Eval cb set helper proto>>;
5162 <<Eval cb set proto>>;
5163 <<Eval cb setq proto>>;
5164 <<Eval cb enum proto>>;
5166 <<Eval cb defun proto>>;
5169 (set 20 01 10 15 21 29 01 'lithp/eval.nw'; eval "$shar_touch") &&
5170 chmod 0644 'lithp/eval.nw'
5172 then ${echo} 'restore of lithp/eval.nw failed'
5176 ${MD5SUM} -c >/dev/null 2>&1 || ${echo} 'lithp/eval.nw: MD5 check failed'
5178 e388c9142331e3cd2a72bea0178b5ae8 lithp/eval.nw
5181 test `LC_ALL=C wc -c < 'lithp/eval.nw'` -ne 52035 && \
5182 ${echo} 'restoration warning: size of lithp/eval.nw is not 52035'
5185 if rm -fr ${lock_dir}
5186 then ${echo} 'x - removed lock directory `'${lock_dir}\''.'
5187 else ${echo} 'x - failed to remove lock directory `'${lock_dir}\''.'