From 737023909817fcc30432c33881868b521a3661d9 Mon Sep 17 00:00:00 2001 From: dgp Date: Fri, 8 Dec 2006 20:48:08 +0000 Subject: * generic/tclBasic.c: Another step down the path of re-using * generic/tclCompExpr.c: TclExecuteByteCode to implement the TIP 174 * generic/tclCompile.h: commands instead of using a mass of code * generic/tclMathOp.c: duplication. Now all operator commands that * tests/mathop.test: demand exactly one operation are implemented via TclSingleOpCmd and a call to TEBC. --- ChangeLog | 7 ++++ generic/tclBasic.c | 89 +++++++++++++++++++++++++++++++++------------------ generic/tclCompExpr.c | 60 +++++++++++++++++++++------------- generic/tclCompile.h | 15 ++++++++- generic/tclMathOp.c | 5 ++- tests/mathop.test | 10 +++--- 6 files changed, 122 insertions(+), 64 deletions(-) diff --git a/ChangeLog b/ChangeLog index 77b92d6..a48d227 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,12 @@ 2006-12-08 Don Porter + * generic/tclBasic.c: Another step down the path of re-using + * generic/tclCompExpr.c: TclExecuteByteCode to implement the TIP 174 + * generic/tclCompile.h: commands instead of using a mass of code + * generic/tclMathOp.c: duplication. Now all operator commands that + * tests/mathop.test: demand exactly one operation are implemented + via TclSingleOpCmd and a call to TEBC. + * generic/tclCompExpr.c: Revised implementation of TclInvertOpCmd * generic/tclMathOp.c: to perform a bytecode compile / execute sequence. This demonstrates a path toward avoiding mountains of diff --git a/generic/tclBasic.c b/generic/tclBasic.c index bef8f10..8c43737 100644 --- a/generic/tclBasic.c +++ b/generic/tclBasic.c @@ -13,7 +13,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclBasic.c,v 1.227 2006/12/07 16:29:31 dkf Exp $ + * RCS: @(#) $Id: tclBasic.c,v 1.228 2006/12/08 20:48:08 dgp Exp $ */ #include "tclInt.h" @@ -53,6 +53,7 @@ static char * CallCommandTraces (Interp *iPtr, Command *cmdPtr, CONST char *oldName, CONST char* newName, int flags); static int CheckDoubleResult (Tcl_Interp *interp, double dResult); static void DeleteInterpProc (Tcl_Interp *interp); +static void DeleteOpCmdClientData(ClientData clientData); static void ProcessUnexpectedResult (Tcl_Interp *interp, int returnCode); static int OldMathFuncProc (ClientData clientData, Tcl_Interp *interp, @@ -270,31 +271,40 @@ static const BuiltinFuncDef BuiltinFuncTable[] = { * TIP#174's math operators. */ -static const CmdInfo mathOpCmds[] = { - { "~", TclInvertOpCmd, TclCompileInvertOpCmd, 1 }, - { "!", TclNotOpCmd, TclCompileNotOpCmd, 1 }, - { "+", TclAddOpCmd, TclCompileAddOpCmd, 1 }, - { "*", TclMulOpCmd, TclCompileMulOpCmd, 1 }, - { "&", TclAndOpCmd, TclCompileAndOpCmd, 1 }, - { "|", TclOrOpCmd, TclCompileOrOpCmd, 1 }, - { "^", TclXorOpCmd, TclCompileXorOpCmd, 1 }, - { "**", TclPowOpCmd, TclCompilePowOpCmd, 1 }, - { "<<", TclLshiftOpCmd, TclCompileLshiftOpCmd, 1 }, - { ">>", TclRshiftOpCmd, TclCompileRshiftOpCmd, 1 }, - { "%", TclModOpCmd, TclCompileModOpCmd, 1 }, - { "!=", TclNeqOpCmd, TclCompileNeqOpCmd, 1 }, - { "ne", TclStrneqOpCmd, TclCompileStrneqOpCmd, 1 }, - { "in", TclInOpCmd, TclCompileInOpCmd, 1 }, - { "ni", TclNiOpCmd, TclCompileNiOpCmd, 1 }, - { "-", TclMinusOpCmd, TclCompileMinusOpCmd, 1 }, - { "/", TclDivOpCmd, TclCompileDivOpCmd, 1 }, - { "<", TclLessOpCmd, TclCompileLessOpCmd, 1 }, - { "<=", TclLeqOpCmd, TclCompileLeqOpCmd, 1 }, - { ">", TclGreaterOpCmd, TclCompileGreaterOpCmd, 1 }, - { ">=", TclGeqOpCmd, TclCompileGeqOpCmd, 1 }, - { "==", TclEqOpCmd, TclCompileEqOpCmd, 1 }, - { "eq", TclStreqOpCmd, TclCompileStreqOpCmd, 1 }, - { NULL, NULL, NULL, 0 } +typedef struct { + const char *name; /* Name of object-based command. */ + Tcl_ObjCmdProc *objProc; /* Object-based function for command. */ + CompileProc *compileProc; /* Function called to compile command. */ + int numArgs; + const char *expected; /* For error message, what argument(s) + * were expected. */ +} OpCmdInfo; + +static const OpCmdInfo mathOpCmds[] = { + { "~", TclSingleOpCmd, TclCompileInvertOpCmd, 1, "integer" }, + { "!", TclSingleOpCmd, TclCompileNotOpCmd, 1, "boolean" }, + { "+", TclAddOpCmd, TclCompileAddOpCmd, 0, NULL }, + { "*", TclMulOpCmd, TclCompileMulOpCmd, 0, NULL }, + { "&", TclAndOpCmd, TclCompileAndOpCmd, 0, NULL }, + { "|", TclOrOpCmd, TclCompileOrOpCmd, 0, NULL }, + { "^", TclXorOpCmd, TclCompileXorOpCmd, 0, NULL }, + { "**", TclPowOpCmd, TclCompilePowOpCmd, 0, NULL }, + { "<<", TclSingleOpCmd, TclCompileLshiftOpCmd, 2, "integer shift" }, + { ">>", TclSingleOpCmd, TclCompileRshiftOpCmd, 2, "integer shift" }, + { "%", TclSingleOpCmd, TclCompileModOpCmd, 2, "integer integer" }, + { "!=", TclSingleOpCmd, TclCompileNeqOpCmd, 2, "value value"}, + { "ne", TclSingleOpCmd, TclCompileStrneqOpCmd, 2, "value value" }, + { "in", TclSingleOpCmd, TclCompileInOpCmd, 2, "value list"}, + { "ni", TclSingleOpCmd, TclCompileNiOpCmd, 2, "value list"}, + { "-", TclMinusOpCmd, TclCompileMinusOpCmd, 0, NULL }, + { "/", TclDivOpCmd, TclCompileDivOpCmd, 0, NULL }, + { "<", TclLessOpCmd, TclCompileLessOpCmd, 0, NULL }, + { "<=", TclLeqOpCmd, TclCompileLeqOpCmd, 0, NULL }, + { ">", TclGreaterOpCmd, TclCompileGreaterOpCmd, 0, NULL }, + { ">=", TclGeqOpCmd, TclCompileGeqOpCmd, 0, NULL }, + { "==", TclEqOpCmd, TclCompileEqOpCmd, 0, NULL }, + { "eq", TclStreqOpCmd, TclCompileStreqOpCmd, 0, NULL }, + { NULL, NULL, NULL, 0, NULL } }; /* @@ -322,6 +332,7 @@ Tcl_CreateInterp(void) Tcl_Interp *interp; Command *cmdPtr; const BuiltinFuncDef *builtinFuncPtr; + const OpCmdInfo *opcmdInfoPtr; const CmdInfo *cmdInfoPtr; const CmdInfo2 *cmdInfo2Ptr; Tcl_Namespace *mathfuncNSPtr, *mathopNSPtr; @@ -633,14 +644,20 @@ Tcl_CreateInterp(void) } (void) Tcl_Export(interp, mathopNSPtr, "*", 1); strcpy(mathFuncName, "::tcl::mathop::"); - for (cmdInfoPtr=mathOpCmds ; cmdInfoPtr->name!=NULL ; cmdInfoPtr++) { - strcpy(mathFuncName + MATH_OP_PREFIX_LEN, cmdInfoPtr->name); + for (opcmdInfoPtr=mathOpCmds ; opcmdInfoPtr->name!=NULL ; opcmdInfoPtr++) { + TclOpCmdClientData *occdPtr + = (TclOpCmdClientData *) ckalloc(sizeof(TclOpCmdClientData)); + occdPtr->operator = opcmdInfoPtr->name; + occdPtr->numArgs = opcmdInfoPtr->numArgs; + occdPtr->expected = opcmdInfoPtr->expected; + strcpy(mathFuncName + MATH_OP_PREFIX_LEN, opcmdInfoPtr->name); cmdPtr = (Command *) Tcl_CreateObjCommand(interp, mathFuncName, - cmdInfoPtr->objProc, NULL, NULL); + opcmdInfoPtr->objProc, (ClientData) occdPtr, + DeleteOpCmdClientData); if (cmdPtr == NULL) { - Tcl_Panic("failed to create math operator %s", cmdInfoPtr->name); - } else if (cmdInfoPtr->compileProc != NULL) { - cmdPtr->compileProc = cmdInfoPtr->compileProc; + Tcl_Panic("failed to create math operator %s", opcmdInfoPtr->name); + } else if (opcmdInfoPtr->compileProc != NULL) { + cmdPtr->compileProc = opcmdInfoPtr->compileProc; } } @@ -717,6 +734,14 @@ Tcl_CreateInterp(void) return interp; } + +static void +DeleteOpCmdClientData( + ClientData clientData) +{ + TclOpCmdClientData *occdPtr = (TclOpCmdClientData *)clientData; + ckfree((char *)occdPtr); +} /* *---------------------------------------------------------------------- diff --git a/generic/tclCompExpr.c b/generic/tclCompExpr.c index 146c3c4..195f67e 100644 --- a/generic/tclCompExpr.c +++ b/generic/tclCompExpr.c @@ -10,7 +10,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclCompExpr.c,v 1.41 2006/12/08 18:08:33 dgp Exp $ + * RCS: @(#) $Id: tclCompExpr.c,v 1.42 2006/12/08 20:48:09 dgp Exp $ */ #include "tclInt.h" @@ -2584,38 +2584,23 @@ CompileExprTree( } } -int -TclInvertOpCmd( - ClientData clientData, +static int +OpCmd( Tcl_Interp *interp, - int objc, - Tcl_Obj *const objv[]) + OpNode *nodes, + Tcl_Obj * const litObjv[]) { CompileEnv compEnv; ByteCode *byteCodePtr; - OpNode nodes[2]; - int code, tmp = 1; - Tcl_Obj *byteCodeObj; - - if (objc != 2) { - Tcl_WrongNumArgs(interp, 1, objv, "number"); - return TCL_ERROR; - } + int code, tmp=1; + Tcl_Obj *byteCodeObj = Tcl_NewObj(); /* Note we are compiling an expression with literal arguments. * This means there can be no [info frame] calls when we execute * the resulting bytecode, so there's no need to tend to TIP 280 issues */ TclInitCompileEnv(interp, &compEnv, NULL, 0, NULL, 0); - - nodes[0].lexeme = START; - nodes[0].right = 1; - nodes[1].lexeme = BIT_NOT; - nodes[1].right = OT_LITERAL; - nodes[1].parent = 0; - - CompileExprTree(interp, nodes, objv+1, NULL, NULL, &tmp, &compEnv); + CompileExprTree(interp, nodes, litObjv, NULL, NULL, &tmp, &compEnv); TclEmitOpcode(INST_DONE, &compEnv); - byteCodeObj = Tcl_NewObj(); Tcl_IncrRefCount(byteCodeObj); TclInitByteCodeObj(byteCodeObj, &compEnv); TclFreeCompileEnv(&compEnv); @@ -2624,6 +2609,35 @@ TclInvertOpCmd( Tcl_DecrRefCount(byteCodeObj); return code; } + +int +TclSingleOpCmd( + ClientData clientData, + Tcl_Interp *interp, + int objc, + Tcl_Obj *const objv[]) +{ + TclOpCmdClientData *occdPtr = (TclOpCmdClientData *)clientData; + unsigned char lexeme; + OpNode nodes[2]; + + if (objc != 1+occdPtr->numArgs) { + Tcl_WrongNumArgs(interp, 1, objv, occdPtr->expected); + return TCL_ERROR; + } + + ParseLexeme(occdPtr->operator, strlen(occdPtr->operator), &lexeme, NULL); + nodes[0].lexeme = START; + nodes[0].right = 1; + nodes[1].lexeme = lexeme; + nodes[1].left = OT_LITERAL; + nodes[1].right = OT_LITERAL; + nodes[1].parent = 0; + + return OpCmd(interp, nodes, objv+1); +} + + /* *---------------------------------------------------------------------- diff --git a/generic/tclCompile.h b/generic/tclCompile.h index 5dc9cd7..c864c3c 100644 --- a/generic/tclCompile.h +++ b/generic/tclCompile.h @@ -8,7 +8,7 @@ * See the file "license.terms" for information on usage and redistribution * of this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclCompile.h,v 1.63 2006/12/08 18:08:35 dgp Exp $ + * RCS: @(#) $Id: tclCompile.h,v 1.64 2006/12/08 20:48:09 dgp Exp $ */ #ifndef _TCLCOMPILATION @@ -746,6 +746,16 @@ typedef struct JumptableInfo { } JumptableInfo; MODULE_SCOPE AuxDataType tclJumptableInfoType; + +/* + * ClientData type used by the math operator commands. + */ +typedef struct { + const char *operator; + const char *expected; + int numArgs; +} TclOpCmdClientData; + /* *---------------------------------------------------------------- @@ -845,6 +855,9 @@ MODULE_SCOPE int TclRegisterLiteral(CompileEnv *envPtr, MODULE_SCOPE void TclReleaseLiteral(Tcl_Interp *interp, Tcl_Obj *objPtr); MODULE_SCOPE void TclSetCmdNameObj(Tcl_Interp *interp, Tcl_Obj *objPtr, Command *cmdPtr); +MODULE_SCOPE int TclSingleOpCmd(ClientData clientData, + Tcl_Interp *interp, int objc, + Tcl_Obj *CONST objv[]); #ifdef TCL_COMPILE_DEBUG MODULE_SCOPE void TclVerifyGlobalLiteralTable(Interp *iPtr); MODULE_SCOPE void TclVerifyLocalLiteralTable(CompileEnv *envPtr); diff --git a/generic/tclMathOp.c b/generic/tclMathOp.c index f146a39..0ef70a1 100644 --- a/generic/tclMathOp.c +++ b/generic/tclMathOp.c @@ -9,7 +9,7 @@ * See the file "license.terms" for information on usage and redistribution of * this file, and for a DISCLAIMER OF ALL WARRANTIES. * - * RCS: @(#) $Id: tclMathOp.c,v 1.6 2006/12/08 18:08:37 dgp Exp $ + * RCS: @(#) $Id: tclMathOp.c,v 1.7 2006/12/08 20:48:09 dgp Exp $ */ #include "tclInt.h" @@ -1047,7 +1047,7 @@ CompareNumbers( * *---------------------------------------------------------------------- */ -#if 0 + int TclInvertOpCmd( ClientData clientData, @@ -1108,7 +1108,6 @@ TclInvertOpCmd( } } } -#endif /* *---------------------------------------------------------------------- diff --git a/tests/mathop.test b/tests/mathop.test index 477120d..b7e886b 100644 --- a/tests/mathop.test +++ b/tests/mathop.test @@ -10,7 +10,7 @@ # See the file "license.terms" for information on usage and redistribution of # this file, and for a DISCLAIMER OF ALL WARRANTIES. # -# RCS: @(#) $Id: mathop.test,v 1.6 2006/12/08 16:14:18 dgp Exp $ +# RCS: @(#) $Id: mathop.test,v 1.7 2006/12/08 20:48:09 dgp Exp $ if {[lsearch [namespace children] ::tcltest] == -1} { package require tcltest 2.1 @@ -306,10 +306,10 @@ namespace eval ::testmathop { } -returnCodes error -result {can't use non-numeric string as operand of "~"} test mathop-4.9 {compiled ~: errors} -body { ~ 0 0 - } -returnCodes error -result "wrong # args: should be \"~ number\"" + } -returnCodes error -result "wrong # args: should be \"~ integer\"" test mathop-4.10 {compiled ~: errors} -body { ~ - } -returnCodes error -result "wrong # args: should be \"~ number\"" + } -returnCodes error -result "wrong # args: should be \"~ integer\"" test mathop-4.11 {compiled ~: errors} -returnCodes error -body { ~ 0.0 } -result {can't use floating-point value as operand of "~"} @@ -329,10 +329,10 @@ namespace eval ::testmathop { } -returnCodes error -result {can't use non-numeric string as operand of "~"} test mathop-4.21 {interpreted ~: errors} -body { $op 0 0 - } -returnCodes error -result "wrong # args: should be \"~ number\"" + } -returnCodes error -result "wrong # args: should be \"~ integer\"" test mathop-4.22 {interpreted ~: errors} -body { $op - } -returnCodes error -result "wrong # args: should be \"~ number\"" + } -returnCodes error -result "wrong # args: should be \"~ integer\"" test mathop-4.23 {interpreted ~: errors} -returnCodes error -body { $op 0.0 } -result {can't use floating-point value as operand of "~"} -- cgit v0.12