15dfecf96Smrg/* 25dfecf96Smrg * Copyright (c) 2002 by The XFree86 Project, Inc. 35dfecf96Smrg * 45dfecf96Smrg * Permission is hereby granted, free of charge, to any person obtaining a 55dfecf96Smrg * copy of this software and associated documentation files (the "Software"), 65dfecf96Smrg * to deal in the Software without restriction, including without limitation 75dfecf96Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 85dfecf96Smrg * and/or sell copies of the Software, and to permit persons to whom the 95dfecf96Smrg * Software is furnished to do so, subject to the following conditions: 105dfecf96Smrg * 115dfecf96Smrg * The above copyright notice and this permission notice shall be included in 125dfecf96Smrg * all copies or substantial portions of the Software. 135dfecf96Smrg * 145dfecf96Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 155dfecf96Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 165dfecf96Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 175dfecf96Smrg * THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 185dfecf96Smrg * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF 195dfecf96Smrg * OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 205dfecf96Smrg * SOFTWARE. 215dfecf96Smrg * 225dfecf96Smrg * Except as contained in this notice, the name of the XFree86 Project shall 235dfecf96Smrg * not be used in advertising or otherwise to promote the sale, use or other 245dfecf96Smrg * dealings in this Software without prior written authorization from the 255dfecf96Smrg * XFree86 Project. 265dfecf96Smrg * 275dfecf96Smrg * Author: Paulo César Pereira de Andrade 285dfecf96Smrg */ 295dfecf96Smrg 305dfecf96Smrg/* $XFree86: xc/programs/xedit/lisp/compile.c,v 1.15tsi Exp $ */ 315dfecf96Smrg 325dfecf96Smrg#define VARIABLE_USED 0x0001 335dfecf96Smrg#define VARIABLE_ARGUMENT 0x0002 345dfecf96Smrg 355dfecf96Smrg/* 365dfecf96Smrg * Prototypes 375dfecf96Smrg */ 385dfecf96Smrgstatic void ComPredicate(LispCom*, LispBuiltin*, LispBytePredicate); 395dfecf96Smrgstatic void ComReturnFrom(LispCom*, LispBuiltin*, int); 405dfecf96Smrg 415dfecf96Smrgstatic int ComConstantp(LispCom*, LispObj*); 425dfecf96Smrgstatic void ComAddVariable(LispCom*, LispObj*, LispObj*); 435dfecf96Smrgstatic int ComGetVariable(LispCom*, LispObj*); 445dfecf96Smrgstatic void ComVariableSetFlag(LispCom*, LispAtom*, int); 455dfecf96Smrg#define COM_VARIABLE_USED(atom) \ 465dfecf96Smrg ComVariableSetFlag(com, atom, VARIABLE_USED) 475dfecf96Smrg#define COM_VARIABLE_ARGUMENT(atom) \ 485dfecf96Smrg ComVariableSetFlag(com, atom, VARIABLE_ARGUMENT) 495dfecf96Smrg 505dfecf96Smrgstatic int FindIndex(void*, void**, int); 515dfecf96Smrgstatic int compare(const void*, const void*); 525dfecf96Smrgstatic int BuildTablePointer(void*, void***, int*); 535dfecf96Smrg 545dfecf96Smrgstatic void ComLabel(LispCom*, LispObj*); 555dfecf96Smrgstatic void ComPush(LispCom*, LispObj*, LispObj*, int, int, int); 565dfecf96Smrgstatic int ComCall(LispCom*, LispArgList*, LispObj*, LispObj*, int, int, int); 575dfecf96Smrgstatic void ComFuncall(LispCom*, LispObj*, LispObj*, int); 585dfecf96Smrgstatic void ComProgn(LispCom*, LispObj*); 595dfecf96Smrgstatic void ComEval(LispCom*, LispObj*); 605dfecf96Smrg 615dfecf96Smrgstatic void ComRecursiveCall(LispCom*, LispArgList*, LispObj*, LispObj*); 625dfecf96Smrgstatic void ComInlineCall(LispCom*, LispArgList*, LispObj*, LispObj*, LispObj*); 635dfecf96Smrg 645dfecf96Smrgstatic void ComMacroBackquote(LispCom*, LispObj*); 655dfecf96Smrgstatic void ComMacroCall(LispCom*, LispArgList*, LispObj*, LispObj*, LispObj*); 665dfecf96Smrgstatic LispObj *ComMacroExpandBackquote(LispCom*, LispObj*); 675dfecf96Smrgstatic LispObj *ComMacroExpand(LispCom*, LispObj*); 685dfecf96Smrgstatic LispObj *ComMacroExpandFuncall(LispCom*, LispObj*, LispObj*); 695dfecf96Smrgstatic LispObj *ComMacroExpandEval(LispCom*, LispObj*); 705dfecf96Smrg 715dfecf96Smrg/* 725dfecf96Smrg * Implementation 735dfecf96Smrg */ 745dfecf96Smrgvoid 755dfecf96SmrgCom_And(LispCom *com, LispBuiltin *builtin) 765dfecf96Smrg/* 775dfecf96Smrg and &rest args 785dfecf96Smrg */ 795dfecf96Smrg{ 805dfecf96Smrg LispObj *args; 815dfecf96Smrg 825dfecf96Smrg args = ARGUMENT(0); 835dfecf96Smrg 845dfecf96Smrg if (CONSP(args)) { 855dfecf96Smrg /* Evaluate first argument */ 865dfecf96Smrg ComEval(com, CAR(args)); 875dfecf96Smrg args = CDR(args); 885dfecf96Smrg 895dfecf96Smrg /* If more than one argument, create jump list */ 905dfecf96Smrg if (CONSP(args)) { 915dfecf96Smrg CodeTree *tree = NULL, *group; 925dfecf96Smrg 935dfecf96Smrg group = NEW_TREE(CodeTreeJumpIf); 945dfecf96Smrg group->code = XBC_JUMPNIL; 955dfecf96Smrg 965dfecf96Smrg for (; CONSP(args); args = CDR(args)) { 975dfecf96Smrg ComEval(com, CAR(args)); 985dfecf96Smrg tree = NEW_TREE(CodeTreeJumpIf); 995dfecf96Smrg tree->code = XBC_JUMPNIL; 1005dfecf96Smrg group->group = tree; 1015dfecf96Smrg group = tree; 1025dfecf96Smrg } 1035dfecf96Smrg /* Finish form the last CodeTree code is changed to sign the 1045dfecf96Smrg * end of the AND list */ 1055dfecf96Smrg group->code = XBC_NOOP; 1065dfecf96Smrg if (group) 1075dfecf96Smrg group->group = tree; 1085dfecf96Smrg } 1095dfecf96Smrg } 1105dfecf96Smrg else 1115dfecf96Smrg /* Identity of AND is T */ 1125dfecf96Smrg com_Bytecode(com, XBC_T); 1135dfecf96Smrg} 1145dfecf96Smrg 1155dfecf96Smrgvoid 1165dfecf96SmrgCom_Block(LispCom *com, LispBuiltin *builtin) 1175dfecf96Smrg/* 1185dfecf96Smrg block name &rest body 1195dfecf96Smrg */ 1205dfecf96Smrg{ 1215dfecf96Smrg 1225dfecf96Smrg LispObj *name, *body; 1235dfecf96Smrg 1245dfecf96Smrg body = ARGUMENT(1); 1255dfecf96Smrg name = ARGUMENT(0); 1265dfecf96Smrg 1275dfecf96Smrg if (name != NIL && name != T && !SYMBOLP(name)) 1285dfecf96Smrg LispDestroy("%s: %s cannot name a block", 1295dfecf96Smrg STRFUN(builtin), STROBJ(name)); 1305dfecf96Smrg if (CONSP(body)) { 1315dfecf96Smrg CompileIniBlock(com, LispBlockTag, name); 1325dfecf96Smrg ComProgn(com, body); 1335dfecf96Smrg CompileFiniBlock(com); 1345dfecf96Smrg } 1355dfecf96Smrg else 1365dfecf96Smrg /* Just load NIL without starting an empty block */ 1375dfecf96Smrg com_Bytecode(com, XBC_NIL); 1385dfecf96Smrg} 1395dfecf96Smrg 1405dfecf96Smrgvoid 1415dfecf96SmrgCom_C_r(LispCom *com, LispBuiltin *builtin) 1425dfecf96Smrg/* 1435dfecf96Smrg c[ad]{1,4}r list 1445dfecf96Smrg */ 1455dfecf96Smrg{ 1465dfecf96Smrg LispObj *list; 147f765521fSmrg const char *desc; 1485dfecf96Smrg 1495dfecf96Smrg list = ARGUMENT(0); 1505dfecf96Smrg 1515dfecf96Smrg desc = STRFUN(builtin); 1525dfecf96Smrg if (*desc == 'F') /* FIRST */ 1535dfecf96Smrg desc = "CAR"; 1545dfecf96Smrg else if (*desc == 'R') /* REST */ 1555dfecf96Smrg desc = "CDR"; 1565dfecf96Smrg 1575dfecf96Smrg /* Check if it is a list of constants */ 1585dfecf96Smrg while (desc[1] != 'R') 1595dfecf96Smrg desc++; 1605dfecf96Smrg ComEval(com, list); 1615dfecf96Smrg while (*desc != 'C') { 1625dfecf96Smrg com_Bytecode(com, *desc == 'A' ? XBC_CAR : XBC_CDR); 1635dfecf96Smrg --desc; 1645dfecf96Smrg } 1655dfecf96Smrg} 1665dfecf96Smrg 1675dfecf96Smrgvoid 1685dfecf96SmrgCom_Cond(LispCom *com, LispBuiltin *builtin) 1695dfecf96Smrg/* 1705dfecf96Smrg cond &rest body 1715dfecf96Smrg */ 1725dfecf96Smrg{ 1735dfecf96Smrg int count; 1745dfecf96Smrg LispObj *code, *body; 1755dfecf96Smrg CodeTree *group, *tree; 1765dfecf96Smrg 1775dfecf96Smrg body = ARGUMENT(0); 1785dfecf96Smrg 1795dfecf96Smrg count = 0; 1805dfecf96Smrg group = NULL; 1815dfecf96Smrg if (CONSP(body)) { 1825dfecf96Smrg for (; CONSP(body); body = CDR(body)) { 1835dfecf96Smrg code = CAR(body); 1845dfecf96Smrg CHECK_CONS(code); 1855dfecf96Smrg ++count; 1865dfecf96Smrg ComEval(com, CAR(code)); 1875dfecf96Smrg tree = NEW_TREE(CodeTreeCond); 1885dfecf96Smrg if (group) 1895dfecf96Smrg group->group = tree; 1905dfecf96Smrg tree->code = XBC_JUMPNIL; 1915dfecf96Smrg group = tree; 1925dfecf96Smrg /* The code to execute if the test is true */ 1935dfecf96Smrg ComProgn(com, CDR(code)); 1945dfecf96Smrg /* Add a node signaling the end of the PROGN code */ 1955dfecf96Smrg tree = NEW_TREE(CodeTreeCond); 1965dfecf96Smrg tree->code = XBC_JUMPT; 1975dfecf96Smrg if (group) 1985dfecf96Smrg group->group = tree; 1995dfecf96Smrg group = tree; 2005dfecf96Smrg } 2015dfecf96Smrg } 2025dfecf96Smrg if (!count) 2035dfecf96Smrg com_Bytecode(com, XBC_NIL); 2045dfecf96Smrg else 2055dfecf96Smrg /* Where to jump after T progn */ 2065dfecf96Smrg group->code = XBC_NOOP; 2075dfecf96Smrg} 2085dfecf96Smrg 2095dfecf96Smrgvoid 2105dfecf96SmrgCom_Cons(LispCom *com, LispBuiltin *builtin) 2115dfecf96Smrg/* 2125dfecf96Smrg cons car cdr 2135dfecf96Smrg */ 2145dfecf96Smrg{ 2155dfecf96Smrg LispObj *car, *cdr; 2165dfecf96Smrg 2175dfecf96Smrg cdr = ARGUMENT(1); 2185dfecf96Smrg car = ARGUMENT(0); 2195dfecf96Smrg 2205dfecf96Smrg if (ComConstantp(com, car) && ComConstantp(com, cdr)) 2215dfecf96Smrg com_BytecodeCons(com, XBC_CCONS, car, cdr); 2225dfecf96Smrg else { 2235dfecf96Smrg ++com->stack.cpstack; 2245dfecf96Smrg if (com->stack.pstack < com->stack.cpstack) 2255dfecf96Smrg com->stack.pstack = com->stack.cpstack; 2265dfecf96Smrg ComEval(com, car); 2275dfecf96Smrg com_Bytecode(com, XBC_CSTAR); 2285dfecf96Smrg ComEval(com, cdr); 2295dfecf96Smrg com_Bytecode(com, XBC_CFINI); 2305dfecf96Smrg --com->stack.cpstack; 2315dfecf96Smrg } 2325dfecf96Smrg} 2335dfecf96Smrg 2345dfecf96Smrgvoid 2355dfecf96SmrgCom_Consp(LispCom *com, LispBuiltin *builtin) 2365dfecf96Smrg/* 2375dfecf96Smrg consp object 2385dfecf96Smrg */ 2395dfecf96Smrg{ 2405dfecf96Smrg ComPredicate(com, builtin, XBP_CONSP); 2415dfecf96Smrg} 2425dfecf96Smrg 2435dfecf96Smrgvoid 2445dfecf96SmrgCom_Dolist(LispCom *com, LispBuiltin *builtin) 2455dfecf96Smrg/* 2465dfecf96Smrg dolist init &rest body 2475dfecf96Smrg */ 2485dfecf96Smrg{ 2495dfecf96Smrg int unbound, item; 2505dfecf96Smrg LispObj *symbol, *list, *result; 2515dfecf96Smrg LispObj *init, *body; 2525dfecf96Smrg CodeTree *group, *tree; 2535dfecf96Smrg 2545dfecf96Smrg body = ARGUMENT(1); 2555dfecf96Smrg init = ARGUMENT(0); 2565dfecf96Smrg 2575dfecf96Smrg CHECK_CONS(init); 2585dfecf96Smrg symbol = CAR(init); 2595dfecf96Smrg CHECK_SYMBOL(symbol); 2605dfecf96Smrg CHECK_CONSTANT(symbol); 2615dfecf96Smrg init = CDR(init); 2625dfecf96Smrg if (CONSP(init)) { 2635dfecf96Smrg list = CAR(init); 2645dfecf96Smrg init = CDR(init); 2655dfecf96Smrg } 2665dfecf96Smrg else 2675dfecf96Smrg list = NIL; 2685dfecf96Smrg if (CONSP(init)) { 2695dfecf96Smrg result = CAR(init); 2705dfecf96Smrg if (CONSP(CDR(init))) 2715dfecf96Smrg LispDestroy("%s: too many arguments %s", 2725dfecf96Smrg STRFUN(builtin), STROBJ(CDR(init))); 2735dfecf96Smrg } 2745dfecf96Smrg else 2755dfecf96Smrg result = NIL; 2765dfecf96Smrg 2775dfecf96Smrg /* Generate code for the body of the form. 2785dfecf96Smrg * The generated code uses two objects unavailable to user code, 2795dfecf96Smrg * in the format: 2805dfecf96Smrg * (block NIL 2815dfecf96Smrg * (let ((? list) (item NIL)) 2825dfecf96Smrg * (tagbody 2835dfecf96Smrg * . ; the DOT object as a label 2845dfecf96Smrg * (when (consp list) 2855dfecf96Smrg * (setq item (car ?)) 2865dfecf96Smrg * @body ; code to be executed 2875dfecf96Smrg * (setq ? (cdr ?)) 2885dfecf96Smrg * (go .) 2895dfecf96Smrg * ) 2905dfecf96Smrg * ) 2915dfecf96Smrg * (setq item nil) 2925dfecf96Smrg * result 2935dfecf96Smrg * ) 2945dfecf96Smrg * ) 2955dfecf96Smrg */ 2965dfecf96Smrg 2975dfecf96Smrg /* XXX All of the logic below should be simplified at some time 2985dfecf96Smrg * by adding more opcodes for compound operations ... */ 2995dfecf96Smrg 3005dfecf96Smrg /* Relative offsets the locally added variables will have at run time */ 3015dfecf96Smrg unbound = lisp__data.env.length - lisp__data.env.lex; 3025dfecf96Smrg item = unbound + 1; 3035dfecf96Smrg 3045dfecf96Smrg /* Start BLOCK NIL */ 3055dfecf96Smrg FORM_ENTER(); 3065dfecf96Smrg CompileIniBlock(com, LispBlockTag, NIL); 3075dfecf96Smrg 3085dfecf96Smrg /* Add the <?> variable */ 3095dfecf96Smrg ComPush(com, UNBOUND, list, 1, 0, 0); 3105dfecf96Smrg /* Add the <item> variable */ 3115dfecf96Smrg ComPush(com, symbol, NIL, 0, 0, 0); 3125dfecf96Smrg /* Stack length is increased */ 3135dfecf96Smrg CompileStackEnter(com, 2, 0); 3145dfecf96Smrg /* Bind variables */ 3155dfecf96Smrg com_Bind(com, 2); 3165dfecf96Smrg com->block->bind += 2; 3175dfecf96Smrg lisp__data.env.head += 2; 3185dfecf96Smrg 3195dfecf96Smrg /* Remember that iteration variable is used even if it not referenced */ 3205dfecf96Smrg COM_VARIABLE_USED(symbol->data.atom); 3215dfecf96Smrg 3225dfecf96Smrg /* Initialize the TAGBODY */ 3235dfecf96Smrg FORM_ENTER(); 3245dfecf96Smrg CompileIniBlock(com, LispBlockBody, NIL); 3255dfecf96Smrg 3265dfecf96Smrg /* Create the <.> label */ 3275dfecf96Smrg ComLabel(com, DOT); 3285dfecf96Smrg 3295dfecf96Smrg /* Load <?> variable */ 3305dfecf96Smrg com_BytecodeShort(com, XBC_LOAD, unbound); 3315dfecf96Smrg /* Check if <?> is a list */ 3325dfecf96Smrg com_BytecodeChar(com, XBC_PRED, XBP_CONSP); 3335dfecf96Smrg 3345dfecf96Smrg /* Start WHEN block */ 3355dfecf96Smrg group = NEW_TREE(CodeTreeJumpIf); 3365dfecf96Smrg group->code = XBC_JUMPNIL; 3375dfecf96Smrg /* Load <?> again */ 3385dfecf96Smrg com_BytecodeShort(com, XBC_LOAD, unbound); 3395dfecf96Smrg /* Get CAR of <?> */ 3405dfecf96Smrg com_Bytecode(com, XBC_CAR); 3415dfecf96Smrg /* Store it in <item> */ 3425dfecf96Smrg com_BytecodeShort(com, XBC_SET, item); 3435dfecf96Smrg /* Execute @BODY */ 3445dfecf96Smrg ComProgn(com, body); 3455dfecf96Smrg 3465dfecf96Smrg /* Load <?> again */ 3475dfecf96Smrg com_BytecodeShort(com, XBC_LOAD, unbound); 3485dfecf96Smrg /* Get CDR of <?> */ 3495dfecf96Smrg com_Bytecode(com, XBC_CDR); 3505dfecf96Smrg /* Change value of <?> */ 3515dfecf96Smrg com_BytecodeShort(com, XBC_SET, unbound); 3525dfecf96Smrg 3535dfecf96Smrg /* GO back to <.> */ 3545dfecf96Smrg tree = NEW_TREE(CodeTreeGo); 3555dfecf96Smrg tree->data.object = DOT; 3565dfecf96Smrg 3575dfecf96Smrg /* Finish WHEN block */ 3585dfecf96Smrg tree = NEW_TREE(CodeTreeJumpIf); 3595dfecf96Smrg tree->code = XBC_NOOP; 3605dfecf96Smrg group->group = tree; 3615dfecf96Smrg 3625dfecf96Smrg /* Finish the TAGBODY */ 3635dfecf96Smrg CompileFiniBlock(com); 3645dfecf96Smrg FORM_LEAVE(); 3655dfecf96Smrg 3665dfecf96Smrg /* Set <item> to NIL, in case result references it... 3675dfecf96Smrg * Loaded value is NIL as the CONSP predicate */ 3685dfecf96Smrg com_BytecodeShort(com, XBC_SET, item); 3695dfecf96Smrg 3705dfecf96Smrg /* Evaluate <result> */ 3715dfecf96Smrg ComEval(com, result); 3725dfecf96Smrg 3735dfecf96Smrg /* Unbind variables */ 3745dfecf96Smrg lisp__data.env.head -= 2; 3755dfecf96Smrg lisp__data.env.length -= 2; 3765dfecf96Smrg com->block->bind -= 2; 3775dfecf96Smrg com_Unbind(com, 2); 3785dfecf96Smrg /* Stack length is reduced. */ 3795dfecf96Smrg CompileStackLeave(com, 2, 0); 3805dfecf96Smrg 3815dfecf96Smrg /* Finish BLOCK NIL */ 3825dfecf96Smrg CompileFiniBlock(com); 3835dfecf96Smrg FORM_LEAVE(); 3845dfecf96Smrg} 3855dfecf96Smrg 3865dfecf96Smrgvoid 3875dfecf96SmrgCom_Eq(LispCom *com, LispBuiltin *builtin) 3885dfecf96Smrg/* 3895dfecf96Smrg eq left right 3905dfecf96Smrg eql left right 3915dfecf96Smrg equal left right 3925dfecf96Smrg equalp left right 3935dfecf96Smrg */ 3945dfecf96Smrg{ 3955dfecf96Smrg LispObj *left, *right; 3965dfecf96Smrg LispByteOpcode code; 3975dfecf96Smrg char *name; 3985dfecf96Smrg 3995dfecf96Smrg right = ARGUMENT(1); 4005dfecf96Smrg left = ARGUMENT(0); 4015dfecf96Smrg 4025dfecf96Smrg CompileStackEnter(com, 1, 1); 4035dfecf96Smrg /* Just like preparing to call a builtin function */ 4045dfecf96Smrg ComEval(com, left); 4055dfecf96Smrg com_Bytecode(com, XBC_PUSH); 4065dfecf96Smrg /* The second argument is now loaded */ 4075dfecf96Smrg ComEval(com, right); 4085dfecf96Smrg 4095dfecf96Smrg /* Compare arguments and restore builtin stack */ 4105dfecf96Smrg name = STRFUN(builtin); 4115dfecf96Smrg switch (name[3]) { 4125dfecf96Smrg case 'L': 4135dfecf96Smrg code = XBC_EQL; 4145dfecf96Smrg break; 4155dfecf96Smrg case 'U': 4165dfecf96Smrg code = name[5] == 'P' ? XBC_EQUALP : XBC_EQUAL; 4175dfecf96Smrg break; 4185dfecf96Smrg default: 4195dfecf96Smrg code = XBC_EQ; 4205dfecf96Smrg break; 4215dfecf96Smrg } 4225dfecf96Smrg com_Bytecode(com, code); 4235dfecf96Smrg 4245dfecf96Smrg CompileStackLeave(com, 1, 1); 4255dfecf96Smrg} 4265dfecf96Smrg 4275dfecf96Smrgvoid 4285dfecf96SmrgCom_Go(LispCom *com, LispBuiltin *builtin) 4295dfecf96Smrg/* 4305dfecf96Smrg go tag 4315dfecf96Smrg */ 4325dfecf96Smrg{ 4335dfecf96Smrg int bind; 4345dfecf96Smrg LispObj *tag; 4355dfecf96Smrg CodeTree *tree; 4365dfecf96Smrg CodeBlock *block; 4375dfecf96Smrg 4385dfecf96Smrg tag = ARGUMENT(0); 4395dfecf96Smrg 4405dfecf96Smrg block = com->block; 4415dfecf96Smrg bind = block->bind; 4425dfecf96Smrg 4435dfecf96Smrg while (block) { 4445dfecf96Smrg if (block->type == LispBlockClosure || block->type == LispBlockBody) 4455dfecf96Smrg break; 4465dfecf96Smrg block = block->prev; 4475dfecf96Smrg if (block) 4485dfecf96Smrg bind += block->bind; 4495dfecf96Smrg } 4505dfecf96Smrg 4515dfecf96Smrg if (!block || block->type != LispBlockBody) 4525dfecf96Smrg LispDestroy("%s called not within a block", STRFUN(builtin)); 4535dfecf96Smrg 4545dfecf96Smrg /* Unbind any local variables */ 4555dfecf96Smrg com_Unbind(com, bind); 4565dfecf96Smrg tree = NEW_TREE(CodeTreeGo); 4575dfecf96Smrg tree->data.object = tag; 4585dfecf96Smrg} 4595dfecf96Smrg 4605dfecf96Smrgvoid 4615dfecf96SmrgCom_If(LispCom *com, LispBuiltin *builtin) 4625dfecf96Smrg/* 4635dfecf96Smrg if test then &optional else 4645dfecf96Smrg */ 4655dfecf96Smrg{ 4665dfecf96Smrg CodeTree *group, *tree; 4675dfecf96Smrg LispObj *test, *then, *oelse; 4685dfecf96Smrg 4695dfecf96Smrg oelse = ARGUMENT(2); 4705dfecf96Smrg then = ARGUMENT(1); 4715dfecf96Smrg test = ARGUMENT(0); 4725dfecf96Smrg 4735dfecf96Smrg /* Build code to execute test */ 4745dfecf96Smrg ComEval(com, test); 4755dfecf96Smrg 4765dfecf96Smrg /* Add jump node to use if test is NIL */ 4775dfecf96Smrg group = NEW_TREE(CodeTreeJumpIf); 4785dfecf96Smrg group->code = XBC_JUMPNIL; 4795dfecf96Smrg 4805dfecf96Smrg /* Build T code */ 4815dfecf96Smrg ComEval(com, then); 4825dfecf96Smrg 4835dfecf96Smrg if (oelse != UNSPEC) { 4845dfecf96Smrg /* Remember start of NIL code */ 4855dfecf96Smrg tree = NEW_TREE(CodeTreeJump); 4865dfecf96Smrg tree->code = XBC_JUMP; 4875dfecf96Smrg group->group = tree; 4885dfecf96Smrg group = tree; 4895dfecf96Smrg /* Build NIL code */ 4905dfecf96Smrg ComEval(com, oelse); 4915dfecf96Smrg } 4925dfecf96Smrg 4935dfecf96Smrg /* Remember jump of T code */ 4945dfecf96Smrg tree = NEW_TREE(CodeTreeJumpIf); 4955dfecf96Smrg tree->code = XBC_NOOP; 4965dfecf96Smrg group->group = tree; 4975dfecf96Smrg} 4985dfecf96Smrg 4995dfecf96Smrgvoid 5005dfecf96SmrgCom_Last(LispCom *com, LispBuiltin *builtin) 5015dfecf96Smrg/* 5025dfecf96Smrg last list &optional count 5035dfecf96Smrg */ 5045dfecf96Smrg{ 5055dfecf96Smrg LispObj *list, *count; 5065dfecf96Smrg 5075dfecf96Smrg count = ARGUMENT(1); 5085dfecf96Smrg list = ARGUMENT(0); 5095dfecf96Smrg 5105dfecf96Smrg ComEval(com, list); 5115dfecf96Smrg CompileStackEnter(com, 1, 1); 5125dfecf96Smrg com_Bytecode(com, XBC_PUSH); 5135dfecf96Smrg if (count == UNSPEC) 5145dfecf96Smrg count = FIXNUM(1); 5155dfecf96Smrg ComEval(com, count); 5165dfecf96Smrg CompileStackLeave(com, 1, 1); 5175dfecf96Smrg com_Bytecode(com, XBC_LAST); 5185dfecf96Smrg} 5195dfecf96Smrg 5205dfecf96Smrgvoid 5215dfecf96SmrgCom_Length(LispCom *com, LispBuiltin *builtin) 5225dfecf96Smrg/* 5235dfecf96Smrg length sequence 5245dfecf96Smrg */ 5255dfecf96Smrg{ 5265dfecf96Smrg LispObj *sequence; 5275dfecf96Smrg 5285dfecf96Smrg sequence = ARGUMENT(0); 5295dfecf96Smrg 5305dfecf96Smrg ComEval(com, sequence); 5315dfecf96Smrg com_Bytecode(com, XBC_LENGTH); 5325dfecf96Smrg} 5335dfecf96Smrg 5345dfecf96Smrgvoid 5355dfecf96SmrgCom_Let(LispCom *com, LispBuiltin *builtin) 5365dfecf96Smrg/* 5375dfecf96Smrg let init &rest body 5385dfecf96Smrg */ 5395dfecf96Smrg{ 5405dfecf96Smrg int count; 5415dfecf96Smrg LispObj *symbol, *value, *pair; 5425dfecf96Smrg 5435dfecf96Smrg LispObj *init, *body; 5445dfecf96Smrg 5455dfecf96Smrg body = ARGUMENT(1); 5465dfecf96Smrg init = ARGUMENT(0); 5475dfecf96Smrg 5485dfecf96Smrg if (init == NIL) { 5495dfecf96Smrg /* If no local variables */ 5505dfecf96Smrg ComProgn(com, body); 5515dfecf96Smrg return; 5525dfecf96Smrg } 5535dfecf96Smrg CHECK_CONS(init); 5545dfecf96Smrg 5555dfecf96Smrg /* Could optimize if the body is empty and the 5565dfecf96Smrg * init form is known to have no side effects */ 5575dfecf96Smrg 5585dfecf96Smrg for (count = 0; CONSP(init); init = CDR(init), count++) { 5595dfecf96Smrg pair = CAR(init); 5605dfecf96Smrg if (CONSP(pair)) { 5615dfecf96Smrg symbol = CAR(pair); 5625dfecf96Smrg pair = CDR(pair); 5635dfecf96Smrg if (CONSP(pair)) { 5645dfecf96Smrg value = CAR(pair); 5655dfecf96Smrg if (CDR(pair) != NIL) 5665dfecf96Smrg LispDestroy("%s: too much arguments to initialize %s", 5675dfecf96Smrg STRFUN(builtin), STROBJ(symbol)); 5685dfecf96Smrg } 5695dfecf96Smrg else 5705dfecf96Smrg value = NIL; 5715dfecf96Smrg } 5725dfecf96Smrg else { 5735dfecf96Smrg symbol = pair; 5745dfecf96Smrg value = NIL; 5755dfecf96Smrg } 5765dfecf96Smrg CHECK_SYMBOL(symbol); 5775dfecf96Smrg CHECK_CONSTANT(symbol); 5785dfecf96Smrg 5795dfecf96Smrg /* Add the variable */ 5805dfecf96Smrg ComPush(com, symbol, value, 1, 0, 0); 5815dfecf96Smrg } 5825dfecf96Smrg 5835dfecf96Smrg /* Stack length is increased */ 5845dfecf96Smrg CompileStackEnter(com, count, 0); 5855dfecf96Smrg /* Bind the added variables */ 5865dfecf96Smrg com_Bind(com, count); 5875dfecf96Smrg com->block->bind += count; 5885dfecf96Smrg lisp__data.env.head += count; 5895dfecf96Smrg /* Generate code for the body of the form */ 5905dfecf96Smrg ComProgn(com, body); 5915dfecf96Smrg /* Unbind the added variables */ 5925dfecf96Smrg lisp__data.env.head -= count; 5935dfecf96Smrg lisp__data.env.length -= count; 5945dfecf96Smrg com->block->bind -= count; 5955dfecf96Smrg com_Unbind(com, count); 5965dfecf96Smrg /* Stack length is reduced. */ 5975dfecf96Smrg CompileStackLeave(com, count, 0); 5985dfecf96Smrg} 5995dfecf96Smrg 6005dfecf96Smrgvoid 6015dfecf96SmrgCom_Letx(LispCom *com, LispBuiltin *builtin) 6025dfecf96Smrg/* 6035dfecf96Smrg let* init &rest body 6045dfecf96Smrg */ 6055dfecf96Smrg{ 6065dfecf96Smrg int count; 6075dfecf96Smrg LispObj *symbol, *value, *pair; 6085dfecf96Smrg 6095dfecf96Smrg LispObj *init, *body; 6105dfecf96Smrg 6115dfecf96Smrg body = ARGUMENT(1); 6125dfecf96Smrg init = ARGUMENT(0); 6135dfecf96Smrg 6145dfecf96Smrg if (init == NIL) { 6155dfecf96Smrg /* If no local variables */ 6165dfecf96Smrg ComProgn(com, body); 6175dfecf96Smrg return; 6185dfecf96Smrg } 6195dfecf96Smrg CHECK_CONS(body); 6205dfecf96Smrg 6215dfecf96Smrg /* Could optimize if the body is empty and the 6225dfecf96Smrg * init form is known to have no side effects */ 6235dfecf96Smrg 6245dfecf96Smrg for (count = 0; CONSP(init); init = CDR(init), count++) { 6255dfecf96Smrg pair = CAR(init); 6265dfecf96Smrg if (CONSP(pair)) { 6275dfecf96Smrg symbol = CAR(pair); 6285dfecf96Smrg pair = CDR(pair); 6295dfecf96Smrg if (CONSP(pair)) { 6305dfecf96Smrg value = CAR(pair); 6315dfecf96Smrg if (CDR(pair) != NIL) 6325dfecf96Smrg LispDestroy("%s: too much arguments to initialize %s", 6335dfecf96Smrg STRFUN(builtin), STROBJ(symbol)); 6345dfecf96Smrg } 6355dfecf96Smrg else 6365dfecf96Smrg value = NIL; 6375dfecf96Smrg } 6385dfecf96Smrg else { 6395dfecf96Smrg symbol = pair; 6405dfecf96Smrg value = NIL; 6415dfecf96Smrg } 6425dfecf96Smrg CHECK_SYMBOL(symbol); 6435dfecf96Smrg CHECK_CONSTANT(symbol); 6445dfecf96Smrg 6455dfecf96Smrg /* LET* is identical to &AUX arguments, just bind the symbol */ 6465dfecf96Smrg ComPush(com, symbol, value, 1, 0, 0); 6475dfecf96Smrg /* Every added variable is binded */ 6485dfecf96Smrg com_Bind(com, 1); 6495dfecf96Smrg /* Must be binded at compile time also */ 6505dfecf96Smrg ++lisp__data.env.head; 6515dfecf96Smrg ++com->block->bind; 6525dfecf96Smrg } 6535dfecf96Smrg 6545dfecf96Smrg /* Generate code for the body of the form */ 6555dfecf96Smrg CompileStackEnter(com, count, 0); 6565dfecf96Smrg ComProgn(com, body); 6575dfecf96Smrg com_Unbind(com, count); 6585dfecf96Smrg com->block->bind -= count; 6595dfecf96Smrg lisp__data.env.head -= count; 6605dfecf96Smrg lisp__data.env.length -= count; 6615dfecf96Smrg CompileStackLeave(com, count, 0); 6625dfecf96Smrg} 6635dfecf96Smrg 6645dfecf96Smrgvoid 6655dfecf96SmrgCom_Listp(LispCom *com, LispBuiltin *builtin) 6665dfecf96Smrg/* 6675dfecf96Smrg listp object 6685dfecf96Smrg */ 6695dfecf96Smrg{ 6705dfecf96Smrg ComPredicate(com, builtin, XBP_LISTP); 6715dfecf96Smrg} 6725dfecf96Smrg 6735dfecf96Smrgvoid 6745dfecf96SmrgCom_Loop(LispCom *com, LispBuiltin *builtin) 6755dfecf96Smrg/* 6765dfecf96Smrg loop &rest body 6775dfecf96Smrg */ 6785dfecf96Smrg{ 6795dfecf96Smrg CodeTree *tree, *group; 6805dfecf96Smrg LispObj *body; 6815dfecf96Smrg 6825dfecf96Smrg body = ARGUMENT(0); 6835dfecf96Smrg 6845dfecf96Smrg /* Start NIL block */ 6855dfecf96Smrg CompileIniBlock(com, LispBlockTag, NIL); 6865dfecf96Smrg 6875dfecf96Smrg /* Insert node to mark LOOP start */ 6885dfecf96Smrg tree = NEW_TREE(CodeTreeJump); 6895dfecf96Smrg tree->code = XBC_NOOP; 6905dfecf96Smrg 6915dfecf96Smrg /* Execute @BODY */ 6925dfecf96Smrg if (CONSP(body)) 6935dfecf96Smrg ComProgn(com, body); 6945dfecf96Smrg else 6955dfecf96Smrg /* XXX bytecode.c code require that blocks have at least one opcode */ 6965dfecf96Smrg com_Bytecode(com, XBC_NIL); 6975dfecf96Smrg 6985dfecf96Smrg /* Insert node to jump of start of LOOP */ 6995dfecf96Smrg group = NEW_TREE(CodeTreeJump); 7005dfecf96Smrg group->code = XBC_JUMP; 7015dfecf96Smrg group->group = tree; 7025dfecf96Smrg 7035dfecf96Smrg /* Finish NIL block */ 7045dfecf96Smrg CompileFiniBlock(com); 7055dfecf96Smrg} 7065dfecf96Smrg 7075dfecf96Smrgvoid 7085dfecf96SmrgCom_Nthcdr(LispCom *com, LispBuiltin *builtin) 7095dfecf96Smrg/* 7105dfecf96Smrg nthcdr index list 7115dfecf96Smrg */ 7125dfecf96Smrg{ 7135dfecf96Smrg LispObj *oindex, *list; 7145dfecf96Smrg 7155dfecf96Smrg list = ARGUMENT(1); 7165dfecf96Smrg oindex = ARGUMENT(0); 7175dfecf96Smrg 7185dfecf96Smrg ComEval(com, oindex); 7195dfecf96Smrg CompileStackEnter(com, 1, 1); 7205dfecf96Smrg com_Bytecode(com, XBC_PUSH); 7215dfecf96Smrg ComEval(com, list); 7225dfecf96Smrg CompileStackLeave(com, 1, 1); 7235dfecf96Smrg com_Bytecode(com, XBC_NTHCDR); 7245dfecf96Smrg} 7255dfecf96Smrg 7265dfecf96Smrgvoid 7275dfecf96SmrgCom_Null(LispCom *com, LispBuiltin *builtin) 7285dfecf96Smrg/* 7295dfecf96Smrg null list 7305dfecf96Smrg */ 7315dfecf96Smrg{ 7325dfecf96Smrg LispObj *list; 7335dfecf96Smrg 7345dfecf96Smrg list = ARGUMENT(0); 7355dfecf96Smrg 7365dfecf96Smrg if (list == NIL) 7375dfecf96Smrg com_Bytecode(com, XBC_T); 7385dfecf96Smrg else if (ComConstantp(com, list)) 7395dfecf96Smrg com_Bytecode(com, XBC_NIL); 7405dfecf96Smrg else { 7415dfecf96Smrg ComEval(com, list); 7425dfecf96Smrg com_Bytecode(com, XBC_INV); 7435dfecf96Smrg } 7445dfecf96Smrg} 7455dfecf96Smrg 7465dfecf96Smrgvoid 7475dfecf96SmrgCom_Numberp(LispCom *com, LispBuiltin *builtin) 7485dfecf96Smrg/* 7495dfecf96Smrg numberp object 7505dfecf96Smrg */ 7515dfecf96Smrg{ 7525dfecf96Smrg ComPredicate(com, builtin, XBP_NUMBERP); 7535dfecf96Smrg} 7545dfecf96Smrg 7555dfecf96Smrgvoid 7565dfecf96SmrgCom_Or(LispCom *com, LispBuiltin *builtin) 7575dfecf96Smrg/* 7585dfecf96Smrg or &rest args 7595dfecf96Smrg */ 7605dfecf96Smrg{ 7615dfecf96Smrg LispObj *args; 7625dfecf96Smrg 7635dfecf96Smrg args = ARGUMENT(0); 7645dfecf96Smrg 7655dfecf96Smrg if (CONSP(args)) { 7665dfecf96Smrg /* Evaluate first argument */ 7675dfecf96Smrg ComEval(com, CAR(args)); 7685dfecf96Smrg args = CDR(args); 7695dfecf96Smrg 7705dfecf96Smrg /* If more than one argument, create jump list */ 7715dfecf96Smrg if (CONSP(args)) { 7725dfecf96Smrg CodeTree *tree = NULL, *group; 7735dfecf96Smrg 7745dfecf96Smrg group = NEW_TREE(CodeTreeJumpIf); 7755dfecf96Smrg group->code = XBC_JUMPT; 7765dfecf96Smrg 7775dfecf96Smrg for (; CONSP(args); args = CDR(args)) { 7785dfecf96Smrg ComEval(com, CAR(args)); 7795dfecf96Smrg tree = NEW_TREE(CodeTreeJumpIf); 7805dfecf96Smrg tree->code = XBC_JUMPT; 7815dfecf96Smrg group->group = tree; 7825dfecf96Smrg group = tree; 7835dfecf96Smrg } 7845dfecf96Smrg /* Finish form the last CodeTree code is changed to sign the 7855dfecf96Smrg * end of the AND list */ 7865dfecf96Smrg group->code = XBC_NOOP; 7875dfecf96Smrg group->group = tree; 7885dfecf96Smrg } 7895dfecf96Smrg } 7905dfecf96Smrg else 7915dfecf96Smrg /* Identity of OR is NIL */ 7925dfecf96Smrg com_Bytecode(com, XBC_NIL); 7935dfecf96Smrg} 7945dfecf96Smrg 7955dfecf96Smrgvoid 7965dfecf96SmrgCom_Progn(LispCom *com, LispBuiltin *builtin) 7975dfecf96Smrg/* 7985dfecf96Smrg progn &rest body 7995dfecf96Smrg */ 8005dfecf96Smrg{ 8015dfecf96Smrg LispObj *body; 8025dfecf96Smrg 8035dfecf96Smrg body = ARGUMENT(0); 8045dfecf96Smrg 8055dfecf96Smrg ComProgn(com, body); 8065dfecf96Smrg} 8075dfecf96Smrg 8085dfecf96Smrgvoid 8095dfecf96SmrgCom_Return(LispCom *com, LispBuiltin *builtin) 8105dfecf96Smrg/* 8115dfecf96Smrg return &optional result 8125dfecf96Smrg */ 8135dfecf96Smrg{ 8145dfecf96Smrg ComReturnFrom(com, builtin, 0); 8155dfecf96Smrg} 8165dfecf96Smrg 8175dfecf96Smrgvoid 8185dfecf96SmrgCom_ReturnFrom(LispCom *com, LispBuiltin *builtin) 8195dfecf96Smrg/* 8205dfecf96Smrg return-from name &optional result 8215dfecf96Smrg */ 8225dfecf96Smrg{ 8235dfecf96Smrg ComReturnFrom(com, builtin, 1); 8245dfecf96Smrg} 8255dfecf96Smrg 8265dfecf96Smrgvoid 8275dfecf96SmrgCom_Rplac_(LispCom *com, LispBuiltin *builtin) 8285dfecf96Smrg/* 8295dfecf96Smrg rplac[ad] place value 8305dfecf96Smrg */ 8315dfecf96Smrg{ 8325dfecf96Smrg LispObj *place, *value; 8335dfecf96Smrg 8345dfecf96Smrg value = ARGUMENT(1); 8355dfecf96Smrg place = ARGUMENT(0); 8365dfecf96Smrg 8375dfecf96Smrg CompileStackEnter(com, 1, 1); 8385dfecf96Smrg ComEval(com, place); 8395dfecf96Smrg com_Bytecode(com, XBC_PUSH); 8405dfecf96Smrg ComEval(com, value); 8415dfecf96Smrg com_Bytecode(com, STRFUN(builtin)[5] == 'A' ? XBC_RPLACA : XBC_RPLACD); 8425dfecf96Smrg CompileStackLeave(com, 1, 1); 8435dfecf96Smrg} 8445dfecf96Smrg 8455dfecf96Smrgvoid 8465dfecf96SmrgCom_Setq(LispCom *com, LispBuiltin *builtin) 8475dfecf96Smrg/* 8485dfecf96Smrg setq &rest form 8495dfecf96Smrg */ 8505dfecf96Smrg{ 8515dfecf96Smrg int offset; 8525dfecf96Smrg LispObj *form, *symbol, *value; 8535dfecf96Smrg 8545dfecf96Smrg form = ARGUMENT(0); 8555dfecf96Smrg 8565dfecf96Smrg for (; CONSP(form); form = CDR(form)) { 8575dfecf96Smrg symbol = CAR(form); 8585dfecf96Smrg CHECK_SYMBOL(symbol); 8595dfecf96Smrg CHECK_CONSTANT(symbol); 8605dfecf96Smrg form = CDR(form); 8615dfecf96Smrg if (!CONSP(form)) 8625dfecf96Smrg LispDestroy("%s: odd number of arguments", STRFUN(builtin)); 8635dfecf96Smrg value = CAR(form); 8645dfecf96Smrg /* Generate code to load value */ 8655dfecf96Smrg ComEval(com, value); 8665dfecf96Smrg offset = ComGetVariable(com, symbol); 8675dfecf96Smrg if (offset >= 0) 8685dfecf96Smrg com_Set(com, offset); 8695dfecf96Smrg else 8705dfecf96Smrg com_SetSym(com, symbol->data.atom); 8715dfecf96Smrg } 8725dfecf96Smrg} 8735dfecf96Smrg 8745dfecf96Smrgvoid 8755dfecf96SmrgCom_Tagbody(LispCom *com, LispBuiltin *builtin) 8765dfecf96Smrg/* 8775dfecf96Smrg tagbody &rest body 8785dfecf96Smrg */ 8795dfecf96Smrg{ 8805dfecf96Smrg LispObj *body; 8815dfecf96Smrg 8825dfecf96Smrg body = ARGUMENT(0); 8835dfecf96Smrg 8845dfecf96Smrg if (CONSP(body)) { 8855dfecf96Smrg CompileIniBlock(com, LispBlockBody, NIL); 8865dfecf96Smrg ComProgn(com, body); 8875dfecf96Smrg /* Tagbody returns NIL */ 8885dfecf96Smrg com_Bytecode(com, XBC_NIL); 8895dfecf96Smrg CompileFiniBlock(com); 8905dfecf96Smrg } 8915dfecf96Smrg else 8925dfecf96Smrg /* Tagbody always returns NIL */ 8935dfecf96Smrg com_Bytecode(com, XBC_NIL); 8945dfecf96Smrg} 8955dfecf96Smrg 8965dfecf96Smrgvoid 8975dfecf96SmrgCom_Unless(LispCom *com, LispBuiltin *builtin) 8985dfecf96Smrg/* 8995dfecf96Smrg unless test &rest body 9005dfecf96Smrg */ 9015dfecf96Smrg{ 9025dfecf96Smrg CodeTree *group, *tree; 9035dfecf96Smrg LispObj *test, *body; 9045dfecf96Smrg 9055dfecf96Smrg body = ARGUMENT(1); 9065dfecf96Smrg test = ARGUMENT(0); 9075dfecf96Smrg 9085dfecf96Smrg /* Generate code to evaluate test */ 9095dfecf96Smrg ComEval(com, test); 9105dfecf96Smrg /* Add node after test */ 9115dfecf96Smrg group = NEW_TREE(CodeTreeJumpIf); 9125dfecf96Smrg group->code = XBC_JUMPT; 9135dfecf96Smrg /* Generate NIL code */ 9145dfecf96Smrg ComProgn(com, body); 9155dfecf96Smrg /* Insert node to know where to jump if test is T */ 9165dfecf96Smrg tree = NEW_TREE(CodeTreeJumpIf); 9175dfecf96Smrg tree->code = XBC_NOOP; 9185dfecf96Smrg group->group = tree; 9195dfecf96Smrg} 9205dfecf96Smrg 9215dfecf96Smrgvoid 9225dfecf96SmrgCom_Until(LispCom *com, LispBuiltin *builtin) 9235dfecf96Smrg/* 9245dfecf96Smrg until test &rest body 9255dfecf96Smrg */ 9265dfecf96Smrg{ 9275dfecf96Smrg CodeTree *tree, *group, *ltree, *lgroup; 9285dfecf96Smrg LispObj *test, *body; 9295dfecf96Smrg 9305dfecf96Smrg body = ARGUMENT(1); 9315dfecf96Smrg test = ARGUMENT(0); 9325dfecf96Smrg 9335dfecf96Smrg /* Insert node to mark LOOP start */ 9345dfecf96Smrg ltree = NEW_TREE(CodeTreeJump); 9355dfecf96Smrg ltree->code = XBC_NOOP; 9365dfecf96Smrg 9375dfecf96Smrg /* Build code for test */ 9385dfecf96Smrg ComEval(com, test); 9395dfecf96Smrg group = NEW_TREE(CodeTreeJumpIf); 9405dfecf96Smrg group->code = XBC_JUMPT; 9415dfecf96Smrg 9425dfecf96Smrg /* Execute @BODY */ 9435dfecf96Smrg ComProgn(com, body); 9445dfecf96Smrg 9455dfecf96Smrg /* Insert node to jump to test again */ 9465dfecf96Smrg lgroup = NEW_TREE(CodeTreeJump); 9475dfecf96Smrg lgroup->code = XBC_JUMP; 9485dfecf96Smrg lgroup->group = ltree; 9495dfecf96Smrg 9505dfecf96Smrg /* Insert node to know where to jump if test is T */ 9515dfecf96Smrg tree = NEW_TREE(CodeTreeJumpIf); 9525dfecf96Smrg tree->code = XBC_NOOP; 9535dfecf96Smrg group->group = tree; 9545dfecf96Smrg} 9555dfecf96Smrg 9565dfecf96Smrgvoid 9575dfecf96SmrgCom_When(LispCom *com, LispBuiltin *builtin) 9585dfecf96Smrg/* 9595dfecf96Smrg when test &rest body 9605dfecf96Smrg */ 9615dfecf96Smrg{ 9625dfecf96Smrg CodeTree *group, *tree; 9635dfecf96Smrg LispObj *test, *body; 9645dfecf96Smrg 9655dfecf96Smrg body = ARGUMENT(1); 9665dfecf96Smrg test = ARGUMENT(0); 9675dfecf96Smrg 9685dfecf96Smrg /* Generate code to evaluate test */ 9695dfecf96Smrg ComEval(com, test); 9705dfecf96Smrg /* Add node after test */ 9715dfecf96Smrg group = NEW_TREE(CodeTreeJumpIf); 9725dfecf96Smrg group->code = XBC_JUMPNIL; 9735dfecf96Smrg /* Generate T code */ 9745dfecf96Smrg ComProgn(com, body); 9755dfecf96Smrg /* Insert node to know where to jump if test is NIL */ 9765dfecf96Smrg tree = NEW_TREE(CodeTreeJumpIf); 9775dfecf96Smrg tree->code = XBC_NOOP; 9785dfecf96Smrg group->group = tree; 9795dfecf96Smrg} 9805dfecf96Smrg 9815dfecf96Smrgvoid 9825dfecf96SmrgCom_While(LispCom *com, LispBuiltin *builtin) 9835dfecf96Smrg/* 9845dfecf96Smrg while test &rest body 9855dfecf96Smrg */ 9865dfecf96Smrg{ 9875dfecf96Smrg CodeTree *tree, *group, *ltree, *lgroup; 9885dfecf96Smrg LispObj *test, *body; 9895dfecf96Smrg 9905dfecf96Smrg body = ARGUMENT(1); 9915dfecf96Smrg test = ARGUMENT(0); 9925dfecf96Smrg 9935dfecf96Smrg /* Insert node to mark LOOP start */ 9945dfecf96Smrg ltree = NEW_TREE(CodeTreeJump); 9955dfecf96Smrg ltree->code = XBC_NOOP; 9965dfecf96Smrg 9975dfecf96Smrg /* Build code for test */ 9985dfecf96Smrg ComEval(com, test); 9995dfecf96Smrg group = NEW_TREE(CodeTreeJumpIf); 10005dfecf96Smrg group->code = XBC_JUMPNIL; 10015dfecf96Smrg 10025dfecf96Smrg /* Execute @BODY */ 10035dfecf96Smrg ComProgn(com, body); 10045dfecf96Smrg 10055dfecf96Smrg /* Insert node to jump to test again */ 10065dfecf96Smrg lgroup = NEW_TREE(CodeTreeJump); 10075dfecf96Smrg lgroup->code = XBC_JUMP; 10085dfecf96Smrg lgroup->group = ltree; 10095dfecf96Smrg 10105dfecf96Smrg /* Insert node to know where to jump if test is NIL */ 10115dfecf96Smrg tree = NEW_TREE(CodeTreeJumpIf); 10125dfecf96Smrg tree->code = XBC_NOOP; 10135dfecf96Smrg group->group = tree; 10145dfecf96Smrg} 10155dfecf96Smrg 10165dfecf96Smrg 10175dfecf96Smrg/*********************************************************************** 10185dfecf96Smrg * Com_XXX helper functions 10195dfecf96Smrg ***********************************************************************/ 10205dfecf96Smrgstatic void 10215dfecf96SmrgComPredicate(LispCom *com, LispBuiltin *builtin, LispBytePredicate predicate) 10225dfecf96Smrg{ 10235dfecf96Smrg LispObj *object; 10245dfecf96Smrg 10255dfecf96Smrg object = ARGUMENT(0); 10265dfecf96Smrg 10275dfecf96Smrg if (ComConstantp(com, object)) { 10285dfecf96Smrg switch (predicate) { 10295dfecf96Smrg case XBP_CONSP: 10305dfecf96Smrg com_Bytecode(com, CONSP(object) ? XBC_T : XBC_NIL); 10315dfecf96Smrg break; 10325dfecf96Smrg case XBP_LISTP: 10335dfecf96Smrg com_Bytecode(com, CONSP(object) || object == NIL ? 10345dfecf96Smrg XBC_T : XBC_NIL); 10355dfecf96Smrg break; 10365dfecf96Smrg case XBP_NUMBERP: 10375dfecf96Smrg com_Bytecode(com, NUMBERP(object) ? XBC_T : XBC_NIL); 10385dfecf96Smrg break; 10395dfecf96Smrg } 10405dfecf96Smrg } 10415dfecf96Smrg else { 10425dfecf96Smrg ComEval(com, object); 10435dfecf96Smrg com_BytecodeChar(com, XBC_PRED, predicate); 10445dfecf96Smrg } 10455dfecf96Smrg} 10465dfecf96Smrg 10475dfecf96Smrg/* XXX Could receive an argument telling if is the last statement in the 10485dfecf96Smrg * block(s), i.e. if a jump opcode should be generated or just the 10495dfecf96Smrg * evaluation of the returned value. Probably this is better done in 10505dfecf96Smrg * an optimization step. */ 10515dfecf96Smrgstatic void 10525dfecf96SmrgComReturnFrom(LispCom *com, LispBuiltin *builtin, int from) 10535dfecf96Smrg{ 10545dfecf96Smrg int bind; 10555dfecf96Smrg CodeTree *tree; 10565dfecf96Smrg LispObj *name, *result; 10575dfecf96Smrg CodeBlock *block = com->block; 10585dfecf96Smrg 10595dfecf96Smrg if (from) { 10605dfecf96Smrg result = ARGUMENT(1); 10615dfecf96Smrg name = ARGUMENT(0); 10625dfecf96Smrg } 10635dfecf96Smrg else { 10645dfecf96Smrg result = ARGUMENT(0); 10655dfecf96Smrg name = NIL; 10665dfecf96Smrg } 10675dfecf96Smrg if (result == UNSPEC) 10685dfecf96Smrg result = NIL; 10695dfecf96Smrg 10705dfecf96Smrg bind = block->bind; 10715dfecf96Smrg while (block) { 10725dfecf96Smrg if (block->type == LispBlockClosure) 10735dfecf96Smrg /* A function call */ 10745dfecf96Smrg break; 10755dfecf96Smrg else if (block->type == LispBlockTag && block->tag == name) 10765dfecf96Smrg break; 10775dfecf96Smrg block = block->prev; 10785dfecf96Smrg if (block) 10795dfecf96Smrg bind += block->bind; 10805dfecf96Smrg } 10815dfecf96Smrg 10825dfecf96Smrg if (!block || block->tag != name) 10835dfecf96Smrg LispDestroy("%s: no visible %s block", STRFUN(builtin), STROBJ(name)); 10845dfecf96Smrg 10855dfecf96Smrg /* Generate code to load result */ 10865dfecf96Smrg ComEval(com, result); 10875dfecf96Smrg 10885dfecf96Smrg /* Check for added variables that the jump is skiping the unbind opcode */ 10895dfecf96Smrg com_Unbind(com, bind); 10905dfecf96Smrg 10915dfecf96Smrg tree = NEW_TREE(CodeTreeReturn); 10925dfecf96Smrg tree->data.block = block; 10935dfecf96Smrg} 10945dfecf96Smrg 10955dfecf96Smrg/*********************************************************************** 10965dfecf96Smrg * Helper functions 10975dfecf96Smrg ***********************************************************************/ 10985dfecf96Smrgstatic int 10995dfecf96SmrgComConstantp(LispCom *com, LispObj *object) 11005dfecf96Smrg{ 11015dfecf96Smrg switch (OBJECT_TYPE(object)) { 11025dfecf96Smrg case LispAtom_t: 11035dfecf96Smrg /* Keywords are guaranteed to evaluate to itself */ 11045dfecf96Smrg if (object->data.atom->package == lisp__data.keyword) 11055dfecf96Smrg break; 11065dfecf96Smrg return (0); 11075dfecf96Smrg 11085dfecf96Smrg /* Function call */ 11095dfecf96Smrg case LispCons_t: 11105dfecf96Smrg 11115dfecf96Smrg /* Need macro expansion, these are special abstract objects */ 11125dfecf96Smrg case LispQuote_t: 11135dfecf96Smrg case LispBackquote_t: 11145dfecf96Smrg case LispComma_t: 11155dfecf96Smrg case LispFunctionQuote_t: 11165dfecf96Smrg return (0); 11175dfecf96Smrg 11185dfecf96Smrg /* Anything else is a literal constant */ 11195dfecf96Smrg default: 11205dfecf96Smrg break; 11215dfecf96Smrg } 11225dfecf96Smrg 11235dfecf96Smrg return (1); 11245dfecf96Smrg} 11255dfecf96Smrg 11265dfecf96Smrgstatic int 11275dfecf96SmrgFindIndex(void *item, void **table, int length) 11285dfecf96Smrg{ 11295dfecf96Smrg long cmp; 11305dfecf96Smrg int left, right, i; 11315dfecf96Smrg 11325dfecf96Smrg left = 0; 11335dfecf96Smrg right = length - 1; 11345dfecf96Smrg while (left <= right) { 11355dfecf96Smrg i = (left + right) >> 1; 11365dfecf96Smrg cmp = (char*)item - (char*)table[i]; 11375dfecf96Smrg if (cmp == 0) 11385dfecf96Smrg return (i); 11395dfecf96Smrg else if (cmp < 0) 11405dfecf96Smrg right = i - 1; 11415dfecf96Smrg else 11425dfecf96Smrg left = i + 1; 11435dfecf96Smrg } 11445dfecf96Smrg 11455dfecf96Smrg return (-1); 11465dfecf96Smrg} 11475dfecf96Smrg 11485dfecf96Smrgstatic int 11495dfecf96Smrgcompare(const void *left, const void *right) 11505dfecf96Smrg{ 11515dfecf96Smrg long cmp = *(char**)left - *(char**)right; 11525dfecf96Smrg 11535dfecf96Smrg return (cmp < 0 ? -1 : 1); 11545dfecf96Smrg} 11555dfecf96Smrg 11565dfecf96Smrgstatic int 11575dfecf96SmrgBuildTablePointer(void *pointer, void ***pointers, int *num_pointers) 11585dfecf96Smrg{ 11595dfecf96Smrg int i; 11605dfecf96Smrg 11615dfecf96Smrg if ((i = FindIndex(pointer, *pointers, *num_pointers)) < 0) { 11625dfecf96Smrg *pointers = LispRealloc(*pointers, 11635dfecf96Smrg sizeof(void*) * (*num_pointers + 1)); 11645dfecf96Smrg (*pointers)[*num_pointers] = pointer; 11655dfecf96Smrg if (++*num_pointers > 1) 11665dfecf96Smrg qsort(*pointers, *num_pointers, sizeof(void*), compare); 11675dfecf96Smrg i = FindIndex(pointer, *pointers, *num_pointers); 11685dfecf96Smrg } 11695dfecf96Smrg 11705dfecf96Smrg return (i); 11715dfecf96Smrg} 11725dfecf96Smrg 11735dfecf96Smrgstatic void 11745dfecf96SmrgComAddVariable(LispCom *com, LispObj *symbol, LispObj *value) 11755dfecf96Smrg{ 11765dfecf96Smrg LispAtom *atom = symbol->data.atom; 11775dfecf96Smrg 1178f14f4646Smrg if (atom && atom->key && !com->macro) { 11795dfecf96Smrg int i, length = com->block->variables.length; 11805dfecf96Smrg 11815dfecf96Smrg i = BuildTablePointer(atom, (void***)&com->block->variables.symbols, 11825dfecf96Smrg &com->block->variables.length); 11835dfecf96Smrg 11845dfecf96Smrg if (com->block->variables.length != length) { 11855dfecf96Smrg com->block->variables.flags = 11865dfecf96Smrg LispRealloc(com->block->variables.flags, 11875dfecf96Smrg com->block->variables.length * sizeof(int)); 11885dfecf96Smrg 11895dfecf96Smrg /* Variable was inserted in the middle of the list */ 11905dfecf96Smrg if (i < length) 11915dfecf96Smrg memmove(com->block->variables.flags + i + 1, 11925dfecf96Smrg com->block->variables.flags + i, 11935dfecf96Smrg (length - i) * sizeof(int)); 11945dfecf96Smrg 11955dfecf96Smrg com->block->variables.flags[i] = 0; 11965dfecf96Smrg } 11975dfecf96Smrg } 11985dfecf96Smrg 11995dfecf96Smrg LispAddVar(symbol, value); 12005dfecf96Smrg} 12015dfecf96Smrg 12025dfecf96Smrgstatic int 12035dfecf96SmrgComGetVariable(LispCom *com, LispObj *symbol) 12045dfecf96Smrg{ 12055dfecf96Smrg LispAtom *name; 12065dfecf96Smrg int i, base, offset; 12075dfecf96Smrg Atom_id id; 12085dfecf96Smrg 12095dfecf96Smrg name = symbol->data.atom; 12105dfecf96Smrg if (name->constant) { 12115dfecf96Smrg if (name->package == lisp__data.keyword) 12125dfecf96Smrg /* Just load <symbol> from the byte stream, keywords are 12135dfecf96Smrg * guaranteed to evaluate to itself. */ 12145dfecf96Smrg return (SYMBOL_KEYWORD); 12155dfecf96Smrg return (SYMBOL_CONSTANT); 12165dfecf96Smrg } 12175dfecf96Smrg 12185dfecf96Smrg offset = name->offset; 1219f14f4646Smrg id = name->key; 12205dfecf96Smrg base = lisp__data.env.lex; 12215dfecf96Smrg i = lisp__data.env.head - 1; 12225dfecf96Smrg 12235dfecf96Smrg /* If variable is local */ 12245dfecf96Smrg if (offset <= i && offset >= com->lex && lisp__data.env.names[offset] == id) { 12255dfecf96Smrg COM_VARIABLE_USED(name); 12265dfecf96Smrg /* Relative offset */ 12275dfecf96Smrg return (offset - base); 12285dfecf96Smrg } 12295dfecf96Smrg 12305dfecf96Smrg /* name->offset may have been changed in a macro expansion */ 12315dfecf96Smrg for (; i >= com->lex; i--) 12325dfecf96Smrg if (lisp__data.env.names[i] == id) { 12335dfecf96Smrg name->offset = i; 12345dfecf96Smrg COM_VARIABLE_USED(name); 12355dfecf96Smrg return (i - base); 12365dfecf96Smrg } 12375dfecf96Smrg 12385dfecf96Smrg if (!name->a_object) { 12395dfecf96Smrg ++com->warnings; 12405dfecf96Smrg LispWarning("variable %s is neither declared nor bound", 1241f14f4646Smrg name->key->value); 12425dfecf96Smrg } 12435dfecf96Smrg 12445dfecf96Smrg /* Not found, resolve <symbol> at run time */ 12455dfecf96Smrg return (SYMBOL_UNBOUND); 12465dfecf96Smrg} 12475dfecf96Smrg 12485dfecf96Smrgstatic void 12495dfecf96SmrgComVariableSetFlag(LispCom *com, LispAtom *atom, int flag) 12505dfecf96Smrg{ 12515dfecf96Smrg int i; 12525dfecf96Smrg CodeBlock *block = com->block; 12535dfecf96Smrg 12545dfecf96Smrg while (block) { 12555dfecf96Smrg i = FindIndex(atom, (void**)block->variables.symbols, 12565dfecf96Smrg block->variables.length); 12575dfecf96Smrg if (i >= 0) { 12585dfecf96Smrg block->variables.flags[i] |= flag; 12595dfecf96Smrg /* Descend block list if an argument to function being called 12605dfecf96Smrg * has the same name as a bound variable in the current function. 12615dfecf96Smrg */ 12625dfecf96Smrg if ((flag & VARIABLE_ARGUMENT) || 12635dfecf96Smrg !(block->variables.flags[i] & VARIABLE_ARGUMENT)) 12645dfecf96Smrg break; 12655dfecf96Smrg } 12665dfecf96Smrg block = block->prev; 12675dfecf96Smrg } 12685dfecf96Smrg} 12695dfecf96Smrg 12705dfecf96Smrg/*********************************************************************** 12715dfecf96Smrg * Bytecode compiler functions 12725dfecf96Smrg ***********************************************************************/ 12735dfecf96Smrgstatic void 12745dfecf96SmrgComLabel(LispCom *com, LispObj *label) 12755dfecf96Smrg{ 12765dfecf96Smrg int i; 12775dfecf96Smrg CodeTree *tree; 12785dfecf96Smrg 12795dfecf96Smrg for (i = 0; i < com->block->tagbody.length; i++) 12805dfecf96Smrg if (label == com->block->tagbody.labels[i]) 12815dfecf96Smrg LispDestroy("TAGBODY: tag %s specified more than once", 12825dfecf96Smrg STROBJ(label)); 12835dfecf96Smrg 12845dfecf96Smrg if (com->block->tagbody.length >= com->block->tagbody.space) { 12855dfecf96Smrg com->block->tagbody.labels = 12865dfecf96Smrg LispRealloc(com->block->tagbody.labels, 12875dfecf96Smrg sizeof(LispObj*) * (com->block->tagbody.space + 8)); 12885dfecf96Smrg /* Reserve space, will be used at link time when 12895dfecf96Smrg * resolving GO jumps. */ 12905dfecf96Smrg com->block->tagbody.codes = 12915dfecf96Smrg LispRealloc(com->block->tagbody.codes, 12925dfecf96Smrg sizeof(CodeTree*) * (com->block->tagbody.space + 8)); 12935dfecf96Smrg com->block->tagbody.space += 8; 12945dfecf96Smrg } 12955dfecf96Smrg 12965dfecf96Smrg com->block->tagbody.labels[com->block->tagbody.length++] = label; 12975dfecf96Smrg tree = NEW_TREE(CodeTreeLabel); 12985dfecf96Smrg tree->data.object = label; 12995dfecf96Smrg} 13005dfecf96Smrg 13015dfecf96Smrgstatic void 13025dfecf96SmrgComPush(LispCom *com, LispObj *symbol, LispObj *value, 13035dfecf96Smrg int eval, int builtin, int compile) 13045dfecf96Smrg{ 13055dfecf96Smrg /* If <compile> is set, it is pushing an argument to one of 13065dfecf96Smrg * Com_XXX functions. */ 13075dfecf96Smrg if (compile) { 13085dfecf96Smrg if (builtin) 13095dfecf96Smrg lisp__data.stack.values[lisp__data.stack.length++] = value; 13105dfecf96Smrg else 13115dfecf96Smrg ComAddVariable(com, symbol, value); 13125dfecf96Smrg return; 13135dfecf96Smrg } 13145dfecf96Smrg 13155dfecf96Smrg /* If <com->macro> is set, it is expanding a macro, just add the local 13165dfecf96Smrg * variable <symbol> bounded to <value>, so that it will be available 13175dfecf96Smrg * when calling the interpreter to expand the macro. */ 13185dfecf96Smrg else if (com->macro) { 13195dfecf96Smrg ComAddVariable(com, symbol, value); 13205dfecf96Smrg return; 13215dfecf96Smrg } 13225dfecf96Smrg 13235dfecf96Smrg /* If <eval> is set, it must generate the opcodes to evaluate <value>. 13245dfecf96Smrg * If <value> is a constant, just generate the opcodes to load it. */ 13255dfecf96Smrg else if (eval && !ComConstantp(com, value)) { 13265dfecf96Smrg switch (OBJECT_TYPE(value)) { 13275dfecf96Smrg case LispAtom_t: { 13285dfecf96Smrg int offset = ComGetVariable(com, value); 13295dfecf96Smrg 13305dfecf96Smrg if (offset >= 0) { 13315dfecf96Smrg /* Load <value> from user stack at the relative offset */ 13325dfecf96Smrg if (builtin) 13335dfecf96Smrg com_LoadPush(com, offset); 13345dfecf96Smrg else 13355dfecf96Smrg com_LoadLet(com, offset, symbol->data.atom); 13365dfecf96Smrg } 13375dfecf96Smrg /* ComConstantp() does not return true for this, as the 13385dfecf96Smrg * current value must be computed. */ 13395dfecf96Smrg else if (offset == SYMBOL_CONSTANT) { 13405dfecf96Smrg value = value->data.atom->property->value; 13415dfecf96Smrg if (builtin) 13425dfecf96Smrg com_LoadConPush(com, value); 13435dfecf96Smrg else 13445dfecf96Smrg com_LoadConLet(com, value, symbol->data.atom); 13455dfecf96Smrg } 13465dfecf96Smrg else { 13475dfecf96Smrg /* Load value bound to <value> at run time */ 13485dfecf96Smrg if (builtin) 13495dfecf96Smrg com_LoadSymPush(com, value->data.atom); 13505dfecf96Smrg else 13515dfecf96Smrg com_LoadSymLet(com, value->data.atom, 13525dfecf96Smrg symbol->data.atom); 13535dfecf96Smrg } 13545dfecf96Smrg } break; 13555dfecf96Smrg 13565dfecf96Smrg default: 13575dfecf96Smrg /* Generate code to evaluate <value> */ 13585dfecf96Smrg ComEval(com, value); 13595dfecf96Smrg if (builtin) 13605dfecf96Smrg com_Bytecode(com, XBC_PUSH); 13615dfecf96Smrg else 13625dfecf96Smrg com_Let(com, symbol->data.atom); 13635dfecf96Smrg break; 13645dfecf96Smrg } 13655dfecf96Smrg 13665dfecf96Smrg /* Remember <symbol> will be bound, <value> only matters for 13675dfecf96Smrg * the Com_XXX functions */ 13685dfecf96Smrg if (builtin) 13695dfecf96Smrg lisp__data.stack.values[lisp__data.stack.length++] = value; 13705dfecf96Smrg else 13715dfecf96Smrg ComAddVariable(com, symbol, value); 13725dfecf96Smrg return; 13735dfecf96Smrg } 13745dfecf96Smrg 13755dfecf96Smrg if (builtin) { 13765dfecf96Smrg /* Load <value> as a constant in builtin stack */ 13775dfecf96Smrg com_LoadConPush(com, value); 13785dfecf96Smrg lisp__data.stack.values[lisp__data.stack.length++] = value; 13795dfecf96Smrg } 13805dfecf96Smrg else { 13815dfecf96Smrg /* Load <value> as a constant in stack */ 13825dfecf96Smrg com_LoadConLet(com, value, symbol->data.atom); 13835dfecf96Smrg /* Remember <symbol> will be bound */ 13845dfecf96Smrg ComAddVariable(com, symbol, value); 13855dfecf96Smrg } 13865dfecf96Smrg} 13875dfecf96Smrg 13885dfecf96Smrg/* This function does almost the same job as LispMakeEnvironment, but 13895dfecf96Smrg * it is not optimized for speed, as it is not building argument lists 13905dfecf96Smrg * to user code, but to Com_XXX functions, or helping in generating the 13915dfecf96Smrg * opcodes to load arguments at bytecode run time. */ 13925dfecf96Smrgstatic int 13935dfecf96SmrgComCall(LispCom *com, LispArgList *alist, 13945dfecf96Smrg LispObj *name, LispObj *values, 13955dfecf96Smrg int eval, int builtin, int compile) 13965dfecf96Smrg{ 13975dfecf96Smrg char *desc; 13985dfecf96Smrg int i, count, base; 13995dfecf96Smrg LispObj **symbols, **defaults, **sforms; 14005dfecf96Smrg 14015dfecf96Smrg if (builtin) { 14025dfecf96Smrg base = lisp__data.stack.length; 14035dfecf96Smrg /* This should never be executed, but make the check for safety */ 14045dfecf96Smrg if (base + alist->num_arguments > lisp__data.stack.space) { 14055dfecf96Smrg do 14065dfecf96Smrg LispMoreStack(); 14075dfecf96Smrg while (base + alist->num_arguments > lisp__data.stack.space); 14085dfecf96Smrg } 14095dfecf96Smrg } 14105dfecf96Smrg else 14115dfecf96Smrg base = lisp__data.env.length; 14125dfecf96Smrg 14135dfecf96Smrg desc = alist->description; 14145dfecf96Smrg switch (*desc++) { 14155dfecf96Smrg case '.': 14165dfecf96Smrg goto normal_label; 14175dfecf96Smrg case 'o': 14185dfecf96Smrg goto optional_label; 14195dfecf96Smrg case 'k': 14205dfecf96Smrg goto key_label; 14215dfecf96Smrg case 'r': 14225dfecf96Smrg goto rest_label; 14235dfecf96Smrg case 'a': 14245dfecf96Smrg goto aux_label; 14255dfecf96Smrg default: 14265dfecf96Smrg goto done_label; 14275dfecf96Smrg } 14285dfecf96Smrg 14295dfecf96Smrg 14305dfecf96Smrg /* Normal arguments */ 14315dfecf96Smrgnormal_label: 14325dfecf96Smrg i = 0; 14335dfecf96Smrg symbols = alist->normals.symbols; 14345dfecf96Smrg count = alist->normals.num_symbols; 14355dfecf96Smrg for (; i < count && CONSP(values); i++, values = CDR(values)) { 14365dfecf96Smrg ComPush(com, symbols[i], CAR(values), eval, builtin, compile); 14375dfecf96Smrg if (!builtin && !com->macro) 14385dfecf96Smrg COM_VARIABLE_ARGUMENT(symbols[i]->data.atom); 14395dfecf96Smrg } 14405dfecf96Smrg if (i < count) 14415dfecf96Smrg LispDestroy("%s: too few arguments", STROBJ(name)); 14425dfecf96Smrg 14435dfecf96Smrg switch (*desc++) { 14445dfecf96Smrg case 'o': 14455dfecf96Smrg goto optional_label; 14465dfecf96Smrg case 'k': 14475dfecf96Smrg goto key_label; 14485dfecf96Smrg case 'r': 14495dfecf96Smrg goto rest_label; 14505dfecf96Smrg case 'a': 14515dfecf96Smrg goto aux_label; 14525dfecf96Smrg default: 14535dfecf96Smrg goto done_label; 14545dfecf96Smrg } 14555dfecf96Smrg 14565dfecf96Smrg 14575dfecf96Smrg /* &OPTIONAL */ 14585dfecf96Smrgoptional_label: 14595dfecf96Smrg i = 0; 14605dfecf96Smrg count = alist->optionals.num_symbols; 14615dfecf96Smrg symbols = alist->optionals.symbols; 14625dfecf96Smrg defaults = alist->optionals.defaults; 14635dfecf96Smrg sforms = alist->optionals.sforms; 14645dfecf96Smrg for (; i < count && CONSP(values); i++, values = CDR(values)) { 14655dfecf96Smrg ComPush(com, symbols[i], CAR(values), eval, builtin, compile); 14665dfecf96Smrg if (!builtin && !com->macro) 14675dfecf96Smrg COM_VARIABLE_ARGUMENT(symbols[i]->data.atom); 14685dfecf96Smrg if (sforms[i]) { 14695dfecf96Smrg ComPush(com, sforms[i], T, 0, builtin, compile); 14705dfecf96Smrg if (!builtin && !com->macro) 14715dfecf96Smrg COM_VARIABLE_ARGUMENT(sforms[i]->data.atom); 14725dfecf96Smrg } 14735dfecf96Smrg } 14745dfecf96Smrg for (; i < count; i++) { 14755dfecf96Smrg if (!builtin) { 14765dfecf96Smrg int lex = com->lex; 14775dfecf96Smrg int head = lisp__data.env.head; 14785dfecf96Smrg 14795dfecf96Smrg com->lex = base; 14805dfecf96Smrg lisp__data.env.head = lisp__data.env.length; 14815dfecf96Smrg /* default arguments are evaluated for macros */ 14825dfecf96Smrg ComPush(com, symbols[i], defaults[i], 1, 0, compile); 14835dfecf96Smrg if (!com->macro) 14845dfecf96Smrg COM_VARIABLE_ARGUMENT(symbols[i]->data.atom); 14855dfecf96Smrg lisp__data.env.head = head; 14865dfecf96Smrg com->lex = lex; 14875dfecf96Smrg } 14885dfecf96Smrg else 14895dfecf96Smrg ComPush(com, symbols[i], defaults[i], eval, 1, compile); 14905dfecf96Smrg if (sforms[i]) { 14915dfecf96Smrg ComPush(com, sforms[i], NIL, 0, builtin, compile); 14925dfecf96Smrg if (!builtin && !com->macro) 14935dfecf96Smrg COM_VARIABLE_ARGUMENT(sforms[i]->data.atom); 14945dfecf96Smrg } 14955dfecf96Smrg } 14965dfecf96Smrg 14975dfecf96Smrg switch (*desc++) { 14985dfecf96Smrg case 'k': 14995dfecf96Smrg goto key_label; 15005dfecf96Smrg case 'r': 15015dfecf96Smrg goto rest_label; 15025dfecf96Smrg case 'a': 15035dfecf96Smrg goto aux_label; 15045dfecf96Smrg default: 15055dfecf96Smrg goto done_label; 15065dfecf96Smrg } 15075dfecf96Smrg 15085dfecf96Smrg 15095dfecf96Smrg /* &KEY */ 15105dfecf96Smrgkey_label: 15115dfecf96Smrg { 15125dfecf96Smrg int varset; 15135dfecf96Smrg LispObj *val, *karg, **keys; 15145dfecf96Smrg 15155dfecf96Smrg count = alist->keys.num_symbols; 15165dfecf96Smrg symbols = alist->keys.symbols; 15175dfecf96Smrg defaults = alist->keys.defaults; 15185dfecf96Smrg sforms = alist->keys.sforms; 15195dfecf96Smrg keys = alist->keys.keys; 15205dfecf96Smrg 15215dfecf96Smrg /* Check if arguments are correctly specified */ 15225dfecf96Smrg for (karg = values; CONSP(karg); karg = CDR(karg)) { 15235dfecf96Smrg val = CAR(karg); 15245dfecf96Smrg if (KEYWORDP(val)) { 15255dfecf96Smrg for (i = 0; i < alist->keys.num_symbols; i++) 15265dfecf96Smrg if (!keys[i] && symbols[i] == val) 15275dfecf96Smrg break; 15285dfecf96Smrg } 15295dfecf96Smrg 15305dfecf96Smrg else if (!builtin && 15315dfecf96Smrg QUOTEP(val) && SYMBOLP(val->data.quote)) { 15325dfecf96Smrg for (i = 0; i < alist->keys.num_symbols; i++) 15335dfecf96Smrg if (keys[i] && ATOMID(keys[i]) == ATOMID(val->data.quote)) 15345dfecf96Smrg break; 15355dfecf96Smrg } 15365dfecf96Smrg 15375dfecf96Smrg else 15385dfecf96Smrg /* Just make the error test true */ 15395dfecf96Smrg i = alist->keys.num_symbols; 15405dfecf96Smrg 15415dfecf96Smrg if (i == alist->keys.num_symbols) { 15425dfecf96Smrg /* If not in argument specification list... */ 15435dfecf96Smrg char function_name[36]; 15445dfecf96Smrg 15455dfecf96Smrg strcpy(function_name, STROBJ(name)); 15465dfecf96Smrg LispDestroy("%s: invalid keyword %s", 15475dfecf96Smrg function_name, STROBJ(val)); 15485dfecf96Smrg } 15495dfecf96Smrg 15505dfecf96Smrg karg = CDR(karg); 15515dfecf96Smrg if (!CONSP(karg)) 15525dfecf96Smrg LispDestroy("%s: &KEY needs arguments as pairs", 15535dfecf96Smrg STROBJ(name)); 15545dfecf96Smrg } 15555dfecf96Smrg 15565dfecf96Smrg /* Add variables */ 15575dfecf96Smrg for (i = 0; i < alist->keys.num_symbols; i++) { 15585dfecf96Smrg val = defaults[i]; 15595dfecf96Smrg varset = 0; 15605dfecf96Smrg if (!builtin && keys[i]) { 15615dfecf96Smrg Atom_id atom = ATOMID(keys[i]); 15625dfecf96Smrg 15635dfecf96Smrg /* Special keyword specification, need to compare ATOMID 15645dfecf96Smrg * and keyword specification must be a quoted object */ 15655dfecf96Smrg for (karg = values; CONSP(karg); karg = CDR(karg)) { 15665dfecf96Smrg val = CAR(karg); 15675dfecf96Smrg if (QUOTEP(val) && atom == ATOMID(val->data.quote)) { 15685dfecf96Smrg val = CADR(karg); 15695dfecf96Smrg varset = 1; 15705dfecf96Smrg break; 15715dfecf96Smrg } 15725dfecf96Smrg karg = CDR(karg); 15735dfecf96Smrg } 15745dfecf96Smrg } 15755dfecf96Smrg 15765dfecf96Smrg else { 15775dfecf96Smrg /* Normal keyword specification, can compare object pointers, 15785dfecf96Smrg * as they point to the same object in the keyword package */ 15795dfecf96Smrg for (karg = values; CONSP(karg); karg = CDR(karg)) { 15805dfecf96Smrg /* Don't check if argument is a valid keyword or 15815dfecf96Smrg * special quoted keyword */ 15825dfecf96Smrg if (symbols[i] == CAR(karg)) { 15835dfecf96Smrg val = CADR(karg); 15845dfecf96Smrg varset = 1; 15855dfecf96Smrg break; 15865dfecf96Smrg } 15875dfecf96Smrg karg = CDR(karg); 15885dfecf96Smrg } 15895dfecf96Smrg } 15905dfecf96Smrg 15915dfecf96Smrg /* Add the variable to environment */ 15925dfecf96Smrg if (varset) { 15935dfecf96Smrg ComPush(com, symbols[i], val, eval, builtin, compile); 15945dfecf96Smrg if (sforms[i]) 15955dfecf96Smrg ComPush(com, sforms[i], T, 0, builtin, compile); 15965dfecf96Smrg } 15975dfecf96Smrg else { 15985dfecf96Smrg /* default arguments are evaluated for macros */ 15995dfecf96Smrg if (!builtin) { 16005dfecf96Smrg int lex = com->lex; 16015dfecf96Smrg int head = lisp__data.env.head; 16025dfecf96Smrg 16035dfecf96Smrg com->lex = base; 16045dfecf96Smrg lisp__data.env.head = lisp__data.env.length; 16055dfecf96Smrg ComPush(com, symbols[i], val, eval, 0, compile); 16065dfecf96Smrg lisp__data.env.head = head; 16075dfecf96Smrg com->lex = lex; 16085dfecf96Smrg } 16095dfecf96Smrg else 16105dfecf96Smrg ComPush(com, symbols[i], val, eval, builtin, compile); 16115dfecf96Smrg if (sforms[i]) 16125dfecf96Smrg ComPush(com, sforms[i], NIL, 0, builtin, compile); 16135dfecf96Smrg } 16145dfecf96Smrg if (!builtin && !com->macro) { 16155dfecf96Smrg COM_VARIABLE_ARGUMENT(symbols[i]->data.atom); 16165dfecf96Smrg if (sforms[i]) 16175dfecf96Smrg COM_VARIABLE_ARGUMENT(sforms[i]->data.atom); 16185dfecf96Smrg } 16195dfecf96Smrg } 16205dfecf96Smrg } 16215dfecf96Smrg 16225dfecf96Smrg if (*desc == 'a') { 16235dfecf96Smrg /* &KEY uses all remaining arguments */ 16245dfecf96Smrg values = NIL; 16255dfecf96Smrg goto aux_label; 16265dfecf96Smrg } 16275dfecf96Smrg goto finished_label; 16285dfecf96Smrg 16295dfecf96Smrg 16305dfecf96Smrg /* &REST */ 16315dfecf96Smrgrest_label: 16325dfecf96Smrg if (!eval || !CONSP(values) || (compile && !builtin)) 16335dfecf96Smrg ComPush(com, alist->rest, values, eval, builtin, compile); 16345dfecf96Smrg else { 16355dfecf96Smrg char *string; 16365dfecf96Smrg LispObj *list, *car = NIL; 16375dfecf96Smrg int count, constantp; 16385dfecf96Smrg 16395dfecf96Smrg /* Count number of arguments and check if it is a list of constants */ 16405dfecf96Smrg for (count = 0, constantp = 1, list = values; 16415dfecf96Smrg CONSP(list); 16425dfecf96Smrg list = CDR(list), count++) { 16435dfecf96Smrg car = CAR(list); 16445dfecf96Smrg if (!ComConstantp(com, car)) 16455dfecf96Smrg constantp = 0; 16465dfecf96Smrg } 16475dfecf96Smrg 1648f14f4646Smrg string = builtin ? ATOMID(name)->value : NULL; 16495dfecf96Smrg /* XXX FIXME should have a flag indicating if function call 16505dfecf96Smrg * change the &REST arguments even if it is a constant list 16515dfecf96Smrg * (or if the returned value may be changed). */ 16525dfecf96Smrg if (string && (count < MAX_BCONS || constantp) && 16535dfecf96Smrg strcmp(string, "LIST") && 16545dfecf96Smrg strcmp(string, "APPLY") && /* XXX depends on function argument */ 16555dfecf96Smrg strcmp(string, "VECTOR") && 16565dfecf96Smrg /* Append does not copy the last/single list */ 16575dfecf96Smrg (strcmp(string, "APPEND") || !CONSP(car))) { 16585dfecf96Smrg if (constantp) { 16595dfecf96Smrg /* If the builtin function changes the &REST parameters, must 16605dfecf96Smrg * define a Com_XXX function for it. */ 16615dfecf96Smrg ComPush(com, alist->rest, values, 0, builtin, compile); 16625dfecf96Smrg } 16635dfecf96Smrg else { 16645dfecf96Smrg CompileStackEnter(com, count - 1, 1); 16655dfecf96Smrg for (; CONSP(CDR(values)); values = CDR(values)) { 16665dfecf96Smrg /* Evaluate this argument */ 16675dfecf96Smrg ComEval(com, CAR(values)); 16685dfecf96Smrg /* Save result in builtin stack */ 16695dfecf96Smrg com_Bytecode(com, XBC_PUSH); 16705dfecf96Smrg } 16715dfecf96Smrg CompileStackLeave(com, count - 1, 1); 16725dfecf96Smrg /* The last argument is not saved in the stack */ 16735dfecf96Smrg ComEval(com, CAR(values)); 16745dfecf96Smrg values = NIL; 16755dfecf96Smrg com_Bytecode(com, (LispByteOpcode)(XBC_BCONS + (count - 1))); 16765dfecf96Smrg } 16775dfecf96Smrg } 16785dfecf96Smrg else { 16795dfecf96Smrg /* Allocate a fresh list of cons */ 16805dfecf96Smrg 16815dfecf96Smrg /* Generate code to load object */ 16825dfecf96Smrg ComEval(com, CAR(values)); 16835dfecf96Smrg 16845dfecf96Smrg com->stack.cpstack += 2; 16855dfecf96Smrg if (com->stack.pstack < com->stack.cpstack) 16865dfecf96Smrg com->stack.pstack = com->stack.cpstack; 16875dfecf96Smrg /* Start building a gc protected list, with the loaded value */ 16885dfecf96Smrg com_Bytecode(com, XBC_LSTAR); 16895dfecf96Smrg 16905dfecf96Smrg for (values = CDR(values); CONSP(values); values = CDR(values)) { 16915dfecf96Smrg /* Generate code to load object */ 16925dfecf96Smrg ComEval(com, CAR(values)); 16935dfecf96Smrg 16945dfecf96Smrg /* Add loaded value to gc protected list */ 16955dfecf96Smrg com_Bytecode(com, XBC_LCONS); 16965dfecf96Smrg } 16975dfecf96Smrg 16985dfecf96Smrg /* Finish gc protected list */ 16995dfecf96Smrg com_Bytecode(com, XBC_LFINI); 17005dfecf96Smrg 17015dfecf96Smrg /* Push loaded value */ 17025dfecf96Smrg if (builtin) 17035dfecf96Smrg com_Bytecode(com, XBC_PUSH); 17045dfecf96Smrg else { 17055dfecf96Smrg com_Let(com, alist->rest->data.atom); 17065dfecf96Smrg 17075dfecf96Smrg /* Remember this symbol will be bound */ 17085dfecf96Smrg ComAddVariable(com, alist->rest, values); 17095dfecf96Smrg } 17105dfecf96Smrg com->stack.cpstack -= 2; 17115dfecf96Smrg } 17125dfecf96Smrg } 17135dfecf96Smrg if (!builtin && !com->macro) 17145dfecf96Smrg COM_VARIABLE_ARGUMENT(alist->rest->data.atom); 17155dfecf96Smrg if (*desc != 'a') 17165dfecf96Smrg goto finished_label; 17175dfecf96Smrg 17185dfecf96Smrg 17195dfecf96Smrg /* &AUX */ 17205dfecf96Smrgaux_label: 17215dfecf96Smrg i = 0; 17225dfecf96Smrg count = alist->auxs.num_symbols; 17235dfecf96Smrg symbols = alist->auxs.symbols; 17245dfecf96Smrg defaults = alist->auxs.initials; 17255dfecf96Smrg if (!builtin && !compile) { 17265dfecf96Smrg int lex = com->lex; 17275dfecf96Smrg 17285dfecf96Smrg com->lex = base; 17295dfecf96Smrg lisp__data.env.head = lisp__data.env.length; 17305dfecf96Smrg for (; i < count; i++) { 17315dfecf96Smrg ComPush(com, symbols[i], defaults[i], 1, 0, 0); 17325dfecf96Smrg if (!com->macro) 17335dfecf96Smrg COM_VARIABLE_ARGUMENT(symbols[i]->data.atom); 17345dfecf96Smrg ++lisp__data.env.head; 17355dfecf96Smrg } 17365dfecf96Smrg com->lex = lex; 17375dfecf96Smrg } 17385dfecf96Smrg else { 17395dfecf96Smrg for (; i < count; i++) { 17405dfecf96Smrg ComPush(com, symbols[i], defaults[i], eval, builtin, compile); 17415dfecf96Smrg if (!builtin && !com->macro) 17425dfecf96Smrg COM_VARIABLE_ARGUMENT(symbols[i]->data.atom); 17435dfecf96Smrg } 17445dfecf96Smrg } 17455dfecf96Smrg 17465dfecf96Smrgdone_label: 17475dfecf96Smrg if (CONSP(values)) 17485dfecf96Smrg LispDestroy("%s: too many arguments", STROBJ(name)); 17495dfecf96Smrg 17505dfecf96Smrgfinished_label: 17515dfecf96Smrg if (builtin) 17525dfecf96Smrg lisp__data.stack.base = base; 17535dfecf96Smrg else 17545dfecf96Smrg lisp__data.env.head = lisp__data.env.length; 17555dfecf96Smrg 17565dfecf96Smrg return (base); 17575dfecf96Smrg} 17585dfecf96Smrg 17595dfecf96Smrgstatic void 17605dfecf96SmrgComFuncall(LispCom *com, LispObj *function, LispObj *arguments, int eval) 17615dfecf96Smrg{ 17625dfecf96Smrg int base, compile; 17635dfecf96Smrg LispAtom *atom; 17645dfecf96Smrg LispArgList *alist; 17655dfecf96Smrg LispBuiltin *builtin; 17665dfecf96Smrg LispObj *lambda; 17675dfecf96Smrg 17685dfecf96Smrg switch (OBJECT_TYPE(function)) { 17695dfecf96Smrg case LispFunction_t: 17705dfecf96Smrg function = function->data.atom->object; 17715dfecf96Smrg case LispAtom_t: 17725dfecf96Smrg atom = function->data.atom; 17735dfecf96Smrg alist = atom->property->alist; 17745dfecf96Smrg 17755dfecf96Smrg if (atom->a_builtin) { 17765dfecf96Smrg builtin = atom->property->fun.builtin; 17775dfecf96Smrg compile = builtin->compile != NULL; 17785dfecf96Smrg 17795dfecf96Smrg /* If one of: 17805dfecf96Smrg * o expanding a macro 17815dfecf96Smrg * o calling a builtin special form 17825dfecf96Smrg * o builtin function is a macro 17835dfecf96Smrg * don't evaluate arguments. */ 17845dfecf96Smrg if (com->macro || compile || builtin->type == LispMacro) 17855dfecf96Smrg eval = 0; 17865dfecf96Smrg 17875dfecf96Smrg if (!com->macro && builtin->type == LispMacro) { 17885dfecf96Smrg /* Set flag of variable used, in case variable is only 17895dfecf96Smrg * used as a builtin macro argument. */ 17905dfecf96Smrg LispObj *obj; 17915dfecf96Smrg 17925dfecf96Smrg for (obj = arguments; CONSP(obj); obj = CDR(obj)) { 17935dfecf96Smrg if (SYMBOLP(CAR(obj))) 17945dfecf96Smrg COM_VARIABLE_USED(CAR(obj)->data.atom); 17955dfecf96Smrg } 17965dfecf96Smrg } 17975dfecf96Smrg 17985dfecf96Smrg FORM_ENTER(); 17995dfecf96Smrg if (!compile && !com->macro) 18005dfecf96Smrg CompileStackEnter(com, alist->num_arguments, 1); 18015dfecf96Smrg 18025dfecf96Smrg /* Build argument list in the interpreter stacks */ 18035dfecf96Smrg base = ComCall(com, alist, function, arguments, 18045dfecf96Smrg eval, 1, compile); 18055dfecf96Smrg 18065dfecf96Smrg /* If <compile> is set, it is a special form */ 18075dfecf96Smrg if (compile) 18085dfecf96Smrg builtin->compile(com, builtin); 18095dfecf96Smrg 18105dfecf96Smrg /* Else, generate opcodes to call builtin function */ 18115dfecf96Smrg else { 18125dfecf96Smrg com_Call(com, alist->num_arguments, builtin); 18135dfecf96Smrg CompileStackLeave(com, alist->num_arguments, 1); 18145dfecf96Smrg } 18155dfecf96Smrg lisp__data.stack.base = lisp__data.stack.length = base; 18165dfecf96Smrg FORM_LEAVE(); 18175dfecf96Smrg } 18185dfecf96Smrg else if (atom->a_function) { 18195dfecf96Smrg int macro; 18205dfecf96Smrg 18215dfecf96Smrg lambda = atom->property->fun.function; 18225dfecf96Smrg macro = lambda->funtype == LispMacro; 18235dfecf96Smrg 18245dfecf96Smrg /* If <macro> is set, expand macro */ 18255dfecf96Smrg if (macro) 18265dfecf96Smrg ComMacroCall(com, alist, function, lambda, arguments); 18275dfecf96Smrg 18285dfecf96Smrg else { 18295dfecf96Smrg if (com->toplevel->type == LispBlockClosure && 18305dfecf96Smrg com->toplevel->tag == function) 18315dfecf96Smrg ComRecursiveCall(com, alist, function, arguments); 18325dfecf96Smrg else { 18335dfecf96Smrg#if 0 18345dfecf96Smrg ComInlineCall(com, alist, function, arguments, 18355dfecf96Smrg lambda->data.lambda.code); 18365dfecf96Smrg#else 18375dfecf96Smrg com_Funcall(com, function, arguments); 18385dfecf96Smrg#endif 18395dfecf96Smrg } 18405dfecf96Smrg } 18415dfecf96Smrg } 18425dfecf96Smrg else if (atom->a_defstruct && 18435dfecf96Smrg atom->property->structure.function != STRUCT_NAME && 18445dfecf96Smrg atom->property->structure.function != STRUCT_CONSTRUCTOR) { 18455dfecf96Smrg LispObj *definition = atom->property->structure.definition; 18465dfecf96Smrg 18475dfecf96Smrg if (!CONSP(arguments) || CONSP(CDR(arguments))) 1848f14f4646Smrg LispDestroy("%s: too %s arguments", atom->key->value, 18495dfecf96Smrg CONSP(arguments) ? "many" : "few"); 18505dfecf96Smrg 18515dfecf96Smrg ComEval(com, CAR(arguments)); 18525dfecf96Smrg if (atom->property->structure.function == STRUCT_CHECK) 18535dfecf96Smrg com_Structp(com, definition); 18545dfecf96Smrg else 18555dfecf96Smrg com_Struct(com, 18565dfecf96Smrg atom->property->structure.function, definition); 18575dfecf96Smrg } 18585dfecf96Smrg else if (atom->a_compiled) { 18595dfecf96Smrg FORM_ENTER(); 18605dfecf96Smrg CompileStackEnter(com, alist->num_arguments, 0); 18615dfecf96Smrg 18625dfecf96Smrg /* Build argument list in the interpreter stacks */ 18635dfecf96Smrg base = ComCall(com, alist, function, arguments, 1, 0, 0); 18645dfecf96Smrg com_Bytecall(com, alist->num_arguments, 18655dfecf96Smrg atom->property->fun.function); 18665dfecf96Smrg CompileStackLeave(com, alist->num_arguments, 0); 18675dfecf96Smrg lisp__data.env.head = lisp__data.env.length = base; 18685dfecf96Smrg FORM_LEAVE(); 18695dfecf96Smrg } 18705dfecf96Smrg else { 18715dfecf96Smrg /* Not yet defined function/macro. */ 18725dfecf96Smrg ++com->warnings; 1873f14f4646Smrg LispWarning("call to undefined function %s", atom->key->value); 18745dfecf96Smrg com_Funcall(com, function, arguments); 18755dfecf96Smrg } 18765dfecf96Smrg break; 18775dfecf96Smrg 18785dfecf96Smrg case LispLambda_t: 18795dfecf96Smrg lambda = function->data.lambda.code; 18805dfecf96Smrg alist = (LispArgList*)function->data.lambda.name->data.opaque.data; 18815dfecf96Smrg ComInlineCall(com, alist, NIL, arguments, lambda->data.lambda.code); 18825dfecf96Smrg break; 18835dfecf96Smrg 18845dfecf96Smrg case LispCons_t: 18855dfecf96Smrg if (CAR(function) == Olambda) { 18865dfecf96Smrg function = EVAL(function); 18875dfecf96Smrg if (LAMBDAP(function)) { 18885dfecf96Smrg GC_ENTER(); 18895dfecf96Smrg 18905dfecf96Smrg GC_PROTECT(function); 18915dfecf96Smrg lambda = function->data.lambda.code; 18925dfecf96Smrg alist = (LispArgList*)function->data.lambda.name->data.opaque.data; 18935dfecf96Smrg ComInlineCall(com, alist, NIL, arguments, lambda->data.lambda.code); 18945dfecf96Smrg GC_LEAVE(); 18955dfecf96Smrg break; 18965dfecf96Smrg } 18975dfecf96Smrg } 18985dfecf96Smrg 18995dfecf96Smrg default: 19005dfecf96Smrg /* XXX If bytecode objects are made available, should 19015dfecf96Smrg * handle it here. */ 19025dfecf96Smrg LispDestroy("EVAL: %s is invalid as a function", 19035dfecf96Smrg STROBJ(function)); 19045dfecf96Smrg /*NOTREACHED*/ 19055dfecf96Smrg break; 19065dfecf96Smrg } 19075dfecf96Smrg} 19085dfecf96Smrg 19095dfecf96Smrg/* Generate opcodes for an implicit PROGN */ 19105dfecf96Smrgstatic void 19115dfecf96SmrgComProgn(LispCom *com, LispObj *code) 19125dfecf96Smrg{ 19135dfecf96Smrg if (CONSP(code)) { 19145dfecf96Smrg for (; CONSP(code); code = CDR(code)) 19155dfecf96Smrg ComEval(com, CAR(code)); 19165dfecf96Smrg } 19175dfecf96Smrg else 19185dfecf96Smrg /* If no code to execute, empty PROGN returns NIL */ 19195dfecf96Smrg com_Bytecode(com, XBC_NIL); 19205dfecf96Smrg} 19215dfecf96Smrg 19225dfecf96Smrg/* Generate opcodes to evaluate <object>. */ 19235dfecf96Smrgstatic void 19245dfecf96SmrgComEval(LispCom *com, LispObj *object) 19255dfecf96Smrg{ 19265dfecf96Smrg int offset; 19275dfecf96Smrg LispObj *form; 19285dfecf96Smrg 19295dfecf96Smrg switch (OBJECT_TYPE(object)) { 19305dfecf96Smrg case LispAtom_t: 19315dfecf96Smrg if (IN_TAGBODY()) 19325dfecf96Smrg ComLabel(com, object); 19335dfecf96Smrg else { 19345dfecf96Smrg offset = ComGetVariable(com, object); 19355dfecf96Smrg if (offset >= 0) 19365dfecf96Smrg /* Load from user stack at relative offset */ 19375dfecf96Smrg com_Load(com, offset); 19385dfecf96Smrg else if (offset == SYMBOL_KEYWORD) 19395dfecf96Smrg com_LoadCon(com, object); 19405dfecf96Smrg else if (offset == SYMBOL_CONSTANT) 19415dfecf96Smrg /* Symbol defined as constant, just load it's value */ 19425dfecf96Smrg com_LoadCon(com, LispGetVar(object)); 19435dfecf96Smrg else 19445dfecf96Smrg /* Load value bound to symbol at run time */ 19455dfecf96Smrg com_LoadSym(com, object->data.atom); 19465dfecf96Smrg } 19475dfecf96Smrg break; 19485dfecf96Smrg 19495dfecf96Smrg case LispCons_t: { 19505dfecf96Smrg /* Macro expansion may be done in the object form */ 19515dfecf96Smrg form = com->form; 19525dfecf96Smrg com->form = object; 19535dfecf96Smrg ComFuncall(com, CAR(object), CDR(object), 1); 19545dfecf96Smrg com->form = form; 19555dfecf96Smrg } break; 19565dfecf96Smrg 19575dfecf96Smrg case LispQuote_t: 19585dfecf96Smrg com_LoadCon(com, object->data.quote); 19595dfecf96Smrg break; 19605dfecf96Smrg 19615dfecf96Smrg case LispBackquote_t: 19625dfecf96Smrg /* Macro expansion is stored in the current value of com->form */ 19635dfecf96Smrg ComMacroBackquote(com, object); 19645dfecf96Smrg break; 19655dfecf96Smrg 19665dfecf96Smrg case LispComma_t: 19675dfecf96Smrg LispDestroy("EVAL: comma outside of backquote"); 19685dfecf96Smrg break; 19695dfecf96Smrg 19705dfecf96Smrg case LispFunctionQuote_t: 19715dfecf96Smrg object = object->data.quote; 19725dfecf96Smrg if (SYMBOLP(object)) 19735dfecf96Smrg object = LispSymbolFunction(object); 19745dfecf96Smrg else if (CONSP(object) && CAR(object) == Olambda) { 19755dfecf96Smrg /* object will only be associated with bytecode later, 19765dfecf96Smrg * so, make sure it is protected until compilation finishes */ 19775dfecf96Smrg object = EVAL(object); 19785dfecf96Smrg RPLACD(com->plist, CONS(CAR(com->plist), CDR(com->plist))); 19795dfecf96Smrg RPLACA(com->plist, object); 19805dfecf96Smrg } 19815dfecf96Smrg else 19825dfecf96Smrg LispDestroy("FUNCTION: %s is not a function", STROBJ(object)); 19835dfecf96Smrg com_LoadCon(com, object); 19845dfecf96Smrg break; 19855dfecf96Smrg 19865dfecf96Smrg case LispFixnum_t: 19875dfecf96Smrg if (IN_TAGBODY()) { 19885dfecf96Smrg ComLabel(com, object); 19895dfecf96Smrg break; 19905dfecf96Smrg } 19915dfecf96Smrg /*FALLTROUGH*/ 19925dfecf96Smrg 19935dfecf96Smrg default: 19945dfecf96Smrg /* Constant object */ 19955dfecf96Smrg com_LoadCon(com, object); 19965dfecf96Smrg break; 19975dfecf96Smrg } 19985dfecf96Smrg} 19995dfecf96Smrg 20005dfecf96Smrg/*********************************************************************** 20015dfecf96Smrg * Lambda expansion helper functions 20025dfecf96Smrg ***********************************************************************/ 20035dfecf96Smrgstatic void 20045dfecf96SmrgComRecursiveCall(LispCom *com, LispArgList *alist, 20055dfecf96Smrg LispObj *name, LispObj *arguments) 20065dfecf96Smrg{ 20075dfecf96Smrg int base, lex; 20085dfecf96Smrg 20095dfecf96Smrg /* Save state */ 20105dfecf96Smrg lex = lisp__data.env.lex; 20115dfecf96Smrg 20125dfecf96Smrg FORM_ENTER(); 20135dfecf96Smrg 20145dfecf96Smrg /* Generate code to push function arguments in the stack */ 20155dfecf96Smrg base = ComCall(com, alist, name, arguments, 1, 0, 0); 20165dfecf96Smrg 20175dfecf96Smrg /* Stack will grow this amount */ 20185dfecf96Smrg CompileStackEnter(com, alist->num_arguments, 0); 20195dfecf96Smrg 20205dfecf96Smrg#if 0 20215dfecf96Smrg /* Make the variables available at run time */ 20225dfecf96Smrg com_Bind(com, alist->num_arguments); 20235dfecf96Smrg com->block->bind += alist->num_arguments; 20245dfecf96Smrg#endif 20255dfecf96Smrg 20265dfecf96Smrg com_BytecodeChar(com, XBC_LETREC, alist->num_arguments); 20275dfecf96Smrg 20285dfecf96Smrg#if 0 20295dfecf96Smrg /* The variables are now unbound */ 20305dfecf96Smrg com_Unbind(com, alist->num_arguments); 20315dfecf96Smrg com->block->bind -= alist->num_arguments; 20325dfecf96Smrg#endif 20335dfecf96Smrg 20345dfecf96Smrg /* Stack length is reduced */ 20355dfecf96Smrg CompileStackLeave(com, alist->num_arguments, 0); 20365dfecf96Smrg FORM_LEAVE(); 20375dfecf96Smrg 20385dfecf96Smrg /* Restore state */ 20395dfecf96Smrg lisp__data.env.lex = lex; 20405dfecf96Smrg lisp__data.env.head = lisp__data.env.length = base; 20415dfecf96Smrg} 20425dfecf96Smrg 20435dfecf96Smrgstatic void 20445dfecf96SmrgComInlineCall(LispCom *com, LispArgList *alist, 20455dfecf96Smrg LispObj *name, LispObj *arguments, LispObj *lambda) 20465dfecf96Smrg{ 20475dfecf96Smrg int base, lex; 20485dfecf96Smrg 20495dfecf96Smrg /* Save state */ 20505dfecf96Smrg lex = lisp__data.env.lex; 20515dfecf96Smrg 20525dfecf96Smrg FORM_ENTER(); 20535dfecf96Smrg /* Start the inline function block */ 20545dfecf96Smrg CompileIniBlock(com, LispBlockClosure, name); 20555dfecf96Smrg 20565dfecf96Smrg /* Generate code to push function arguments in the stack */ 20575dfecf96Smrg base = ComCall(com, alist, name, arguments, 1, 0, 0); 20585dfecf96Smrg 20595dfecf96Smrg /* Stack will grow this amount */ 20605dfecf96Smrg CompileStackEnter(com, alist->num_arguments, 0); 20615dfecf96Smrg 20625dfecf96Smrg /* Make the variables available at run time */ 20635dfecf96Smrg com_Bind(com, alist->num_arguments); 20645dfecf96Smrg com->block->bind += alist->num_arguments; 20655dfecf96Smrg 20665dfecf96Smrg /* Expand the lambda list */ 20675dfecf96Smrg ComProgn(com, lambda); 20685dfecf96Smrg 20695dfecf96Smrg /* The variables are now unbound */ 20705dfecf96Smrg com_Unbind(com, alist->num_arguments); 20715dfecf96Smrg com->block->bind -= alist->num_arguments; 20725dfecf96Smrg 20735dfecf96Smrg /* Stack length is reduced */ 20745dfecf96Smrg CompileStackLeave(com, alist->num_arguments, 0); 20755dfecf96Smrg 20765dfecf96Smrg /* Finish the inline function block */ 20775dfecf96Smrg CompileFiniBlock(com); 20785dfecf96Smrg FORM_LEAVE(); 20795dfecf96Smrg 20805dfecf96Smrg /* Restore state */ 20815dfecf96Smrg lisp__data.env.lex = lex; 20825dfecf96Smrg lisp__data.env.head = lisp__data.env.length = base; 20835dfecf96Smrg} 20845dfecf96Smrg 20855dfecf96Smrg/*********************************************************************** 20865dfecf96Smrg * Macro expansion helper functions. 20875dfecf96Smrg ***********************************************************************/ 20885dfecf96Smrgstatic LispObj * 20895dfecf96SmrgComMacroExpandBackquote(LispCom *com, LispObj *object) 20905dfecf96Smrg{ 20915dfecf96Smrg return (LispEvalBackquote(object->data.quote, 1)); 20925dfecf96Smrg} 20935dfecf96Smrg 20945dfecf96Smrgstatic LispObj * 20955dfecf96SmrgComMacroExpandFuncall(LispCom *com, LispObj *function, LispObj *arguments) 20965dfecf96Smrg{ 20975dfecf96Smrg return (LispFuncall(function, arguments, 1)); 20985dfecf96Smrg} 20995dfecf96Smrg 21005dfecf96Smrgstatic LispObj * 21015dfecf96SmrgComMacroExpandEval(LispCom *com, LispObj *object) 21025dfecf96Smrg{ 21035dfecf96Smrg LispObj *result; 21045dfecf96Smrg 21055dfecf96Smrg switch (OBJECT_TYPE(object)) { 21065dfecf96Smrg case LispAtom_t: 21075dfecf96Smrg result = LispGetVar(object); 21085dfecf96Smrg 21095dfecf96Smrg /* Macro expansion requires bounded symbols */ 21105dfecf96Smrg if (result == NULL) 21115dfecf96Smrg LispDestroy("EVAL: the variable %s is unbound", 21125dfecf96Smrg STROBJ(object)); 21135dfecf96Smrg break; 21145dfecf96Smrg 21155dfecf96Smrg case LispCons_t: 21165dfecf96Smrg result = ComMacroExpandFuncall(com, CAR(object), CDR(object)); 21175dfecf96Smrg break; 21185dfecf96Smrg 21195dfecf96Smrg case LispQuote_t: 21205dfecf96Smrg result = object->data.quote; 21215dfecf96Smrg break; 21225dfecf96Smrg 21235dfecf96Smrg case LispBackquote_t: 21245dfecf96Smrg result = ComMacroExpandBackquote(com, object); 21255dfecf96Smrg break; 21265dfecf96Smrg 21275dfecf96Smrg case LispComma_t: 21285dfecf96Smrg LispDestroy("EVAL: comma outside of backquote"); 21295dfecf96Smrg 21305dfecf96Smrg case LispFunctionQuote_t: 21315dfecf96Smrg result = EVAL(object); 21325dfecf96Smrg break; 21335dfecf96Smrg 21345dfecf96Smrg default: 21355dfecf96Smrg result = object; 21365dfecf96Smrg break; 21375dfecf96Smrg } 21385dfecf96Smrg 21395dfecf96Smrg return (result); 21405dfecf96Smrg} 21415dfecf96Smrg 21425dfecf96Smrgstatic LispObj * 21435dfecf96SmrgComMacroExpand(LispCom *com, LispObj *lambda) 21445dfecf96Smrg{ 21455dfecf96Smrg LispObj *result, **presult = &result; 21465dfecf96Smrg int jumped, *pjumped = &jumped, backquote, *pbackquote = &backquote; 21475dfecf96Smrg LispBlock *block; 21485dfecf96Smrg 21495dfecf96Smrg int interpreter_lex, interpreter_head, interpreter_base; 21505dfecf96Smrg 21515dfecf96Smrg /* Save interpreter state */ 21525dfecf96Smrg interpreter_base = lisp__data.stack.length; 21535dfecf96Smrg interpreter_head = lisp__data.env.length; 21545dfecf96Smrg interpreter_lex = lisp__data.env.lex; 21555dfecf96Smrg 21565dfecf96Smrg /* Use the variables */ 21575dfecf96Smrg *presult = NIL; 21585dfecf96Smrg *pjumped = 1; 21595dfecf96Smrg *pbackquote = !CONSP(lambda); 21605dfecf96Smrg 21615dfecf96Smrg block = LispBeginBlock(NIL, LispBlockProtect); 21625dfecf96Smrg if (setjmp(block->jmp) == 0) { 21635dfecf96Smrg if (!backquote) { 21645dfecf96Smrg for (; CONSP(lambda); lambda = CDR(lambda)) 21655dfecf96Smrg result = ComMacroExpandEval(com, CAR(lambda)); 21665dfecf96Smrg } 21675dfecf96Smrg else 21685dfecf96Smrg result = ComMacroExpandBackquote(com, lambda); 21695dfecf96Smrg 21705dfecf96Smrg *pjumped = 0; 21715dfecf96Smrg } 21725dfecf96Smrg LispEndBlock(block); 21735dfecf96Smrg 21745dfecf96Smrg /* If tried to jump out of the macro expansion block */ 21755dfecf96Smrg if (!lisp__data.destroyed && jumped) 21765dfecf96Smrg LispDestroy("*** EVAL: bad jump in macro expansion"); 21775dfecf96Smrg 21785dfecf96Smrg /* Macro expansion did something wrong */ 21795dfecf96Smrg if (lisp__data.destroyed) { 21805dfecf96Smrg LispMessage("*** EVAL: aborting macro expansion"); 21815dfecf96Smrg LispDestroy("."); 21825dfecf96Smrg } 21835dfecf96Smrg 21845dfecf96Smrg /* Restore interpreter state */ 21855dfecf96Smrg lisp__data.env.lex = interpreter_lex; 21865dfecf96Smrg lisp__data.stack.length = interpreter_base; 21875dfecf96Smrg lisp__data.env.head = lisp__data.env.length = interpreter_head; 21885dfecf96Smrg 21895dfecf96Smrg return (result); 21905dfecf96Smrg} 21915dfecf96Smrg 21925dfecf96Smrgstatic void 21935dfecf96SmrgComMacroCall(LispCom *com, LispArgList *alist, 21945dfecf96Smrg LispObj *name, LispObj *lambda, LispObj *arguments) 21955dfecf96Smrg{ 21965dfecf96Smrg int base; 21975dfecf96Smrg LispObj *body; 21985dfecf96Smrg 21995dfecf96Smrg ++com->macro; 22005dfecf96Smrg base = ComCall(com, alist, name, arguments, 0, 0, 0); 22015dfecf96Smrg body = lambda->data.lambda.code; 22025dfecf96Smrg body = ComMacroExpand(com, body); 22035dfecf96Smrg --com->macro; 22045dfecf96Smrg lisp__data.env.head = lisp__data.env.length = base; 22055dfecf96Smrg 22065dfecf96Smrg /* Macro is expanded, store the result */ 22075dfecf96Smrg CAR(com->form) = body; 22085dfecf96Smrg ComEval(com, body); 22095dfecf96Smrg} 22105dfecf96Smrg 22115dfecf96Smrgstatic void 22125dfecf96SmrgComMacroBackquote(LispCom *com, LispObj *lambda) 22135dfecf96Smrg{ 22145dfecf96Smrg LispObj *body; 22155dfecf96Smrg 22165dfecf96Smrg ++com->macro; 22175dfecf96Smrg body = ComMacroExpand(com, lambda); 22185dfecf96Smrg --com->macro; 22195dfecf96Smrg 22205dfecf96Smrg /* Macro is expanded, store the result */ 22215dfecf96Smrg CAR(com->form) = body; 22225dfecf96Smrg 22235dfecf96Smrg com_LoadCon(com, body); 22245dfecf96Smrg} 2225