2
* Copyright (c) 2002 by The XFree86 Project, Inc.
4
* Permission is hereby granted, free of charge, to any person obtaining a
5
* copy of this software and associated documentation files (the "Software"),
6
* to deal in the Software without restriction, including without limitation
7
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
8
* and/or sell copies of the Software, and to permit persons to whom the
9
* Software is furnished to do so, subject to the following conditions:
11
* The above copyright notice and this permission notice shall be included in
12
* all copies or substantial portions of the Software.
14
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17
* THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
18
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
19
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
* Except as contained in this notice, the name of the XFree86 Project shall
23
* not be used in advertising or otherwise to promote the sale, use or other
24
* dealings in this Software without prior written authorization from the
27
* Author: Paulo C�sar Pereira de Andrade
30
/* $XFree86: xc/programs/xedit/lisp/compile.c,v 1.14 2003/01/30 02:46:25 paulo Exp $ */
32
#define VARIABLE_USED 0x0001
33
#define VARIABLE_ARGUMENT 0x0002
38
static void ComPredicate(LispCom*, LispBuiltin*, LispBytePredicate);
39
static void ComReturnFrom(LispCom*, LispBuiltin*, int);
41
static int ComConstantp(LispCom*, LispObj*);
42
static void ComAddVariable(LispCom*, LispObj*, LispObj*);
43
static int ComGetVariable(LispCom*, LispObj*);
44
static void ComVariableSetFlag(LispCom*, LispAtom*, int);
45
#define COM_VARIABLE_USED(atom) \
46
ComVariableSetFlag(com, atom, VARIABLE_USED)
47
#define COM_VARIABLE_ARGUMENT(atom) \
48
ComVariableSetFlag(com, atom, VARIABLE_ARGUMENT)
50
static int FindIndex(void*, void**, int);
51
static int compare(const void*, const void*);
52
static int BuildTablePointer(void*, void***, int*);
54
static void ComLabel(LispCom*, LispObj*);
55
static void ComPush(LispCom*, LispObj*, LispObj*, int, int, int);
56
static int ComCall(LispCom*, LispArgList*, LispObj*, LispObj*, int, int, int);
57
static void ComFuncall(LispCom*, LispObj*, LispObj*, int);
58
static void ComProgn(LispCom*, LispObj*);
59
static void ComEval(LispCom*, LispObj*);
61
static void ComRecursiveCall(LispCom*, LispArgList*, LispObj*, LispObj*);
62
static void ComInlineCall(LispCom*, LispArgList*, LispObj*, LispObj*, LispObj*);
64
static void ComMacroBackquote(LispCom*, LispObj*);
65
static void ComMacroCall(LispCom*, LispArgList*, LispObj*, LispObj*, LispObj*);
66
static LispObj *ComMacroExpandBackquote(LispCom*, LispObj*);
67
static LispObj *ComMacroExpand(LispCom*, LispObj*);
68
static LispObj *ComMacroExpandFuncall(LispCom*, LispObj*, LispObj*);
69
static LispObj *ComMacroExpandEval(LispCom*, LispObj*);
75
Com_And(LispCom *com, LispBuiltin *builtin)
85
/* Evaluate first argument */
86
ComEval(com, CAR(args));
89
/* If more than one argument, create jump list */
91
CodeTree *tree = NULL, *group;
93
group = NEW_TREE(CodeTreeJumpIf);
94
group->code = XBC_JUMPNIL;
96
for (; CONSP(args); args = CDR(args)) {
97
ComEval(com, CAR(args));
98
tree = NEW_TREE(CodeTreeJumpIf);
99
tree->code = XBC_JUMPNIL;
103
/* Finish form the last CodeTree code is changed to sign the
104
* end of the AND list */
105
group->code = XBC_NOOP;
111
/* Identity of AND is T */
112
com_Bytecode(com, XBC_T);
116
Com_Block(LispCom *com, LispBuiltin *builtin)
118
block name &rest body
122
LispObj *name, *body;
127
if (name != NIL && name != T && !SYMBOLP(name))
128
LispDestroy("%s: %s cannot name a block",
129
STRFUN(builtin), STROBJ(name));
131
CompileIniBlock(com, LispBlockTag, name);
133
CompileFiniBlock(com);
136
/* Just load NIL without starting an empty block */
137
com_Bytecode(com, XBC_NIL);
141
Com_C_r(LispCom *com, LispBuiltin *builtin)
151
desc = STRFUN(builtin);
152
if (*desc == 'F') /* FIRST */
154
else if (*desc == 'R') /* REST */
157
/* Check if it is a list of constants */
158
while (desc[1] != 'R')
161
while (*desc != 'C') {
162
com_Bytecode(com, *desc == 'A' ? XBC_CAR : XBC_CDR);
168
Com_Cond(LispCom *com, LispBuiltin *builtin)
174
LispObj *code, *body;
175
CodeTree *group, *tree;
182
for (; CONSP(body); body = CDR(body)) {
186
ComEval(com, CAR(code));
187
tree = NEW_TREE(CodeTreeCond);
190
tree->code = XBC_JUMPNIL;
192
/* The code to execute if the test is true */
193
ComProgn(com, CDR(code));
194
/* Add a node signaling the end of the PROGN code */
195
tree = NEW_TREE(CodeTreeCond);
196
tree->code = XBC_JUMPT;
203
com_Bytecode(com, XBC_NIL);
205
/* Where to jump after T progn */
206
group->code = XBC_NOOP;
210
Com_Cons(LispCom *com, LispBuiltin *builtin)
220
if (ComConstantp(com, car) && ComConstantp(com, cdr))
221
com_BytecodeCons(com, XBC_CCONS, car, cdr);
223
++com->stack.cpstack;
224
if (com->stack.pstack < com->stack.cpstack)
225
com->stack.pstack = com->stack.cpstack;
227
com_Bytecode(com, XBC_CSTAR);
229
com_Bytecode(com, XBC_CFINI);
230
--com->stack.cpstack;
235
Com_Consp(LispCom *com, LispBuiltin *builtin)
240
ComPredicate(com, builtin, XBP_CONSP);
244
Com_Dolist(LispCom *com, LispBuiltin *builtin)
246
dolist init &rest body
250
LispObj *symbol, *list, *result;
251
LispObj *init, *body;
252
CodeTree *group, *tree;
259
CHECK_SYMBOL(symbol);
260
CHECK_CONSTANT(symbol);
270
if (CONSP(CDR(init)))
271
LispDestroy("%s: too many arguments %s",
272
STRFUN(builtin), STROBJ(CDR(init)));
277
/* Generate code for the body of the form.
278
* The generated code uses two objects unavailable to user code,
281
* (let ((? list) (item NIL))
283
* . ; the DOT object as a label
285
* (setq item (car ?))
286
* @body ; code to be executed
297
/* XXX All of the logic below should be simplified at some time
298
* by adding more opcodes for compound operations ... */
300
/* Relative offsets the locally added variables will have at run time */
301
unbound = lisp__data.env.length - lisp__data.env.lex;
304
/* Start BLOCK NIL */
306
CompileIniBlock(com, LispBlockTag, NIL);
308
/* Add the <?> variable */
309
ComPush(com, UNBOUND, list, 1, 0, 0);
310
/* Add the <item> variable */
311
ComPush(com, symbol, NIL, 0, 0, 0);
312
/* Stack length is increased */
313
CompileStackEnter(com, 2, 0);
316
com->block->bind += 2;
317
lisp__data.env.head += 2;
319
/* Remember that iteration variable is used even if it not referenced */
320
COM_VARIABLE_USED(symbol->data.atom);
322
/* Initialize the TAGBODY */
324
CompileIniBlock(com, LispBlockBody, NIL);
326
/* Create the <.> label */
329
/* Load <?> variable */
330
com_BytecodeShort(com, XBC_LOAD, unbound);
331
/* Check if <?> is a list */
332
com_BytecodeChar(com, XBC_PRED, XBP_CONSP);
334
/* Start WHEN block */
335
group = NEW_TREE(CodeTreeJumpIf);
336
group->code = XBC_JUMPNIL;
338
com_BytecodeShort(com, XBC_LOAD, unbound);
340
com_Bytecode(com, XBC_CAR);
341
/* Store it in <item> */
342
com_BytecodeShort(com, XBC_SET, item);
347
com_BytecodeShort(com, XBC_LOAD, unbound);
349
com_Bytecode(com, XBC_CDR);
350
/* Change value of <?> */
351
com_BytecodeShort(com, XBC_SET, unbound);
354
tree = NEW_TREE(CodeTreeGo);
355
tree->data.object = DOT;
357
/* Finish WHEN block */
358
tree = NEW_TREE(CodeTreeJumpIf);
359
tree->code = XBC_NOOP;
362
/* Finish the TAGBODY */
363
CompileFiniBlock(com);
366
/* Set <item> to NIL, in case result references it...
367
* Loaded value is NIL as the CONSP predicate */
368
com_BytecodeShort(com, XBC_SET, item);
370
/* Evaluate <result> */
371
ComEval(com, result);
373
/* Unbind variables */
374
lisp__data.env.head -= 2;
375
lisp__data.env.length -= 2;
376
com->block->bind -= 2;
378
/* Stack length is reduced. */
379
CompileStackLeave(com, 2, 0);
381
/* Finish BLOCK NIL */
382
CompileFiniBlock(com);
387
Com_Eq(LispCom *com, LispBuiltin *builtin)
395
LispObj *left, *right;
402
CompileStackEnter(com, 1, 1);
403
/* Just like preparing to call a builtin function */
405
com_Bytecode(com, XBC_PUSH);
406
/* The second argument is now loaded */
409
/* Compare arguments and restore builtin stack */
410
name = STRFUN(builtin);
416
code = name[5] == 'P' ? XBC_EQUALP : XBC_EQUAL;
422
com_Bytecode(com, code);
424
CompileStackLeave(com, 1, 1);
428
Com_Go(LispCom *com, LispBuiltin *builtin)
444
if (block->type == LispBlockClosure || block->type == LispBlockBody)
451
if (!block || block->type != LispBlockBody)
452
LispDestroy("%s called not within a block", STRFUN(builtin));
454
/* Unbind any local variables */
455
com_Unbind(com, bind);
456
tree = NEW_TREE(CodeTreeGo);
457
tree->data.object = tag;
461
Com_If(LispCom *com, LispBuiltin *builtin)
463
if test then &optional else
466
CodeTree *group, *tree;
467
LispObj *test, *then, *oelse;
473
/* Build code to execute test */
476
/* Add jump node to use if test is NIL */
477
group = NEW_TREE(CodeTreeJumpIf);
478
group->code = XBC_JUMPNIL;
483
if (oelse != UNSPEC) {
484
/* Remember start of NIL code */
485
tree = NEW_TREE(CodeTreeJump);
486
tree->code = XBC_JUMP;
493
/* Remember jump of T code */
494
tree = NEW_TREE(CodeTreeJumpIf);
495
tree->code = XBC_NOOP;
500
Com_Last(LispCom *com, LispBuiltin *builtin)
502
last list &optional count
505
LispObj *list, *count;
511
CompileStackEnter(com, 1, 1);
512
com_Bytecode(com, XBC_PUSH);
516
CompileStackLeave(com, 1, 1);
517
com_Bytecode(com, XBC_LAST);
521
Com_Length(LispCom *com, LispBuiltin *builtin)
528
sequence = ARGUMENT(0);
530
ComEval(com, sequence);
531
com_Bytecode(com, XBC_LENGTH);
535
Com_Let(LispCom *com, LispBuiltin *builtin)
541
LispObj *symbol, *value, *pair;
543
LispObj *init, *body;
549
/* If no local variables */
555
/* Could optimize if the body is empty and the
556
* init form is known to have no side effects */
558
for (count = 0; CONSP(init); init = CDR(init), count++) {
565
if (CDR(pair) != NIL)
566
LispDestroy("%s: too much arguments to initialize %s",
567
STRFUN(builtin), STROBJ(symbol));
576
CHECK_SYMBOL(symbol);
577
CHECK_CONSTANT(symbol);
579
/* Add the variable */
580
ComPush(com, symbol, value, 1, 0, 0);
583
/* Stack length is increased */
584
CompileStackEnter(com, count, 0);
585
/* Bind the added variables */
586
com_Bind(com, count);
587
com->block->bind += count;
588
lisp__data.env.head += count;
589
/* Generate code for the body of the form */
591
/* Unbind the added variables */
592
lisp__data.env.head -= count;
593
lisp__data.env.length -= count;
594
com->block->bind -= count;
595
com_Unbind(com, count);
596
/* Stack length is reduced. */
597
CompileStackLeave(com, count, 0);
601
Com_Letx(LispCom *com, LispBuiltin *builtin)
607
LispObj *symbol, *value, *pair;
609
LispObj *init, *body;
615
/* If no local variables */
621
/* Could optimize if the body is empty and the
622
* init form is known to have no side effects */
624
for (count = 0; CONSP(init); init = CDR(init), count++) {
631
if (CDR(pair) != NIL)
632
LispDestroy("%s: too much arguments to initialize %s",
633
STRFUN(builtin), STROBJ(symbol));
642
CHECK_SYMBOL(symbol);
643
CHECK_CONSTANT(symbol);
645
/* LET* is identical to &AUX arguments, just bind the symbol */
646
ComPush(com, symbol, value, 1, 0, 0);
647
/* Every added variable is binded */
649
/* Must be binded at compile time also */
650
++lisp__data.env.head;
654
/* Generate code for the body of the form */
655
CompileStackEnter(com, count, 0);
657
com_Unbind(com, count);
658
com->block->bind -= count;
659
lisp__data.env.head -= count;
660
lisp__data.env.length -= count;
661
CompileStackLeave(com, count, 0);
665
Com_Listp(LispCom *com, LispBuiltin *builtin)
670
ComPredicate(com, builtin, XBP_LISTP);
674
Com_Loop(LispCom *com, LispBuiltin *builtin)
679
CodeTree *tree, *group;
684
/* Start NIL block */
685
CompileIniBlock(com, LispBlockTag, NIL);
687
/* Insert node to mark LOOP start */
688
tree = NEW_TREE(CodeTreeJump);
689
tree->code = XBC_NOOP;
695
/* XXX bytecode.c code require that blocks have at least one opcode */
696
com_Bytecode(com, XBC_NIL);
698
/* Insert node to jump of start of LOOP */
699
group = NEW_TREE(CodeTreeJump);
700
group->code = XBC_JUMP;
703
/* Finish NIL block */
704
CompileFiniBlock(com);
708
Com_Nthcdr(LispCom *com, LispBuiltin *builtin)
713
LispObj *oindex, *list;
716
oindex = ARGUMENT(0);
718
ComEval(com, oindex);
719
CompileStackEnter(com, 1, 1);
720
com_Bytecode(com, XBC_PUSH);
722
CompileStackLeave(com, 1, 1);
723
com_Bytecode(com, XBC_NTHCDR);
727
Com_Null(LispCom *com, LispBuiltin *builtin)
737
com_Bytecode(com, XBC_T);
738
else if (ComConstantp(com, list))
739
com_Bytecode(com, XBC_NIL);
742
com_Bytecode(com, XBC_INV);
747
Com_Numberp(LispCom *com, LispBuiltin *builtin)
752
ComPredicate(com, builtin, XBP_NUMBERP);
756
Com_Or(LispCom *com, LispBuiltin *builtin)
766
/* Evaluate first argument */
767
ComEval(com, CAR(args));
770
/* If more than one argument, create jump list */
772
CodeTree *tree = NULL, *group;
774
group = NEW_TREE(CodeTreeJumpIf);
775
group->code = XBC_JUMPT;
777
for (; CONSP(args); args = CDR(args)) {
778
ComEval(com, CAR(args));
779
tree = NEW_TREE(CodeTreeJumpIf);
780
tree->code = XBC_JUMPT;
784
/* Finish form the last CodeTree code is changed to sign the
785
* end of the AND list */
786
group->code = XBC_NOOP;
791
/* Identity of OR is NIL */
792
com_Bytecode(com, XBC_NIL);
796
Com_Progn(LispCom *com, LispBuiltin *builtin)
809
Com_Return(LispCom *com, LispBuiltin *builtin)
811
return &optional result
814
ComReturnFrom(com, builtin, 0);
818
Com_ReturnFrom(LispCom *com, LispBuiltin *builtin)
820
return-from name &optional result
823
ComReturnFrom(com, builtin, 1);
827
Com_Rplac_(LispCom *com, LispBuiltin *builtin)
829
rplac[ad] place value
832
LispObj *place, *value;
837
CompileStackEnter(com, 1, 1);
839
com_Bytecode(com, XBC_PUSH);
841
com_Bytecode(com, STRFUN(builtin)[5] == 'A' ? XBC_RPLACA : XBC_RPLACD);
842
CompileStackLeave(com, 1, 1);
846
Com_Setq(LispCom *com, LispBuiltin *builtin)
852
LispObj *form, *symbol, *value;
856
for (; CONSP(form); form = CDR(form)) {
858
CHECK_SYMBOL(symbol);
859
CHECK_CONSTANT(symbol);
862
LispDestroy("%s: odd number of arguments", STRFUN(builtin));
864
/* Generate code to load value */
866
offset = ComGetVariable(com, symbol);
868
com_Set(com, offset);
870
com_SetSym(com, symbol->data.atom);
875
Com_Tagbody(LispCom *com, LispBuiltin *builtin)
885
CompileIniBlock(com, LispBlockBody, NIL);
887
/* Tagbody returns NIL */
888
com_Bytecode(com, XBC_NIL);
889
CompileFiniBlock(com);
892
/* Tagbody always returns NIL */
893
com_Bytecode(com, XBC_NIL);
897
Com_Unless(LispCom *com, LispBuiltin *builtin)
899
unless test &rest body
902
CodeTree *group, *tree;
903
LispObj *test, *body;
908
/* Generate code to evaluate test */
910
/* Add node after test */
911
group = NEW_TREE(CodeTreeJumpIf);
912
group->code = XBC_JUMPT;
913
/* Generate NIL code */
915
/* Insert node to know where to jump if test is T */
916
tree = NEW_TREE(CodeTreeJumpIf);
917
tree->code = XBC_NOOP;
922
Com_Until(LispCom *com, LispBuiltin *builtin)
924
until test &rest body
927
CodeTree *tree, *group, *ltree, *lgroup;
928
LispObj *test, *body;
933
/* Insert node to mark LOOP start */
934
ltree = NEW_TREE(CodeTreeJump);
935
ltree->code = XBC_NOOP;
937
/* Build code for test */
939
group = NEW_TREE(CodeTreeJumpIf);
940
group->code = XBC_JUMPT;
945
/* Insert node to jump to test again */
946
lgroup = NEW_TREE(CodeTreeJump);
947
lgroup->code = XBC_JUMP;
948
lgroup->group = ltree;
950
/* Insert node to know where to jump if test is T */
951
tree = NEW_TREE(CodeTreeJumpIf);
952
tree->code = XBC_NOOP;
957
Com_When(LispCom *com, LispBuiltin *builtin)
962
CodeTree *group, *tree;
963
LispObj *test, *body;
968
/* Generate code to evaluate test */
970
/* Add node after test */
971
group = NEW_TREE(CodeTreeJumpIf);
972
group->code = XBC_JUMPNIL;
973
/* Generate T code */
975
/* Insert node to know where to jump if test is NIL */
976
tree = NEW_TREE(CodeTreeJumpIf);
977
tree->code = XBC_NOOP;
982
Com_While(LispCom *com, LispBuiltin *builtin)
984
while test &rest body
987
CodeTree *tree, *group, *ltree, *lgroup;
988
LispObj *test, *body;
993
/* Insert node to mark LOOP start */
994
ltree = NEW_TREE(CodeTreeJump);
995
ltree->code = XBC_NOOP;
997
/* Build code for test */
999
group = NEW_TREE(CodeTreeJumpIf);
1000
group->code = XBC_JUMPNIL;
1003
ComProgn(com, body);
1005
/* Insert node to jump to test again */
1006
lgroup = NEW_TREE(CodeTreeJump);
1007
lgroup->code = XBC_JUMP;
1008
lgroup->group = ltree;
1010
/* Insert node to know where to jump if test is NIL */
1011
tree = NEW_TREE(CodeTreeJumpIf);
1012
tree->code = XBC_NOOP;
1013
group->group = tree;
1017
/***********************************************************************
1018
* Com_XXX helper functions
1019
***********************************************************************/
1021
ComPredicate(LispCom *com, LispBuiltin *builtin, LispBytePredicate predicate)
1025
object = ARGUMENT(0);
1027
if (ComConstantp(com, object)) {
1028
switch (predicate) {
1030
com_Bytecode(com, CONSP(object) ? XBC_T : XBC_NIL);
1033
com_Bytecode(com, CONSP(object) || object == NIL ?
1037
com_Bytecode(com, NUMBERP(object) ? XBC_T : XBC_NIL);
1042
ComEval(com, object);
1043
com_BytecodeChar(com, XBC_PRED, predicate);
1047
/* XXX Could receive an argument telling if is the last statement in the
1048
* block(s), i.e. if a jump opcode should be generated or just the
1049
* evaluation of the returned value. Probably this is better done in
1050
* an optimization step. */
1052
ComReturnFrom(LispCom *com, LispBuiltin *builtin, int from)
1056
LispObj *name, *result;
1057
CodeBlock *block = com->block;
1060
result = ARGUMENT(1);
1064
result = ARGUMENT(0);
1067
if (result == UNSPEC)
1072
if (block->type == LispBlockClosure)
1073
/* A function call */
1075
else if (block->type == LispBlockTag && block->tag == name)
1077
block = block->prev;
1079
bind += block->bind;
1082
if (!block || block->tag != name)
1083
LispDestroy("%s: no visible %s block", STRFUN(builtin), STROBJ(name));
1085
/* Generate code to load result */
1086
ComEval(com, result);
1088
/* Check for added variables that the jump is skiping the unbind opcode */
1089
com_Unbind(com, bind);
1091
tree = NEW_TREE(CodeTreeReturn);
1092
tree->data.block = block;
1095
/***********************************************************************
1097
***********************************************************************/
1099
ComConstantp(LispCom *com, LispObj *object)
1101
switch (OBJECT_TYPE(object)) {
1103
/* Keywords are guaranteed to evaluate to itself */
1104
if (object->data.atom->package == lisp__data.keyword)
1111
/* Need macro expansion, these are special abstract objects */
1113
case LispBackquote_t:
1115
case LispFunctionQuote_t:
1118
/* Anything else is a literal constant */
1127
FindIndex(void *item, void **table, int length)
1134
while (left <= right) {
1135
i = (left + right) >> 1;
1136
cmp = (char*)item - (char*)table[i];
1149
compare(const void *left, const void *right)
1151
long cmp = *(char**)left - *(char**)right;
1153
return (cmp < 0 ? -1 : 1);
1157
BuildTablePointer(void *pointer, void ***pointers, int *num_pointers)
1161
if ((i = FindIndex(pointer, *pointers, *num_pointers)) < 0) {
1162
*pointers = LispRealloc(*pointers,
1163
sizeof(void*) * (*num_pointers + 1));
1164
(*pointers)[*num_pointers] = pointer;
1165
if (++*num_pointers > 1)
1166
qsort(*pointers, *num_pointers, sizeof(void*), compare);
1167
i = FindIndex(pointer, *pointers, *num_pointers);
1174
ComAddVariable(LispCom *com, LispObj *symbol, LispObj *value)
1176
LispAtom *atom = symbol->data.atom;
1178
if (atom && atom->string && !com->macro) {
1179
int i, length = com->block->variables.length;
1181
i = BuildTablePointer(atom, (void***)&com->block->variables.symbols,
1182
&com->block->variables.length);
1184
if (com->block->variables.length != length) {
1185
com->block->variables.flags =
1186
LispRealloc(com->block->variables.flags,
1187
com->block->variables.length * sizeof(int));
1189
/* Variable was inserted in the middle of the list */
1191
memmove(com->block->variables.flags + i + 1,
1192
com->block->variables.flags + i,
1193
(length - i) * sizeof(int));
1195
com->block->variables.flags[i] = 0;
1199
LispAddVar(symbol, value);
1203
ComGetVariable(LispCom *com, LispObj *symbol)
1206
int i, base, offset;
1209
name = symbol->data.atom;
1210
if (name->constant) {
1211
if (name->package == lisp__data.keyword)
1212
/* Just load <symbol> from the byte stream, keywords are
1213
* guaranteed to evaluate to itself. */
1214
return (SYMBOL_KEYWORD);
1215
return (SYMBOL_CONSTANT);
1218
offset = name->offset;
1220
base = lisp__data.env.lex;
1221
i = lisp__data.env.head - 1;
1223
/* If variable is local */
1224
if (offset <= i && offset >= com->lex && lisp__data.env.names[offset] == id) {
1225
COM_VARIABLE_USED(name);
1226
/* Relative offset */
1227
return (offset - base);
1230
/* name->offset may have been changed in a macro expansion */
1231
for (; i >= com->lex; i--)
1232
if (lisp__data.env.names[i] == id) {
1234
COM_VARIABLE_USED(name);
1238
if (!name->a_object) {
1240
LispWarning("variable %s is neither declared nor bound",
1244
/* Not found, resolve <symbol> at run time */
1245
return (SYMBOL_UNBOUND);
1249
ComVariableSetFlag(LispCom *com, LispAtom *atom, int flag)
1252
CodeBlock *block = com->block;
1255
i = FindIndex(atom, (void**)block->variables.symbols,
1256
block->variables.length);
1258
block->variables.flags[i] |= flag;
1259
/* Descend block list if an argument to function being called
1260
* has the same name as a bound variable in the current function.
1262
if ((flag & VARIABLE_ARGUMENT) ||
1263
!(block->variables.flags[i] & VARIABLE_ARGUMENT))
1266
block = block->prev;
1270
/***********************************************************************
1271
* Bytecode compiler functions
1272
***********************************************************************/
1274
ComLabel(LispCom *com, LispObj *label)
1279
for (i = 0; i < com->block->tagbody.length; i++)
1280
if (label == com->block->tagbody.labels[i])
1281
LispDestroy("TAGBODY: tag %s specified more than once",
1284
if (com->block->tagbody.length >= com->block->tagbody.space) {
1285
com->block->tagbody.labels =
1286
LispRealloc(com->block->tagbody.labels,
1287
sizeof(LispObj*) * (com->block->tagbody.space + 8));
1288
/* Reserve space, will be used at link time when
1289
* resolving GO jumps. */
1290
com->block->tagbody.codes =
1291
LispRealloc(com->block->tagbody.codes,
1292
sizeof(CodeTree*) * (com->block->tagbody.space + 8));
1293
com->block->tagbody.space += 8;
1296
com->block->tagbody.labels[com->block->tagbody.length++] = label;
1297
tree = NEW_TREE(CodeTreeLabel);
1298
tree->data.object = label;
1302
ComPush(LispCom *com, LispObj *symbol, LispObj *value,
1303
int eval, int builtin, int compile)
1305
/* If <compile> is set, it is pushing an argument to one of
1306
* Com_XXX functions. */
1309
lisp__data.stack.values[lisp__data.stack.length++] = value;
1311
ComAddVariable(com, symbol, value);
1315
/* If <com->macro> is set, it is expanding a macro, just add the local
1316
* variable <symbol> bounded to <value>, so that it will be available
1317
* when calling the interpreter to expand the macro. */
1318
else if (com->macro) {
1319
ComAddVariable(com, symbol, value);
1323
/* If <eval> is set, it must generate the opcodes to evaluate <value>.
1324
* If <value> is a constant, just generate the opcodes to load it. */
1325
else if (eval && !ComConstantp(com, value)) {
1326
switch (OBJECT_TYPE(value)) {
1328
int offset = ComGetVariable(com, value);
1331
/* Load <value> from user stack at the relative offset */
1333
com_LoadPush(com, offset);
1335
com_LoadLet(com, offset, symbol->data.atom);
1337
/* ComConstantp() does not return true for this, as the
1338
* current value must be computed. */
1339
else if (offset == SYMBOL_CONSTANT) {
1340
value = value->data.atom->property->value;
1342
com_LoadConPush(com, value);
1344
com_LoadConLet(com, value, symbol->data.atom);
1347
/* Load value bound to <value> at run time */
1349
com_LoadSymPush(com, value->data.atom);
1351
com_LoadSymLet(com, value->data.atom,
1357
/* Generate code to evaluate <value> */
1358
ComEval(com, value);
1360
com_Bytecode(com, XBC_PUSH);
1362
com_Let(com, symbol->data.atom);
1366
/* Remember <symbol> will be bound, <value> only matters for
1367
* the Com_XXX functions */
1369
lisp__data.stack.values[lisp__data.stack.length++] = value;
1371
ComAddVariable(com, symbol, value);
1376
/* Load <value> as a constant in builtin stack */
1377
com_LoadConPush(com, value);
1378
lisp__data.stack.values[lisp__data.stack.length++] = value;
1381
/* Load <value> as a constant in stack */
1382
com_LoadConLet(com, value, symbol->data.atom);
1383
/* Remember <symbol> will be bound */
1384
ComAddVariable(com, symbol, value);
1388
/* This function does almost the same job as LispMakeEnvironment, but
1389
* it is not optimized for speed, as it is not building argument lists
1390
* to user code, but to Com_XXX functions, or helping in generating the
1391
* opcodes to load arguments at bytecode run time. */
1393
ComCall(LispCom *com, LispArgList *alist,
1394
LispObj *name, LispObj *values,
1395
int eval, int builtin, int compile)
1399
LispObj **symbols, **defaults, **sforms;
1402
base = lisp__data.stack.length;
1403
/* This should never be executed, but make the check for safety */
1404
if (base + alist->num_arguments > lisp__data.stack.space) {
1407
while (base + alist->num_arguments > lisp__data.stack.space);
1411
base = lisp__data.env.length;
1413
desc = alist->description;
1418
goto optional_label;
1430
/* Normal arguments */
1433
symbols = alist->normals.symbols;
1434
count = alist->normals.num_symbols;
1435
for (; i < count && CONSP(values); i++, values = CDR(values)) {
1436
ComPush(com, symbols[i], CAR(values), eval, builtin, compile);
1437
if (!builtin && !com->macro)
1438
COM_VARIABLE_ARGUMENT(symbols[i]->data.atom);
1441
LispDestroy("%s: too few arguments", STROBJ(name));
1445
goto optional_label;
1460
count = alist->optionals.num_symbols;
1461
symbols = alist->optionals.symbols;
1462
defaults = alist->optionals.defaults;
1463
sforms = alist->optionals.sforms;
1464
for (; i < count && CONSP(values); i++, values = CDR(values)) {
1465
ComPush(com, symbols[i], CAR(values), eval, builtin, compile);
1466
if (!builtin && !com->macro)
1467
COM_VARIABLE_ARGUMENT(symbols[i]->data.atom);
1469
ComPush(com, sforms[i], T, 0, builtin, compile);
1470
if (!builtin && !com->macro)
1471
COM_VARIABLE_ARGUMENT(sforms[i]->data.atom);
1474
for (; i < count; i++) {
1477
int head = lisp__data.env.head;
1480
lisp__data.env.head = lisp__data.env.length;
1481
/* default arguments are evaluated for macros */
1482
ComPush(com, symbols[i], defaults[i], 1, 0, compile);
1484
COM_VARIABLE_ARGUMENT(symbols[i]->data.atom);
1485
lisp__data.env.head = head;
1489
ComPush(com, symbols[i], defaults[i], eval, 1, compile);
1491
ComPush(com, sforms[i], NIL, 0, builtin, compile);
1492
if (!builtin && !com->macro)
1493
COM_VARIABLE_ARGUMENT(sforms[i]->data.atom);
1513
LispObj *val, *karg, **keys;
1515
count = alist->keys.num_symbols;
1516
symbols = alist->keys.symbols;
1517
defaults = alist->keys.defaults;
1518
sforms = alist->keys.sforms;
1519
keys = alist->keys.keys;
1521
/* Check if arguments are correctly specified */
1522
for (karg = values; CONSP(karg); karg = CDR(karg)) {
1524
if (KEYWORDP(val)) {
1525
for (i = 0; i < alist->keys.num_symbols; i++)
1526
if (!keys[i] && symbols[i] == val)
1530
else if (!builtin &&
1531
QUOTEP(val) && SYMBOLP(val->data.quote)) {
1532
for (i = 0; i < alist->keys.num_symbols; i++)
1533
if (keys[i] && ATOMID(keys[i]) == ATOMID(val->data.quote))
1538
/* Just make the error test true */
1539
i = alist->keys.num_symbols;
1541
if (i == alist->keys.num_symbols) {
1542
/* If not in argument specification list... */
1543
char function_name[36];
1545
strcpy(function_name, STROBJ(name));
1546
LispDestroy("%s: invalid keyword %s",
1547
function_name, STROBJ(val));
1552
LispDestroy("%s: &KEY needs arguments as pairs",
1557
for (i = 0; i < alist->keys.num_symbols; i++) {
1560
if (!builtin && keys[i]) {
1561
Atom_id atom = ATOMID(keys[i]);
1563
/* Special keyword specification, need to compare ATOMID
1564
* and keyword specification must be a quoted object */
1565
for (karg = values; CONSP(karg); karg = CDR(karg)) {
1567
if (QUOTEP(val) && atom == ATOMID(val->data.quote)) {
1577
/* Normal keyword specification, can compare object pointers,
1578
* as they point to the same object in the keyword package */
1579
for (karg = values; CONSP(karg); karg = CDR(karg)) {
1580
/* Don't check if argument is a valid keyword or
1581
* special quoted keyword */
1582
if (symbols[i] == CAR(karg)) {
1591
/* Add the variable to environment */
1593
ComPush(com, symbols[i], val, eval, builtin, compile);
1595
ComPush(com, sforms[i], T, 0, builtin, compile);
1598
/* default arguments are evaluated for macros */
1601
int head = lisp__data.env.head;
1604
lisp__data.env.head = lisp__data.env.length;
1605
ComPush(com, symbols[i], val, eval, 0, compile);
1606
lisp__data.env.head = head;
1610
ComPush(com, symbols[i], val, eval, builtin, compile);
1612
ComPush(com, sforms[i], NIL, 0, builtin, compile);
1614
if (!builtin && !com->macro) {
1615
COM_VARIABLE_ARGUMENT(symbols[i]->data.atom);
1617
COM_VARIABLE_ARGUMENT(sforms[i]->data.atom);
1623
/* &KEY uses all remaining arguments */
1627
goto finished_label;
1632
if (!eval || !CONSP(values) || (compile && !builtin))
1633
ComPush(com, alist->rest, values, eval, builtin, compile);
1636
LispObj *list, *car = NIL;
1637
int count, constantp;
1639
/* Count number of arguments and check if it is a list of constants */
1640
for (count = 0, constantp = 1, list = values;
1642
list = CDR(list), count++) {
1644
if (!ComConstantp(com, car))
1648
string = builtin ? ATOMID(name) : NULL;
1649
/* XXX FIXME should have a flag indicating if function call
1650
* change the &REST arguments even if it is a constant list
1651
* (or if the returned value may be changed). */
1652
if (string && (count < MAX_BCONS || constantp) &&
1653
strcmp(string, "LIST") &&
1654
strcmp(string, "APPLY") && /* XXX depends on function argument */
1655
strcmp(string, "VECTOR") &&
1656
/* Append does not copy the last/single list */
1657
(strcmp(string, "APPEND") || !CONSP(car))) {
1659
/* If the builtin function changes the &REST parameters, must
1660
* define a Com_XXX function for it. */
1661
ComPush(com, alist->rest, values, 0, builtin, compile);
1664
CompileStackEnter(com, count - 1, 1);
1665
for (; CONSP(CDR(values)); values = CDR(values)) {
1666
/* Evaluate this argument */
1667
ComEval(com, CAR(values));
1668
/* Save result in builtin stack */
1669
com_Bytecode(com, XBC_PUSH);
1671
CompileStackLeave(com, count - 1, 1);
1672
/* The last argument is not saved in the stack */
1673
ComEval(com, CAR(values));
1675
com_Bytecode(com, XBC_BCONS + (count - 1));
1679
/* Allocate a fresh list of cons */
1681
/* Generate code to load object */
1682
ComEval(com, CAR(values));
1684
com->stack.cpstack += 2;
1685
if (com->stack.pstack < com->stack.cpstack)
1686
com->stack.pstack = com->stack.cpstack;
1687
/* Start building a gc protected list, with the loaded value */
1688
com_Bytecode(com, XBC_LSTAR);
1690
for (values = CDR(values); CONSP(values); values = CDR(values)) {
1691
/* Generate code to load object */
1692
ComEval(com, CAR(values));
1694
/* Add loaded value to gc protected list */
1695
com_Bytecode(com, XBC_LCONS);
1698
/* Finish gc protected list */
1699
com_Bytecode(com, XBC_LFINI);
1701
/* Push loaded value */
1703
com_Bytecode(com, XBC_PUSH);
1705
com_Let(com, alist->rest->data.atom);
1707
/* Remember this symbol will be bound */
1708
ComAddVariable(com, alist->rest, values);
1710
com->stack.cpstack -= 2;
1713
if (!builtin && !com->macro)
1714
COM_VARIABLE_ARGUMENT(alist->rest->data.atom);
1716
goto finished_label;
1722
count = alist->auxs.num_symbols;
1723
symbols = alist->auxs.symbols;
1724
defaults = alist->auxs.initials;
1725
if (!builtin && !compile) {
1729
lisp__data.env.head = lisp__data.env.length;
1730
for (; i < count; i++) {
1731
ComPush(com, symbols[i], defaults[i], 1, 0, 0);
1733
COM_VARIABLE_ARGUMENT(symbols[i]->data.atom);
1734
++lisp__data.env.head;
1739
for (; i < count; i++) {
1740
ComPush(com, symbols[i], defaults[i], eval, builtin, compile);
1741
if (!builtin && !com->macro)
1742
COM_VARIABLE_ARGUMENT(symbols[i]->data.atom);
1748
LispDestroy("%s: too many arguments", STROBJ(name));
1752
lisp__data.stack.base = base;
1754
lisp__data.env.head = lisp__data.env.length;
1760
ComFuncall(LispCom *com, LispObj *function, LispObj *arguments, int eval)
1765
LispBuiltin *builtin;
1768
switch (OBJECT_TYPE(function)) {
1769
case LispFunction_t:
1770
function = function->data.atom->object;
1772
atom = function->data.atom;
1773
alist = atom->property->alist;
1775
if (atom->a_builtin) {
1776
builtin = atom->property->fun.builtin;
1777
compile = builtin->compile != NULL;
1780
* o expanding a macro
1781
* o calling a builtin special form
1782
* o builtin function is a macro
1783
* don't evaluate arguments. */
1784
if (com->macro || compile || builtin->type == LispMacro)
1787
if (!com->macro && builtin->type == LispMacro) {
1788
/* Set flag of variable used, in case variable is only
1789
* used as a builtin macro argument. */
1792
for (obj = arguments; CONSP(obj); obj = CDR(obj)) {
1793
if (SYMBOLP(CAR(obj)))
1794
COM_VARIABLE_USED(CAR(obj)->data.atom);
1799
if (!compile && !com->macro)
1800
CompileStackEnter(com, alist->num_arguments, 1);
1802
/* Build argument list in the interpreter stacks */
1803
base = ComCall(com, alist, function, arguments,
1806
/* If <compile> is set, it is a special form */
1808
builtin->compile(com, builtin);
1810
/* Else, generate opcodes to call builtin function */
1812
com_Call(com, alist->num_arguments, builtin);
1813
CompileStackLeave(com, alist->num_arguments, 1);
1815
lisp__data.stack.base = lisp__data.stack.length = base;
1818
else if (atom->a_function) {
1821
lambda = atom->property->fun.function;
1822
macro = lambda->funtype == LispMacro;
1824
/* If <macro> is set, expand macro */
1826
ComMacroCall(com, alist, function, lambda, arguments);
1829
if (com->toplevel->type == LispBlockClosure &&
1830
com->toplevel->tag == function)
1831
ComRecursiveCall(com, alist, function, arguments);
1834
ComInlineCall(com, alist, function, arguments,
1835
lambda->data.lambda.code);
1837
com_Funcall(com, function, arguments);
1842
else if (atom->a_defstruct &&
1843
atom->property->structure.function != STRUCT_NAME &&
1844
atom->property->structure.function != STRUCT_CONSTRUCTOR) {
1845
LispObj *definition = atom->property->structure.definition;
1847
if (!CONSP(arguments) || CONSP(CDR(arguments)))
1848
LispDestroy("%s: too %s arguments", atom->string,
1849
CONSP(arguments) ? "many" : "few");
1851
ComEval(com, CAR(arguments));
1852
if (atom->property->structure.function == STRUCT_CHECK)
1853
com_Structp(com, definition);
1856
atom->property->structure.function, definition);
1858
else if (atom->a_compiled) {
1860
CompileStackEnter(com, alist->num_arguments, 0);
1862
/* Build argument list in the interpreter stacks */
1863
base = ComCall(com, alist, function, arguments, 1, 0, 0);
1864
com_Bytecall(com, alist->num_arguments,
1865
atom->property->fun.function);
1866
CompileStackLeave(com, alist->num_arguments, 0);
1867
lisp__data.env.head = lisp__data.env.length = base;
1871
/* Not yet defined function/macro. */
1873
LispWarning("call to undefined function %s", atom->string);
1874
com_Funcall(com, function, arguments);
1879
lambda = function->data.lambda.code;
1880
alist = (LispArgList*)function->data.lambda.name->data.opaque.data;
1881
ComInlineCall(com, alist, NIL, arguments, lambda->data.lambda.code);
1885
if (CAR(function) == Olambda) {
1886
function = EVAL(function);
1887
if (LAMBDAP(function)) {
1890
GC_PROTECT(function);
1891
lambda = function->data.lambda.code;
1892
alist = (LispArgList*)function->data.lambda.name->data.opaque.data;
1893
ComInlineCall(com, alist, NIL, arguments, lambda->data.lambda.code);
1900
/* XXX If bytecode objects are made available, should
1901
* handle it here. */
1902
LispDestroy("EVAL: %s is invalid as a function",
1909
/* Generate opcodes for an implicit PROGN */
1911
ComProgn(LispCom *com, LispObj *code)
1914
for (; CONSP(code); code = CDR(code))
1915
ComEval(com, CAR(code));
1918
/* If no code to execute, empty PROGN returns NIL */
1919
com_Bytecode(com, XBC_NIL);
1922
/* Generate opcodes to evaluate <object>. */
1924
ComEval(LispCom *com, LispObj *object)
1929
switch (OBJECT_TYPE(object)) {
1932
ComLabel(com, object);
1934
offset = ComGetVariable(com, object);
1936
/* Load from user stack at relative offset */
1937
com_Load(com, offset);
1938
else if (offset == SYMBOL_KEYWORD)
1939
com_LoadCon(com, object);
1940
else if (offset == SYMBOL_CONSTANT)
1941
/* Symbol defined as constant, just load it's value */
1942
com_LoadCon(com, LispGetVar(object));
1944
/* Load value bound to symbol at run time */
1945
com_LoadSym(com, object->data.atom);
1950
/* Macro expansion may be done in the object form */
1953
ComFuncall(com, CAR(object), CDR(object), 1);
1958
com_LoadCon(com, object->data.quote);
1961
case LispBackquote_t:
1962
/* Macro expansion is stored in the current value of com->form */
1963
ComMacroBackquote(com, object);
1967
LispDestroy("EVAL: comma outside of backquote");
1970
case LispFunctionQuote_t:
1971
object = object->data.quote;
1972
if (SYMBOLP(object))
1973
object = LispSymbolFunction(object);
1974
else if (CONSP(object) && CAR(object) == Olambda) {
1975
/* object will only be associated with bytecode later,
1976
* so, make sure it is protected until compilation finishes */
1977
object = EVAL(object);
1978
RPLACD(com->plist, CONS(CAR(com->plist), CDR(com->plist)));
1979
RPLACA(com->plist, object);
1982
LispDestroy("FUNCTION: %s is not a function", STROBJ(object));
1983
com_LoadCon(com, object);
1988
ComLabel(com, object);
1994
/* Constant object */
1995
com_LoadCon(com, object);
2000
/***********************************************************************
2001
* Lambda expansion helper functions
2002
***********************************************************************/
2004
ComRecursiveCall(LispCom *com, LispArgList *alist,
2005
LispObj *name, LispObj *arguments)
2010
lex = lisp__data.env.lex;
2014
/* Generate code to push function arguments in the stack */
2015
base = ComCall(com, alist, name, arguments, 1, 0, 0);
2017
/* Stack will grow this amount */
2018
CompileStackEnter(com, alist->num_arguments, 0);
2021
/* Make the variables available at run time */
2022
com_Bind(com, alist->num_arguments);
2023
com->block->bind += alist->num_arguments;
2026
com_BytecodeChar(com, XBC_LETREC, alist->num_arguments);
2029
/* The variables are now unbound */
2030
com_Unbind(com, alist->num_arguments);
2031
com->block->bind -= alist->num_arguments;
2034
/* Stack length is reduced */
2035
CompileStackLeave(com, alist->num_arguments, 0);
2039
lisp__data.env.lex = lex;
2040
lisp__data.env.head = lisp__data.env.length = base;
2044
ComInlineCall(LispCom *com, LispArgList *alist,
2045
LispObj *name, LispObj *arguments, LispObj *lambda)
2050
lex = lisp__data.env.lex;
2053
/* Start the inline function block */
2054
CompileIniBlock(com, LispBlockClosure, name);
2056
/* Generate code to push function arguments in the stack */
2057
base = ComCall(com, alist, name, arguments, 1, 0, 0);
2059
/* Stack will grow this amount */
2060
CompileStackEnter(com, alist->num_arguments, 0);
2062
/* Make the variables available at run time */
2063
com_Bind(com, alist->num_arguments);
2064
com->block->bind += alist->num_arguments;
2066
/* Expand the lambda list */
2067
ComProgn(com, lambda);
2069
/* The variables are now unbound */
2070
com_Unbind(com, alist->num_arguments);
2071
com->block->bind -= alist->num_arguments;
2073
/* Stack length is reduced */
2074
CompileStackLeave(com, alist->num_arguments, 0);
2076
/* Finish the inline function block */
2077
CompileFiniBlock(com);
2081
lisp__data.env.lex = lex;
2082
lisp__data.env.head = lisp__data.env.length = base;
2085
/***********************************************************************
2086
* Macro expansion helper functions.
2087
***********************************************************************/
2089
ComMacroExpandBackquote(LispCom *com, LispObj *object)
2091
return (LispEvalBackquote(object->data.quote, 1));
2095
ComMacroExpandFuncall(LispCom *com, LispObj *function, LispObj *arguments)
2097
return (LispFuncall(function, arguments, 1));
2101
ComMacroExpandEval(LispCom *com, LispObj *object)
2105
switch (OBJECT_TYPE(object)) {
2107
result = LispGetVar(object);
2109
/* Macro expansion requires bounded symbols */
2111
LispDestroy("EVAL: the variable %s is unbound",
2116
result = ComMacroExpandFuncall(com, CAR(object), CDR(object));
2120
result = object->data.quote;
2123
case LispBackquote_t:
2124
result = ComMacroExpandBackquote(com, object);
2128
LispDestroy("EVAL: comma outside of backquote");
2130
case LispFunctionQuote_t:
2131
result = EVAL(object);
2143
ComMacroExpand(LispCom *com, LispObj *lambda)
2145
LispObj *result, **presult = &result, **plambda;
2146
int jumped, *pjumped = &jumped, backquote, *pbackquote = &backquote;
2149
int interpreter_lex, interpreter_head, interpreter_base;
2151
/* Save interpreter state */
2152
interpreter_base = lisp__data.stack.length;
2153
interpreter_head = lisp__data.env.length;
2154
interpreter_lex = lisp__data.env.lex;
2156
/* Use the variables */
2160
*pbackquote = !CONSP(lambda);
2162
block = LispBeginBlock(NIL, LispBlockProtect);
2163
if (setjmp(block->jmp) == 0) {
2165
for (; CONSP(lambda); lambda = CDR(lambda))
2166
result = ComMacroExpandEval(com, CAR(lambda));
2169
result = ComMacroExpandBackquote(com, lambda);
2173
LispEndBlock(block);
2175
/* If tried to jump out of the macro expansion block */
2176
if (!lisp__data.destroyed && jumped)
2177
LispDestroy("*** EVAL: bad jump in macro expansion");
2179
/* Macro expansion did something wrong */
2180
if (lisp__data.destroyed) {
2181
LispMessage("*** EVAL: aborting macro expansion");
2185
/* Restore interpreter state */
2186
lisp__data.env.lex = interpreter_lex;
2187
lisp__data.stack.length = interpreter_base;
2188
lisp__data.env.head = lisp__data.env.length = interpreter_head;
2194
ComMacroCall(LispCom *com, LispArgList *alist,
2195
LispObj *name, LispObj *lambda, LispObj *arguments)
2201
base = ComCall(com, alist, name, arguments, 0, 0, 0);
2202
body = lambda->data.lambda.code;
2203
body = ComMacroExpand(com, body);
2205
lisp__data.env.head = lisp__data.env.length = base;
2207
/* Macro is expanded, store the result */
2208
CAR(com->form) = body;
2213
ComMacroBackquote(LispCom *com, LispObj *lambda)
2218
body = ComMacroExpand(com, lambda);
2221
/* Macro is expanded, store the result */
2222
CAR(com->form) = body;
2224
com_LoadCon(com, body);