~ubuntu-branches/debian/lenny/ucblogo/lenny

« back to all changes in this revision

Viewing changes to eval.c

  • Committer: Bazaar Package Importer
  • Author(s): Hamish Moffatt
  • Date: 2001-09-02 15:15:21 UTC
  • Revision ID: james.westby@ubuntu.com-20010902151521-doo25fmfq7v3pxkg
Tags: upstream-5.1
ImportĀ upstreamĀ versionĀ 5.1

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 *      eval.c          logo eval/apply module                  dko
 
3
 *
 
4
 *      Copyright (C) 1993 by the Regents of the University of California
 
5
 *
 
6
 *      This program is free software; you can redistribute it and/or modify
 
7
 *      it under the terms of the GNU General Public License as published by
 
8
 *      the Free Software Foundation; either version 2 of the License, or
 
9
 *      (at your option) any later version.
 
10
 *  
 
11
 *      This program is distributed in the hope that it will be useful,
 
12
 *      but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
 *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
 *      GNU General Public License for more details.
 
15
 *  
 
16
 *      You should have received a copy of the GNU General Public License
 
17
 *      along with this program; if not, write to the Free Software
 
18
 *      Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
19
 *
 
20
 */
 
21
 
 
22
#include "logo.h"
 
23
#include "globals.h"
 
24
 
 
25
#ifdef HAVE_TERMIO_H
 
26
#include <termio.h>
 
27
#else
 
28
#ifdef HAVE_SGTTY_H
 
29
#include <sgtty.h>
 
30
#endif
 
31
#endif
 
32
 
 
33
#define save(register)      push(register, stack)
 
34
#define restore(register)   (register = car(stack), pop(stack))
 
35
 
 
36
#define save2(reg1,reg2)    (push(reg1,stack),stack->n_obj=reg2)
 
37
#define restore2(reg1,reg2) (reg2 = getobject(stack), \
 
38
                             reg1 = car(stack), pop(stack))
 
39
 
 
40
/* saving and restoring FIXNUMs rather than NODEs */
 
41
 
 
42
#define numsave(register)   numpush(register,&numstack)
 
43
#define numrestore(register) (register=(FIXNUM)car(numstack), numstack=cdr(numstack))
 
44
 
 
45
#define num2save(reg1,reg2) (numpush(reg1,&numstack),numstack->n_obj=(NODE *)reg2)
 
46
#define num2restore(reg1,reg2) (reg2=(FIXNUM)getobject(numstack), \
 
47
                                reg1=(FIXNUM)car(numstack), numstack=cdr(numstack))
 
48
 
 
49
/* save and restore a FIXNUM (reg1) and a NODE (reg2) */
 
50
 
 
51
#define mixsave(reg1,reg2)  (numsave(reg1), save(reg2))
 
52
#define mixrestore(reg1,reg2)   (numrestore(reg1), restore(reg2))
 
53
 
 
54
#define newcont(tag)        (numsave(cont), cont = (FIXNUM)tag)
 
55
 
 
56
/* These variables are all externed in globals.h */
 
57
 
 
58
NODE
 
59
*fun            = NIL,  /* current function name */
 
60
*ufun           = NIL,  /* current user-defined function name */
 
61
*last_ufun      = NIL,  /* the function that called this one */
 
62
*this_line      = NIL,  /* the current instruction line */
 
63
*last_line      = NIL,  /* the line that called this one */
 
64
*var_stack      = NIL,  /* the stack of variables and their bindings */
 
65
*var            = NIL,  /* frame pointer into var_stack */
 
66
*upvar          = NIL,  /* for LOCAL, one stack frame up */
 
67
*last_call      = NIL,  /* the last proc called */
 
68
*didnt_output_name = NIL,   /* the name of the proc that didn't OP */
 
69
*didnt_get_output  = NIL,   /* the name of the proc that wanted the OP */
 
70
*output_node    = NIL;  /* the output of the current function */
 
71
 
 
72
CTRLTYPE    stopping_flag = RUN;
 
73
char        *logolib, *helpfiles;
 
74
FIXNUM      tailcall; /* 0 in sequence, 1 for tail, -1 for arg */
 
75
FIXNUM      val_status;     /* 0 means no value allowed (body of cmd),
 
76
                               1 means value required (arg),
 
77
                               2 means OUTPUT ok (body of oper),
 
78
                               3 means val or no val ok (fn inside catch),
 
79
                               4 means no value in macro (repeat),
 
80
                               5 means value maybe ok in macro (catch)
 
81
                               6 means value required in macro (show run...)
 
82
                               7 means value required *now* (tail call of 6)
 
83
                             */
 
84
FIXNUM      dont_fix_ift = 0;
 
85
FIXNUM      user_repcount = -1;
 
86
 
 
87
/* These variables are local to this file. */
 
88
NODE *qm_list = NIL;    /* question mark list */
 
89
static int trace_level = 0;     /* indentation level when tracing */
 
90
 
 
91
/* These first few functions are externed in globals.h */
 
92
 
 
93
void numpush(FIXNUM obj, NODE **stack) {
 
94
    NODE *temp = newnode(CONT); /*GC*/
 
95
 
 
96
    temp->n_car = (NODE *)obj;
 
97
    temp->n_cdr = *stack;
 
98
    *stack = temp;
 
99
}
 
100
 
 
101
/* forward declaration */
 
102
NODE *evaluator(NODE *list, enum labels where);
 
103
 
 
104
/* Evaluate a line of input. */
 
105
void eval_driver(NODE *line) {
 
106
    evaluator(line, begin_line);
 
107
}
 
108
 
 
109
/* Evaluate a sequence of expressions until we get a value to return.
 
110
 * (Called from erract.)
 
111
 */ 
 
112
NODE *err_eval_driver(NODE *seq) {
 
113
    val_status = 5;
 
114
    return evaluator(seq, begin_seq);
 
115
}
 
116
 
 
117
/* The logo word APPLY. */
 
118
NODE *lapply(NODE *args) {
 
119
    return make_cont(begin_apply, args);
 
120
}
 
121
 
 
122
/* The logo word ? <question-mark>. */
 
123
NODE *lqm(NODE *args) {
 
124
    FIXNUM argnum = 1, i;
 
125
    NODE *np = qm_list;
 
126
 
 
127
    if (args != NIL) argnum = getint(pos_int_arg(args));
 
128
    if (stopping_flag == THROWING) return(UNBOUND);
 
129
    i = argnum;
 
130
    while (--i > 0 && np != NIL) np = cdr(np);
 
131
    if (np == NIL)
 
132
        return(err_logo(BAD_DATA_UNREC,make_intnode(argnum)));
 
133
    return(car(np));
 
134
}
 
135
 
 
136
/* The rest of the functions are local to this file. */
 
137
 
 
138
/* Warn the user if a local variable shadows a global one. */
 
139
void tell_shadow(NODE *arg) {
 
140
    if (flag__caseobj(arg, VAL_STEPPED))
 
141
        err_logo(SHADOW_WARN, arg);
 
142
}
 
143
 
 
144
/* Check if a local variable is already in this frame */
 
145
int not_local(NODE *name, NODE *sp) {
 
146
    for ( ; sp != var; sp = cdr(sp)) {
 
147
        if (compare_node(car(sp),name,TRUE) == 0) {
 
148
            return FALSE;
 
149
        }
 
150
    }
 
151
    return TRUE;
 
152
}
 
153
 
 
154
/* reverse a list destructively */
 
155
NODE *reverse(NODE *list) {
 
156
    NODE *ret = NIL, *temp;
 
157
 
 
158
    while (list != NIL) {
 
159
        temp = list;
 
160
        list = cdr(list);
 
161
        setcdr(temp, ret);
 
162
        ret = temp;
 
163
    }
 
164
    return ret;
 
165
}
 
166
 
 
167
/* nondestructive append */
 
168
NODE *append(NODE *a, NODE *b) {
 
169
    if (a == NIL) return b;
 
170
    return cons(car(a), append(cdr(a), b));
 
171
}
 
172
 
 
173
/* nondestructive flatten */
 
174
NODE *flatten(NODE *a) {
 
175
    if (a == NIL) return NIL;
 
176
    return append(car(a), flatten(cdr(a)));
 
177
}
 
178
 
 
179
/* Reset the var stack to the previous place holder.
 
180
 */
 
181
void reset_args(NODE *old_stack) {
 
182
    for (; var_stack != old_stack; pop(var_stack))
 
183
        setvalnode__caseobj(car(var_stack), getobject(var_stack));
 
184
}
 
185
 
 
186
NODE *bf3(NODE *name) {
 
187
    NODE *string = cnv_node_to_strnode(name);
 
188
    return make_strnode(getstrptr(string)+3, getstrhead(string),
 
189
                        getstrlen(string)-3, nodetype(string), strcpy);
 
190
}
 
191
 
 
192
NODE *deep_copy(NODE *exp) {
 
193
    NODE *val, **p, **q;
 
194
    FIXNUM arridx;
 
195
 
 
196
    if (exp == NIL) return NIL;
 
197
    else if (is_list(exp)) {
 
198
        val = cons(deep_copy(car(exp)), deep_copy(cdr(exp)));
 
199
        val->n_obj = deep_copy(exp->n_obj);
 
200
        settype(val, nodetype(exp));
 
201
    } else if (nodetype(exp) == ARRAY) {
 
202
        val = make_array(getarrdim(exp));
 
203
        setarrorg(val, getarrorg(exp));
 
204
        for (p = getarrptr(exp), q = getarrptr(val), arridx=0;
 
205
             arridx < getarrdim(exp); arridx++, p++)
 
206
        *q++ = deep_copy(*p);
 
207
    } else val = exp;
 
208
    return val;
 
209
}
 
210
 
 
211
 
 
212
 
 
213
/* An explicit control evaluator, taken almost directly from SICP, section
 
214
 * 5.2.  list is a flat list of expressions to evaluate.  where is a label to
 
215
 * begin at.  Return value depends on where.
 
216
 */ 
 
217
NODE *evaluator(NODE *list, enum labels where) {
 
218
 
 
219
    /* registers */
 
220
    NODE    *exp    = NIL,  /* the current expression */
 
221
            *val    = NIL,  /* the value of the last expression */
 
222
            *proc   = NIL,  /* the procedure definition */
 
223
            *argl   = NIL,  /* evaluated argument list */
 
224
            *unev   = NIL,  /* list of unevaluated expressions */
 
225
            *stack  = NIL,  /* register stack */
 
226
            *numstack = NIL,/* stack whose elements aren't objects */
 
227
            *parm   = NIL,  /* the current formal */
 
228
            *catch_tag = NIL,
 
229
            *arg    = NIL;  /* the current actual */
 
230
 
 
231
    NODE    *vsp    = 0,    /* temp ptr into var_stack */
 
232
            *formals = NIL; /* list of formal parameters */
 
233
    FIXNUM  cont   = 0;     /* where to go next */
 
234
 
 
235
    int i;
 
236
    BOOLEAN tracing = FALSE; /* are we tracing the current procedure? */
 
237
    FIXNUM oldtailcall;     /* in case of reentrant use of evaluator */
 
238
    FIXNUM repcount;        /* count for repeat */
 
239
    FIXNUM old_ift_iff;
 
240
        
 
241
    oldtailcall = tailcall;
 
242
    old_ift_iff = ift_iff_flag;
 
243
    save2(var,this_line);
 
244
    var = var_stack;
 
245
    save2(fun,ufun);
 
246
    cont = (FIXNUM)all_done;
 
247
    numsave((FIXNUM)cont);
 
248
    newcont(where);
 
249
    goto fetch_cont;
 
250
    
 
251
begin_line:
 
252
    this_line = list;
 
253
    newcont(end_line);
 
254
begin_seq:
 
255
    make_tree(list);
 
256
    if (!is_tree(list)) {
 
257
        val = UNBOUND;
 
258
        goto fetch_cont;
 
259
    }
 
260
    unev = tree__tree(list);
 
261
    val = UNBOUND;
 
262
    goto eval_sequence;
 
263
 
 
264
end_line:
 
265
    if (val != UNBOUND) {
 
266
        if (NOT_THROWING) err_logo(DK_WHAT, val);
 
267
    }
 
268
    val = NIL;
 
269
    goto fetch_cont;
 
270
 
 
271
 
 
272
/* ----------------- EVAL ---------------------------------- */
 
273
 
 
274
tail_eval_dispatch:
 
275
    tailcall = 1;
 
276
eval_dispatch:
 
277
    switch (nodetype(exp)) {
 
278
        case QUOTE:                     /* quoted literal */
 
279
            val = /* deep_copy */ (node__quote(exp));
 
280
            goto fetch_cont;
 
281
        case COLON:                     /* variable */
 
282
            val = valnode__colon(exp);
 
283
            while (val == UNBOUND && NOT_THROWING)
 
284
                val = err_logo(NO_VALUE, node__colon(exp));
 
285
            goto fetch_cont;
 
286
        case CONS:                      /* procedure application */
 
287
            if (tailcall == 1 && is_macro(car(exp)) &&
 
288
                                 (is_list(procnode__caseobj(car(exp)))
 
289
                                    || !compare_node(car(exp), Goto, TRUE))) {
 
290
                /* tail call to user-defined macro must be treated as non-tail
 
291
                 * because the expression returned by the macro
 
292
                 * remains to be evaluated in the caller's context */
 
293
                unev = NIL;
 
294
                goto non_tail_eval;
 
295
            }
 
296
            fun = car(exp);
 
297
            if (fun == Not_Enough_Node) {
 
298
                err_logo(TOO_MUCH, NIL);
 
299
                val = UNBOUND;
 
300
                goto fetch_cont;
 
301
            }
 
302
            if (cdr(exp) != NIL)
 
303
                goto ev_application;
 
304
            else
 
305
                goto ev_no_args;
 
306
        case ARRAY:                     /* array must be copied */
 
307
            val = deep_copy(exp);
 
308
            goto fetch_cont;
 
309
        default:
 
310
            val = exp;          /* self-evaluating */
 
311
            goto fetch_cont;
 
312
    }
 
313
 
 
314
ev_no_args:
 
315
    /* Evaluate an application of a procedure with no arguments. */
 
316
    argl = NIL;
 
317
    goto apply_dispatch;    /* apply the procedure */
 
318
 
 
319
ev_application:
 
320
    /* Evaluate an application of a procedure with arguments. */
 
321
    unev = cdr(exp);
 
322
    argl = NIL;
 
323
    mixsave(tailcall,var);
 
324
    num2save(val_status,ift_iff_flag);
 
325
    save2(didnt_get_output,didnt_output_name);
 
326
eval_arg_loop:
 
327
    if (unev == NIL) goto eval_args_done;
 
328
    exp = car(unev);
 
329
    if (exp == Not_Enough_Node) {
 
330
        if (NOT_THROWING)
 
331
            err_logo(NOT_ENOUGH, NIL);
 
332
        goto eval_args_done;
 
333
    }
 
334
    save2(argl,proc);
 
335
    save2(unev,fun);
 
336
    save2(ufun,last_ufun);
 
337
    save2(this_line,last_line);
 
338
    var = var_stack;
 
339
    tailcall = -1;
 
340
    val_status = 1;
 
341
    didnt_get_output = cons_list(0, fun, ufun, this_line, END_OF_LIST);
 
342
    didnt_output_name = NIL;
 
343
    newcont(accumulate_arg);
 
344
    goto eval_dispatch;     /* evaluate the current argument */
 
345
 
 
346
accumulate_arg:
 
347
    /* Put the evaluated argument into the argl list. */
 
348
    reset_args(var);
 
349
    restore2(this_line,last_line);
 
350
    restore2(ufun,last_ufun);
 
351
    last_call = fun;
 
352
    restore2(unev,fun);
 
353
    restore2(argl,proc);
 
354
    while (NOT_THROWING && val == UNBOUND) {
 
355
        val = err_logo(DIDNT_OUTPUT, NIL);
 
356
    }
 
357
    push(val, argl);
 
358
    pop(unev);
 
359
    goto eval_arg_loop;
 
360
 
 
361
eval_args_done:
 
362
    restore2(didnt_get_output,didnt_output_name);
 
363
    num2restore(val_status,ift_iff_flag);
 
364
    mixrestore(tailcall,var);
 
365
    if (stopping_flag == THROWING) {
 
366
        val = UNBOUND;
 
367
        goto fetch_cont;
 
368
    }
 
369
    argl = reverse(argl);
 
370
/* --------------------- APPLY ---------------------------- */
 
371
apply_dispatch:
 
372
    /* Load in the procedure's definition and decide whether it's a compound
 
373
     * procedure or a primitive procedure.
 
374
     */
 
375
    proc = procnode__caseobj(fun);
 
376
    if (is_macro(fun)) {
 
377
        num2save(val_status,tailcall);
 
378
        val_status = 1;
 
379
        newcont(macro_return);
 
380
    }
 
381
    if (proc == UNDEFINED) {    /* 5.0 punctuationless variables */
 
382
        if (compare_node(valnode__caseobj(AllowGetSet),True,TRUE)
 
383
               != 0) {      /* No getter/setter allowed, punt */
 
384
            val = err_logo(DK_HOW, fun);
 
385
            goto fetch_cont;
 
386
        } else if (argl == NIL) {       /* possible var getter */
 
387
            val = valnode__caseobj(fun);
 
388
            if (val == UNBOUND && NOT_THROWING)
 
389
                val = err_logo(DK_HOW, fun);
 
390
            else if (val != UNBOUND) {
 
391
                (void)ldefine(cons(fun, cons(
 
392
                   cons(NIL,cons(cons(Output,cons(make_colon(fun),NIL)),NIL))
 
393
                  ,NIL)));    /* make real proc so no disk load next time */
 
394
                setflag__caseobj(fun,PROC_BURIED);
 
395
            }
 
396
            goto fetch_cont;
 
397
        } else {                /* var setter */
 
398
            (void)ldefine(cons(fun, cons(
 
399
                cons(Listvalue,
 
400
                     cons(cons(Make,
 
401
                               cons(make_quote(bf3(fun)),
 
402
                                    cons(Dotsvalue,NIL))),
 
403
                          NIL))
 
404
                ,NIL)));
 
405
            setflag__caseobj(fun,PROC_BURIED);
 
406
            argl = cons(bf3(fun), argl);
 
407
            if (NOT_THROWING)
 
408
                val = lmake(argl);
 
409
            goto fetch_cont;
 
410
        }
 
411
    }
 
412
    if (is_list(proc)) goto compound_apply;
 
413
    /* primitive_apply */
 
414
    if (NOT_THROWING) {
 
415
        if ((tracing = flag__caseobj(fun, PROC_TRACED))) {
 
416
            for (i = 0; i < trace_level; i++) {
 
417
                print_space(stdout);
 
418
            }
 
419
            ndprintf(stdout, "( %s ", fun);
 
420
            if (argl != NIL) {
 
421
                arg = argl;
 
422
                while (arg != NIL) {
 
423
                    print_node(stdout, maybe_quote(car(arg)));
 
424
                    print_space(stdout);
 
425
                    arg = cdr(arg);
 
426
                }
 
427
            }
 
428
            print_char(stdout, ')');
 
429
            new_line(stdout);
 
430
        }
 
431
        val = (*getprimfun(proc))(argl);
 
432
        if (tracing && NOT_THROWING) {
 
433
            for (i = 0; i < trace_level; i++) {
 
434
                print_space(stdout);
 
435
            }
 
436
            print_node(stdout, fun);
 
437
            if (val == UNBOUND)
 
438
                ndprintf(stdout, " %t\n", message_texts[TRACE_STOPS]);
 
439
            else {
 
440
                ndprintf(stdout, " %t %s\n", message_texts[TRACE_OUTPUTS],
 
441
                                             maybe_quote(val));
 
442
            }
 
443
        }
 
444
    } else
 
445
        val = UNBOUND;
 
446
#define do_case(x) case x: goto x;
 
447
fetch_cont:
 
448
    {
 
449
        enum labels x = (enum labels)cont;
 
450
        cont = (FIXNUM)car(numstack);
 
451
        numstack=cdr(numstack);
 
452
        switch (x) {
 
453
            do_list(do_case)
 
454
            default: abort();
 
455
        }
 
456
    }
 
457
 
 
458
compound_apply:
 
459
#ifdef mac
 
460
    check_mac_stop();
 
461
#endif
 
462
#ifdef ibm
 
463
    check_ibm_stop();
 
464
#endif
 
465
    if ((tracing = flag__caseobj(fun, PROC_TRACED))) {
 
466
        for (i = 0; i < trace_level; i++) print_space(writestream);
 
467
        trace_level++;
 
468
        ndprintf(writestream, "( %s ", fun);
 
469
    }
 
470
/* Bind the actuals to the formals */
 
471
lambda_apply:
 
472
    vsp = var_stack;    /* remember where we came in */
 
473
    for (formals = formals__procnode(proc);
 
474
         formals != NIL;
 
475
         formals = cdr(formals)) {
 
476
            parm = car(formals);
 
477
            if (nodetype(parm) == INT) break;   /* default # args */
 
478
            if (argl != NIL) {
 
479
                arg = car(argl);
 
480
                if (tracing) {
 
481
                    print_node(writestream, maybe_quote(arg));
 
482
                    print_space(writestream);
 
483
                }
 
484
            } else
 
485
                arg = UNBOUND;
 
486
            if (nodetype(parm) == CASEOBJ) {
 
487
                if (not_local(parm,vsp)) {
 
488
                    push(parm, var_stack);
 
489
                    var_stack->n_obj = valnode__caseobj(parm);
 
490
                }
 
491
                tell_shadow(parm);
 
492
                setvalnode__caseobj(parm, arg);
 
493
                if (arg == UNBOUND)
 
494
                    err_logo(NOT_ENOUGH, fun);
 
495
            } else if (nodetype(parm) == CONS) {
 
496
                /* parm is optional or rest */
 
497
                if (not_local(car(parm),vsp)) {
 
498
                    push(car(parm), var_stack);
 
499
                    var_stack->n_obj = valnode__caseobj(car(parm));
 
500
                }
 
501
                tell_shadow(car(parm));
 
502
                if (cdr(parm) == NIL) {             /* parm is rest */
 
503
                    setvalnode__caseobj(car(parm), argl);
 
504
                    if (tracing) {
 
505
                        if (argl != NIL) pop(argl);
 
506
                        while (argl != NIL) {
 
507
                            arg = car(argl);
 
508
                            print_node(writestream, maybe_quote(arg));
 
509
                            print_space(writestream);
 
510
                            pop(argl);
 
511
                        }
 
512
                    } else argl = NIL;
 
513
                    break;
 
514
                }
 
515
                if (arg == UNBOUND) {               /* use default */
 
516
                    save(proc);
 
517
                    save2(fun,var);
 
518
                    save2(ufun,last_ufun);
 
519
                    save2(this_line,last_line);
 
520
                    save2(didnt_output_name,didnt_get_output);
 
521
                    num2save(ift_iff_flag,val_status);
 
522
                    var = var_stack;
 
523
                    tailcall = -1;
 
524
                    val_status = 1;
 
525
                    save2(formals,argl);
 
526
                    save(vsp);
 
527
                    list = cdr(parm);
 
528
                    if (NOT_THROWING)
 
529
                        make_tree(list);
 
530
                    else
 
531
                        list = NIL;
 
532
                    if (!is_tree(list)) {
 
533
                        val = UNBOUND;
 
534
                        goto set_args_continue;
 
535
                    }
 
536
                    unev = tree__tree(list);
 
537
                    val = UNBOUND;
 
538
                    newcont(set_args_continue);
 
539
                    goto eval_sequence;
 
540
 
 
541
set_args_continue:
 
542
                    restore(vsp);
 
543
                    restore2(formals,argl);
 
544
                    parm = car(formals);
 
545
                    reset_args(var);
 
546
                    num2restore(ift_iff_flag,val_status);
 
547
                    restore2(didnt_output_name,didnt_get_output);
 
548
                    restore2(this_line,last_line);
 
549
                    restore2(ufun,last_ufun);
 
550
                    restore2(fun,var);
 
551
                    restore(proc);
 
552
                    arg = val;
 
553
                }
 
554
                setvalnode__caseobj(car(parm), arg);
 
555
            }
 
556
            if (argl != NIL) pop(argl);
 
557
    }
 
558
    if (argl != NIL) {
 
559
        err_logo(TOO_MUCH, NIL);
 
560
    }
 
561
    if (check_throwing) {
 
562
        val = UNBOUND;
 
563
        goto fetch_cont;
 
564
    }
 
565
    vsp = NIL;
 
566
    if ((tracing = !is_list(fun)) && flag__caseobj(fun, PROC_TRACED)) {
 
567
        if (NOT_THROWING) print_char(writestream, ')');
 
568
        new_line(writestream);
 
569
        save(fun);
 
570
        newcont(compound_apply_continue);
 
571
    }
 
572
    val = UNBOUND;
 
573
    last_ufun = ufun;
 
574
    if (!is_list(fun)) ufun = fun;
 
575
    last_line = this_line;
 
576
    this_line = NIL;
 
577
    proc = (is_list(fun) ? anonymous_function(fun) : procnode__caseobj(fun));
 
578
    list = bodylist__procnode(proc);    /* get the body ... */
 
579
    make_tree_from_body(list);
 
580
    if (!is_tree(list)) {
 
581
        goto fetch_cont;
 
582
    }
 
583
    unev = tree__tree(list);
 
584
    if (NOT_THROWING) stopping_flag = RUN;
 
585
    output_node = UNBOUND;
 
586
    if (val_status == 1) val_status = 2;
 
587
    else if (val_status == 5) val_status = 3;
 
588
    else val_status = 0;
 
589
eval_sequence:
 
590
    /* Evaluate each expression in the sequence.  Stop as soon as
 
591
     * val != UNBOUND.
 
592
     */
 
593
    if (!RUNNING || val != UNBOUND) {
 
594
        goto fetch_cont;
 
595
    }
 
596
    if (nodetype(unev) == LINE) {
 
597
        if (the_generation != (generation__line(unev))) {
 
598
            /* something redefined while we're running */
 
599
            int linenum = 0;
 
600
            this_line = tree__tree(bodylist__procnode(proc));
 
601
            while (this_line != unev) {
 
602
                /* If redef isn't end of line, don't try to fix,
 
603
                   but don't blow up either. (Maybe not called from here.) */
 
604
                if (this_line == NULL) goto nofix;
 
605
                if (nodetype(this_line) == LINE) linenum++;
 
606
                this_line = cdr(this_line);
 
607
            }
 
608
            untreeify_proc(proc);
 
609
            make_tree_from_body(bodylist__procnode(proc));
 
610
            unev = tree__tree(bodylist__procnode(proc));
 
611
            while (--linenum >= 0) {
 
612
                do pop(unev);
 
613
                while (unev != NIL && nodetype(unev) != LINE);
 
614
            }
 
615
        }
 
616
nofix:  this_line = unparsed__line(unev);
 
617
        if (ufun != NIL && flag__caseobj(ufun, PROC_STEPPED)) {
 
618
            if (tracing) {
 
619
                int i = 1;
 
620
                while (i++ < trace_level) print_space(stdout);
 
621
            }
 
622
            print_node(stdout, this_line);
 
623
            (void)reader(stdin, " >>> ");
 
624
        }
 
625
    }
 
626
    exp = car(unev);
 
627
    pop(unev);
 
628
    if (exp != NIL &&
 
629
        is_list(exp) && (is_tailform(procnode__caseobj(car(exp))))) {
 
630
      i = (int)getprimpri(procnode__caseobj(car(exp)));
 
631
      if (i == OUTPUT_PRIORITY) {
 
632
        didnt_get_output = cons_list(0,car(exp),ufun,this_line,END_OF_LIST);
 
633
        didnt_output_name = NIL;
 
634
        if (cadr(exp) == Not_Enough_Node) {
 
635
            err_logo(NOT_ENOUGH,car(exp));
 
636
            val = UNBOUND;
 
637
            goto fetch_cont;
 
638
        }
 
639
        if (val_status == 2 || val_status == 3) {
 
640
            val_status = 1;
 
641
            exp = cadr(exp);
 
642
            goto tail_eval_dispatch;
 
643
        } else if (ufun == NIL) {
 
644
            err_logo(AT_TOPLEVEL,car(exp));
 
645
            val = UNBOUND;
 
646
            goto fetch_cont;
 
647
        } else if (val_status < 4) {
 
648
            val_status = 1;
 
649
            exp = cadr(exp);
 
650
            unev = NIL;
 
651
            goto non_tail_eval;     /* compute value then give error */
 
652
        }
 
653
      } else if (i == STOP_PRIORITY) {
 
654
        if (ufun == NIL) {
 
655
            err_logo(AT_TOPLEVEL,car(exp));
 
656
            val = UNBOUND;
 
657
            goto fetch_cont;
 
658
        } else if (val_status == 0 || val_status == 3) {
 
659
            val = UNBOUND;
 
660
            goto fetch_cont;
 
661
        } else if (val_status < 4) {
 
662
            didnt_output_name = fun;
 
663
            val = UNBOUND;
 
664
            goto fetch_cont;
 
665
        }
 
666
      } else { /* maybeoutput */
 
667
        exp = cadr(exp);
 
668
        val_status = 5;
 
669
        goto tail_eval_dispatch;
 
670
      }
 
671
    }
 
672
    if (unev == NIL) {
 
673
        if (val_status == 2 || val_status == 4) {
 
674
            didnt_output_name = fun;
 
675
            unev = UNBOUND;
 
676
            goto non_tail_eval;
 
677
        } else {
 
678
            goto tail_eval_dispatch;
 
679
        }
 
680
    }
 
681
    if (car(unev) != NIL && is_list(car(unev)) && 
 
682
                (is_tailform(procnode__caseobj(car(car(unev))))) &&
 
683
                getprimpri(procnode__caseobj(car(car(unev)))) == STOP_PRIORITY) {
 
684
        if ((val_status == 0 || val_status == 3) && ufun != NIL) {
 
685
            goto tail_eval_dispatch;
 
686
        } else if (val_status < 4 && ufun != NIL) {
 
687
            didnt_output_name = fun;
 
688
            goto tail_eval_dispatch;
 
689
        }
 
690
    }
 
691
non_tail_eval:
 
692
    save2(unev,fun);
 
693
    num2save(ift_iff_flag,val_status);
 
694
    save2(ufun,last_ufun);
 
695
    save2(this_line,last_line);
 
696
    save2(var,proc);
 
697
    save(upvar);
 
698
    upvar = var;
 
699
    var = var_stack;
 
700
    tailcall = 0;
 
701
    newcont(eval_sequence_continue);
 
702
    goto eval_dispatch;
 
703
 
 
704
eval_sequence_continue:
 
705
    reset_args(var);
 
706
    restore(upvar);
 
707
    restore2(var,proc);
 
708
    restore2(this_line,last_line);
 
709
    restore2(ufun,last_ufun);
 
710
    if (dont_fix_ift) {
 
711
        num2restore(dont_fix_ift,val_status);
 
712
        dont_fix_ift = 0;
 
713
    } else
 
714
        num2restore(ift_iff_flag,val_status);
 
715
    restore2(unev,fun);
 
716
    if (stopping_flag == MACRO_RETURN) {
 
717
        if (unev == UNBOUND) unev = NIL;
 
718
        if (val != NIL && is_list(val) && (car(val) == Tag))
 
719
            unev = cdr(val);    /* from goto */
 
720
        else
 
721
            unev = append(val, unev);
 
722
        val = UNBOUND;
 
723
        stopping_flag = RUN;
 
724
        if (unev == NIL) goto fetch_cont;
 
725
    } else if (val_status < 4) {
 
726
        if (STOPPING || RUNNING) output_node = UNBOUND;
 
727
        if (stopping_flag == OUTPUT || STOPPING) {
 
728
            stopping_flag = RUN;
 
729
            val = output_node;
 
730
            if (val != UNBOUND && val_status == 1 && NOT_THROWING) {
 
731
                didnt_output_name = Output;
 
732
                err_logo(DIDNT_OUTPUT,Output);
 
733
            }
 
734
            if (val == UNBOUND && val_status == 1 && NOT_THROWING) {
 
735
                didnt_output_name = Stop;
 
736
                err_logo(DIDNT_OUTPUT,Output);
 
737
            }
 
738
            goto fetch_cont;
 
739
        }
 
740
    }
 
741
    if (val != UNBOUND) {
 
742
        err_logo((unev == NIL ? DK_WHAT_UP : DK_WHAT), val);
 
743
        val = UNBOUND;
 
744
    }
 
745
    if (NOT_THROWING && (unev == NIL || unev == UNBOUND)) {
 
746
        if (val_status != 4)  err_logo(DIDNT_OUTPUT,NIL);
 
747
        goto fetch_cont;
 
748
    }
 
749
    goto eval_sequence;
 
750
 
 
751
compound_apply_continue:
 
752
    /* Only get here if tracing */
 
753
    restore(fun);
 
754
    --trace_level;
 
755
    if (NOT_THROWING) {
 
756
        for (i = 0; i < trace_level; i++) print_space(writestream);
 
757
        print_node(writestream, fun);
 
758
        if (val == UNBOUND)
 
759
            ndprintf(writestream, " %t\n", message_texts[TRACE_STOPS]);
 
760
        else {
 
761
            ndprintf(writestream, " %t %s\n", message_texts[TRACE_OUTPUTS],
 
762
                                              maybe_quote(val));
 
763
        }
 
764
    }
 
765
    goto fetch_cont;
 
766
 
 
767
/* --------------------- MACROS ---------------------------- */
 
768
 
 
769
macro_return:
 
770
    num2restore(val_status,tailcall);
 
771
    while (!is_list(val) && NOT_THROWING) {
 
772
        val = err_logo(ERR_MACRO,val);
 
773
    }
 
774
    if (NOT_THROWING) {
 
775
        if (is_cont(val)) {
 
776
            newcont(cont__cont(val));
 
777
            val = val__cont(val);
 
778
            goto fetch_cont;
 
779
        }
 
780
        if (tailcall == 0) {
 
781
            make_tree(val);
 
782
            if (NOT_THROWING) {
 
783
                stopping_flag = MACRO_RETURN;
 
784
                if (!is_tree(val)) val = NIL;
 
785
                else val = tree__tree(val);
 
786
            } else val = UNBOUND;
 
787
            goto fetch_cont;
 
788
        }
 
789
        list = val;
 
790
        goto begin_seq;
 
791
    }
 
792
    val = UNBOUND;
 
793
    goto fetch_cont;
 
794
 
 
795
run_continuation:
 
796
    list = val;
 
797
    val_status = 5;
 
798
    goto begin_seq;
 
799
 
 
800
runresult_continuation:
 
801
    list = val;
 
802
    newcont(runresult_followup);
 
803
    val_status = 5;
 
804
    goto begin_seq;
 
805
 
 
806
runresult_followup:
 
807
    if (val == UNBOUND) {
 
808
        val = NIL;
 
809
    } else {
 
810
        val = cons(val, NIL);
 
811
    }
 
812
    goto fetch_cont;
 
813
 
 
814
repeat_continuation:
 
815
    list = cdr(val);
 
816
    repcount = getint(car(val));
 
817
    user_repcount = 0;
 
818
repeat_again:
 
819
    val = UNBOUND;
 
820
    if (repcount == 0) {
 
821
        user_repcount = -1;
 
822
        goto fetch_cont;
 
823
    }
 
824
    user_repcount++;
 
825
    save(list);
 
826
    num2save(repcount,user_repcount);
 
827
    num2save(val_status,tailcall);
 
828
    val_status = 4;
 
829
    newcont(repeat_followup);
 
830
    goto begin_seq;
 
831
 
 
832
repeat_followup:
 
833
    if (val != UNBOUND && NOT_THROWING) {
 
834
        err_logo(DK_WHAT, val);
 
835
    }
 
836
    num2restore(val_status,tailcall);
 
837
    num2restore(repcount,user_repcount);
 
838
    restore(list);
 
839
    if (val_status < 4 && tailcall != 0) {
 
840
        if (STOPPING || RUNNING) output_node = UNBOUND;
 
841
        if (stopping_flag == OUTPUT || STOPPING) {
 
842
            stopping_flag = RUN;
 
843
            val = output_node;
 
844
            if (val != UNBOUND && val_status < 2) {
 
845
                err_logo(DK_WHAT_UP,val);
 
846
            }
 
847
            goto fetch_cont;
 
848
        }
 
849
    }
 
850
    if (repcount > 0)    /* negative means forever */
 
851
        --repcount;
 
852
#ifdef mac
 
853
    check_mac_stop();
 
854
#endif
 
855
#ifdef ibm
 
856
    check_ibm_stop();
 
857
#endif
 
858
    if (RUNNING) goto repeat_again;
 
859
    val = UNBOUND;
 
860
    user_repcount = -1;
 
861
    goto fetch_cont;
 
862
 
 
863
catch_continuation:
 
864
    list = cdr(val);
 
865
    catch_tag = car(val);
 
866
    if (compare_node(catch_tag,Error,TRUE) == 0) {
 
867
        push(Erract, var_stack);
 
868
        var_stack->n_obj = valnode__caseobj(Erract);
 
869
        setvalnode__caseobj(Erract, UNBOUND);
 
870
    }
 
871
    save(catch_tag);
 
872
    save2(didnt_output_name,didnt_get_output);
 
873
    num2save(val_status,tailcall);
 
874
    newcont(catch_followup);
 
875
    val_status = 5;
 
876
    goto begin_seq;
 
877
 
 
878
catch_followup:
 
879
    num2restore(val_status,tailcall);
 
880
    restore2(didnt_output_name,didnt_get_output);
 
881
    restore(catch_tag);
 
882
    if (val_status < 4 && tailcall != 0) {
 
883
        if (STOPPING || RUNNING) output_node = UNBOUND;
 
884
        if (stopping_flag == OUTPUT || STOPPING) {
 
885
            stopping_flag = RUN;
 
886
            val = output_node;
 
887
            if (val != UNBOUND && val_status < 2) {
 
888
                err_logo(DK_WHAT_UP,val);
 
889
            }
 
890
        }
 
891
    }
 
892
    if (stopping_flag == THROWING &&
 
893
        compare_node(throw_node, catch_tag, TRUE) == 0) {
 
894
            throw_node = UNBOUND;
 
895
            stopping_flag = RUN;
 
896
            val = output_node;
 
897
    }
 
898
    goto fetch_cont;
 
899
 
 
900
goto_continuation:
 
901
    if (NOT_THROWING) {
 
902
        if (ufun == NIL) {
 
903
            err_logo(AT_TOPLEVEL, Goto);
 
904
            val = UNBOUND;
 
905
            goto fetch_cont;
 
906
        }
 
907
        proc = procnode__caseobj(ufun);
 
908
        list = bodylist__procnode(proc);
 
909
        unev = tree__tree(list);
 
910
        while (unev != NIL && !check_throwing) {
 
911
            if (nodetype(unev) == LINE)
 
912
                this_line = unparsed__line(unev);
 
913
            exp = car(unev);
 
914
            pop(unev);
 
915
            if (is_list (exp) &&
 
916
                    (object__caseobj(car(exp)) == object__caseobj(Tag)) &&
 
917
                    (nodetype(cadr(exp)) == QUOTE) &&
 
918
                    compare_node(val, node__quote(cadr(exp)), TRUE) == 0) {
 
919
                val = cons(Tag, unev);
 
920
                stopping_flag = MACRO_RETURN;
 
921
                goto fetch_cont;
 
922
            }
 
923
        }
 
924
        err_logo(BAD_DATA_UNREC, val);
 
925
    }
 
926
    val = UNBOUND;
 
927
    goto fetch_cont;
 
928
 
 
929
begin_apply:
 
930
    /* This is for lapply. */
 
931
    fun = car(val);
 
932
    while (nodetype(fun) == ARRAY && NOT_THROWING)
 
933
        fun = err_logo(APPLY_BAD_DATA, fun);
 
934
    argl = cadr(val);
 
935
    val = UNBOUND;
 
936
    while (!is_list(argl) && NOT_THROWING)
 
937
        argl = err_logo(APPLY_BAD_DATA, argl);
 
938
    if (NOT_THROWING && fun != NIL) {
 
939
        if (is_list(fun)) {                 /* template */
 
940
            if (is_list(car(fun)) && cdr(fun) != NIL) {
 
941
                if (is_list(cadr(fun))) {       /* procedure text form */
 
942
                    proc = anonymous_function(fun);
 
943
                    tracing = 0;
 
944
                    goto lambda_apply;
 
945
                }
 
946
                /* lambda form */
 
947
                formals = car(fun);
 
948
                save(var);
 
949
                numsave(tailcall);
 
950
                tailcall = 0;
 
951
                llocal(formals);    /* bind the formals locally */
 
952
                numrestore(tailcall);
 
953
                for ( ;
 
954
                     formals && argl && NOT_THROWING;
 
955
                     formals = cdr(formals),
 
956
                     argl = cdr(argl))
 
957
                        setvalnode__caseobj(car(formals), car(argl));
 
958
                list = cdr(fun);
 
959
                save(qm_list);
 
960
                newcont(after_lambda);
 
961
                goto lambda_qm;
 
962
            } else {            /* question-mark form */
 
963
                save(qm_list);
 
964
                qm_list = argl;
 
965
                list = fun;
 
966
lambda_qm:
 
967
                make_tree(list);
 
968
                if (list == NIL || !is_tree(list)) {
 
969
                    goto qm_failed;
 
970
                }
 
971
                unev = tree__tree(list);
 
972
                save2(didnt_output_name,didnt_get_output);
 
973
                num2save(val_status,tailcall);
 
974
                newcont(qm_continue);
 
975
                val_status = 5;
 
976
                goto eval_sequence;
 
977
 
 
978
qm_continue:
 
979
                num2restore(val_status,tailcall);
 
980
                restore2(didnt_output_name,didnt_get_output);
 
981
                if (val_status < 4 && tailcall != 0) {
 
982
                    if (STOPPING || RUNNING) output_node = UNBOUND;
 
983
                    if (stopping_flag == OUTPUT || STOPPING) {
 
984
                        stopping_flag = RUN;
 
985
                        val = output_node;
 
986
                        if (val != UNBOUND && val_status < 2) {
 
987
                            err_logo(DK_WHAT_UP,val);
 
988
                        }
 
989
                    }
 
990
                }
 
991
qm_failed:
 
992
                restore(qm_list);
 
993
                goto fetch_cont;
 
994
            }
 
995
        } else {    /* name of procedure to apply */
 
996
            int min, max, n;
 
997
            NODE *arg;
 
998
            fun = intern(fun);
 
999
            if (procnode__caseobj(fun) == UNDEFINED && NOT_THROWING &&
 
1000
                fun != Null_Word)
 
1001
                    silent_load(fun, NULL);    /* try ./<fun>.lg */
 
1002
            if (procnode__caseobj(fun) == UNDEFINED && NOT_THROWING &&
 
1003
                fun != Null_Word)
 
1004
                    silent_load(fun, logolib); /* try <logolib>/<fun> */
 
1005
            proc = procnode__caseobj(fun);
 
1006
            while (proc == UNDEFINED && NOT_THROWING) {
 
1007
                val = err_logo(DK_HOW_UNREC, fun);
 
1008
            }
 
1009
            if (NOT_THROWING) {
 
1010
                if (nodetype(proc) == CONS) {
 
1011
                    min = getint(minargs__procnode(proc));
 
1012
                    max = getint(maxargs__procnode(proc));
 
1013
                } else {
 
1014
                    if (getprimdflt(proc) < 0) {            /* special form */
 
1015
                        err_logo(DK_HOW_UNREC, fun);    /* can't apply */
 
1016
                        goto fetch_cont;
 
1017
                    } else {
 
1018
                        min = getprimmin(proc);
 
1019
                        max = getprimmax(proc);
 
1020
                    }
 
1021
                }
 
1022
                for (n = 0, arg = argl; arg != NIL; n++, arg = cdr(arg));
 
1023
                if (n < min) {
 
1024
                    err_logo(NOT_ENOUGH, NIL);
 
1025
                } else if (n > max && max >= 0) {
 
1026
                    err_logo(TOO_MUCH, NIL);
 
1027
                } else {
 
1028
                    goto apply_dispatch;
 
1029
                }
 
1030
            }
 
1031
        }
 
1032
    }
 
1033
    goto fetch_cont;
 
1034
 
 
1035
after_lambda:
 
1036
    reset_args(var);
 
1037
    restore(var);
 
1038
    goto fetch_cont;
 
1039
 
 
1040
all_done:
 
1041
    tailcall = oldtailcall;
 
1042
    ift_iff_flag = old_ift_iff;
 
1043
    restore2(fun,ufun);
 
1044
    reset_args(var);
 
1045
    restore2(var,this_line);
 
1046
    return(val);
 
1047
}