diff options
author | drh <drh@noemail.net> | 2004-10-04 13:19:23 +0000 |
---|---|---|
committer | drh <drh@noemail.net> | 2004-10-04 13:19:23 +0000 |
commit | f2bc013c7011580ae976e5d7a978863b3f84a52d (patch) | |
tree | 8fdf6922f04914830682242910be66e9d5a58b26 /src | |
parent | 9c105bb990007c678ca28e63b764f8d0b557d5f9 (diff) | |
download | sqlite-f2bc013c7011580ae976e5d7a978863b3f84a52d.tar.gz sqlite-f2bc013c7011580ae976e5d7a978863b3f84a52d.zip |
Save about 800 bytes of code space by aligning TK_ and OP_ constants so that
we do not have to translate between them. (CVS 1998)
FossilOrigin-Name: 4c817e3f293a9c1365e632f7dc13ae440263332a
Diffstat (limited to 'src')
-rw-r--r-- | src/expr.c | 137 | ||||
-rw-r--r-- | src/parse.y | 12 | ||||
-rw-r--r-- | src/sqliteInt.h | 4 | ||||
-rw-r--r-- | src/vdbe.c | 90 |
4 files changed, 125 insertions, 118 deletions
diff --git a/src/expr.c b/src/expr.c index a07fdcd00..75167579b 100644 --- a/src/expr.c +++ b/src/expr.c @@ -12,7 +12,7 @@ ** This file contains routines used for analyzing expressions and ** for generating VDBE code that evaluates expressions in SQLite. ** -** $Id: expr.c,v 1.165 2004/09/25 13:12:15 drh Exp $ +** $Id: expr.c,v 1.166 2004/10/04 13:19:24 drh Exp $ */ #include "sqliteInt.h" #include <ctype.h> @@ -1180,41 +1180,19 @@ static void codeInteger(Vdbe *v, const char *z, int n){ /* ** Generate code into the current Vdbe to evaluate the given ** expression and leave the result on the top of stack. +** +** This code depends on the fact that certain token values (ex: TK_EQ) +** are the same as opcode values (ex: OP_Eq) that implement the corresponding +** operation. Special comments in vdbe.c and the mkopcodeh.awk script in +** the make process cause these values to align. Assert()s in the code +** below verify that the numbers are aligned correctly. */ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){ Vdbe *v = pParse->pVdbe; int op; if( v==0 || pExpr==0 ) return; - switch( pExpr->op ){ - case TK_PLUS: op = OP_Add; break; - case TK_MINUS: op = OP_Subtract; break; - case TK_STAR: op = OP_Multiply; break; - case TK_SLASH: op = OP_Divide; break; - case TK_AND: op = OP_And; break; - case TK_OR: op = OP_Or; break; - case TK_LT: op = OP_Lt; break; - case TK_LE: op = OP_Le; break; - case TK_GT: op = OP_Gt; break; - case TK_GE: op = OP_Ge; break; - case TK_NE: op = OP_Ne; break; - case TK_EQ: op = OP_Eq; break; - case TK_ISNULL: op = OP_IsNull; break; - case TK_NOTNULL: op = OP_NotNull; break; - case TK_NOT: op = OP_Not; break; - case TK_UMINUS: op = OP_Negative; break; - case TK_BITAND: op = OP_BitAnd; break; - case TK_BITOR: op = OP_BitOr; break; - case TK_BITNOT: op = OP_BitNot; break; - case TK_LSHIFT: op = OP_ShiftLeft; break; - case TK_RSHIFT: op = OP_ShiftRight; break; - case TK_REM: op = OP_Remainder; break; - case TK_FLOAT: op = OP_Real; break; - case TK_STRING: op = OP_String8; break; - case TK_BLOB: op = OP_HexBlob; break; - case TK_CONCAT: op = OP_Concat; break; - default: op = 0; break; - } - switch( pExpr->op ){ + op = pExpr->op; + switch( op ){ case TK_COLUMN: { if( pParse->useAgg ){ sqlite3VdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg); @@ -1236,11 +1214,14 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){ } case TK_FLOAT: case TK_STRING: { + assert( TK_FLOAT==OP_Real ); + assert( TK_STRING==OP_String8 ); sqlite3VdbeOp3(v, op, 0, 0, pExpr->token.z, pExpr->token.n); sqlite3VdbeDequoteP3(v, -1); break; } case TK_BLOB: { + assert( TK_BLOB==OP_HexBlob ); sqlite3VdbeOp3(v, op, 0, 0, pExpr->token.z+1, pExpr->token.n-1); sqlite3VdbeDequoteP3(v, -1); break; @@ -1262,6 +1243,12 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){ case TK_GE: case TK_NE: case TK_EQ: { + assert( TK_LT==OP_Lt ); + assert( TK_LE==OP_Le ); + assert( TK_GT==OP_Gt ); + assert( TK_GE==OP_Ge ); + assert( TK_EQ==OP_Eq ); + assert( TK_NE==OP_Ne ); sqlite3ExprCode(pParse, pExpr->pLeft); sqlite3ExprCode(pParse, pExpr->pRight); codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, 0, 0); @@ -1279,6 +1266,17 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){ case TK_LSHIFT: case TK_RSHIFT: case TK_CONCAT: { + assert( TK_AND==OP_And ); + assert( TK_OR==OP_Or ); + assert( TK_PLUS==OP_Add ); + assert( TK_MINUS==OP_Subtract ); + assert( TK_REM==OP_Remainder ); + assert( TK_BITAND==OP_BitAnd ); + assert( TK_BITOR==OP_BitOr ); + assert( TK_SLASH==OP_Divide ); + assert( TK_LSHIFT==OP_ShiftLeft ); + assert( TK_RSHIFT==OP_ShiftRight ); + assert( TK_CONCAT==OP_Concat ); sqlite3ExprCode(pParse, pExpr->pLeft); sqlite3ExprCode(pParse, pExpr->pRight); sqlite3VdbeAddOp(v, op, 0, 0); @@ -1303,6 +1301,8 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){ } case TK_BITNOT: case TK_NOT: { + assert( TK_BITNOT==OP_BitNot ); + assert( TK_NOT==OP_Not ); sqlite3ExprCode(pParse, pExpr->pLeft); sqlite3VdbeAddOp(v, op, 0, 0); break; @@ -1310,13 +1310,15 @@ void sqlite3ExprCode(Parse *pParse, Expr *pExpr){ case TK_ISNULL: case TK_NOTNULL: { int dest; + assert( TK_ISNULL==OP_IsNull ); + assert( TK_NOTNULL==OP_NotNull ); sqlite3VdbeAddOp(v, OP_Integer, 1, 0); sqlite3ExprCode(pParse, pExpr->pLeft); dest = sqlite3VdbeCurrentAddr(v) + 2; sqlite3VdbeAddOp(v, op, 1, dest); sqlite3VdbeAddOp(v, OP_AddImm, -1, 0); + break; } - break; case TK_AGG_FUNCTION: { sqlite3VdbeAddOp(v, OP_AggGet, 0, pExpr->iAgg); break; @@ -1503,23 +1505,19 @@ int sqlite3ExprCodeExprList( ** ** If the expression evaluates to NULL (neither true nor false), then ** take the jump if the jumpIfNull flag is true. +** +** This code depends on the fact that certain token values (ex: TK_EQ) +** are the same as opcode values (ex: OP_Eq) that implement the corresponding +** operation. Special comments in vdbe.c and the mkopcodeh.awk script in +** the make process cause these values to align. Assert()s in the code +** below verify that the numbers are aligned correctly. */ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ Vdbe *v = pParse->pVdbe; int op = 0; if( v==0 || pExpr==0 ) return; - switch( pExpr->op ){ - case TK_LT: op = OP_Lt; break; - case TK_LE: op = OP_Le; break; - case TK_GT: op = OP_Gt; break; - case TK_GE: op = OP_Ge; break; - case TK_NE: op = OP_Ne; break; - case TK_EQ: op = OP_Eq; break; - case TK_ISNULL: op = OP_IsNull; break; - case TK_NOTNULL: op = OP_NotNull; break; - default: break; - } - switch( pExpr->op ){ + op = pExpr->op; + switch( op ){ case TK_AND: { int d2 = sqlite3VdbeMakeLabel(v); sqlite3ExprIfFalse(pParse, pExpr->pLeft, d2, !jumpIfNull); @@ -1542,6 +1540,12 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ case TK_GE: case TK_NE: case TK_EQ: { + assert( TK_LT==OP_Lt ); + assert( TK_LE==OP_Le ); + assert( TK_GT==OP_Gt ); + assert( TK_GE==OP_Ge ); + assert( TK_EQ==OP_Eq ); + assert( TK_NE==OP_Ne ); sqlite3ExprCode(pParse, pExpr->pLeft); sqlite3ExprCode(pParse, pExpr->pRight); codeCompare(pParse, pExpr->pLeft, pExpr->pRight, op, dest, jumpIfNull); @@ -1549,6 +1553,8 @@ void sqlite3ExprIfTrue(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ } case TK_ISNULL: case TK_NOTNULL: { + assert( TK_ISNULL==OP_IsNull ); + assert( TK_NOTNULL==OP_NotNull ); sqlite3ExprCode(pParse, pExpr->pLeft); sqlite3VdbeAddOp(v, op, 1, dest); break; @@ -1597,17 +1603,38 @@ void sqlite3ExprIfFalse(Parse *pParse, Expr *pExpr, int dest, int jumpIfNull){ Vdbe *v = pParse->pVdbe; int op = 0; if( v==0 || pExpr==0 ) return; - switch( pExpr->op ){ - case TK_LT: op = OP_Ge; break; - case TK_LE: op = OP_Gt; break; - case TK_GT: op = OP_Le; break; - case TK_GE: op = OP_Lt; break; - case TK_NE: op = OP_Eq; break; - case TK_EQ: op = OP_Ne; break; - case TK_ISNULL: op = OP_NotNull; break; - case TK_NOTNULL: op = OP_IsNull; break; - default: break; - } + + /* The value of pExpr->op and op are related as follows: + ** + ** pExpr->op op + ** --------- ---------- + ** TK_ISNULL OP_NotNull + ** TK_NOTNULL OP_IsNull + ** TK_NE OP_Eq + ** TK_EQ OP_Ne + ** TK_GT OP_Le + ** TK_LE OP_Gt + ** TK_GE OP_Lt + ** TK_LT OP_Ge + ** + ** For other values of pExpr->op, op is undefined and unused. + ** The value of TK_ and OP_ constants are arranged such that we + ** can compute the mapping above using the following expression. + ** Assert()s verify that the computation is correct. + */ + op = ((pExpr->op+(TK_ISNULL&1))^1)-(TK_ISNULL&1); + + /* Verify correct alignment of TK_ and OP_ constants + */ + assert( pExpr->op!=TK_ISNULL || op==OP_NotNull ); + assert( pExpr->op!=TK_NOTNULL || op==OP_IsNull ); + assert( pExpr->op!=TK_NE || op==OP_Eq ); + assert( pExpr->op!=TK_EQ || op==OP_Ne ); + assert( pExpr->op!=TK_LT || op==OP_Ge ); + assert( pExpr->op!=TK_LE || op==OP_Gt ); + assert( pExpr->op!=TK_GT || op==OP_Le ); + assert( pExpr->op!=TK_GE || op==OP_Lt ); + switch( pExpr->op ){ case TK_AND: { sqlite3ExprIfFalse(pParse, pExpr->pLeft, dest, jumpIfNull); diff --git a/src/parse.y b/src/parse.y index 8d42dfd47..5999e2146 100644 --- a/src/parse.y +++ b/src/parse.y @@ -14,7 +14,7 @@ ** the parser. Lemon will also generate a header file containing ** numeric codes for all of the tokens. ** -** @(#) $Id: parse.y,v 1.139 2004/09/30 14:22:47 drh Exp $ +** @(#) $Id: parse.y,v 1.140 2004/10/04 13:19:24 drh Exp $ */ %token_prefix TK_ %token_type {Token} @@ -137,11 +137,17 @@ id(A) ::= ID(X). {A = X;} // causes them to be assigned integer values that are close together, // which keeps parser tables smaller. // +// The token values assigned to these symbols is determined by the order +// in which lemon first sees them. It must be the case that ISNULL/NOTNULL, +// NE/EQ, GT/LE, and GE/LT are separated by only a single value. See +// the sqlite3ExprIfFalse() routine for additional information on this +// constraint. +// %left OR. %left AND. %right NOT. -%left ISNULL NOTNULL IS LIKE GLOB BETWEEN IN NE EQ. -%left GT GE LT LE. +%left IS LIKE GLOB BETWEEN IN ISNULL NOTNULL NE EQ. +%left GT LE GE LT. %left BITAND BITOR LSHIFT RSHIFT. %left PLUS MINUS. %left STAR SLASH REM. diff --git a/src/sqliteInt.h b/src/sqliteInt.h index e8946f256..7b4c4fc0e 100644 --- a/src/sqliteInt.h +++ b/src/sqliteInt.h @@ -11,7 +11,7 @@ ************************************************************************* ** Internal interface definitions for SQLite. ** -** @(#) $Id: sqliteInt.h,v 1.325 2004/10/01 02:00:31 drh Exp $ +** @(#) $Id: sqliteInt.h,v 1.326 2004/10/04 13:19:24 drh Exp $ */ #ifndef _SQLITEINT_H_ #define _SQLITEINT_H_ @@ -767,9 +767,9 @@ struct Token { struct Expr { u8 op; /* Operation performed by this node */ char affinity; /* The affinity of the column or 0 if not a column */ - CollSeq *pColl; /* The collation type of the column or 0 */ u8 iDb; /* Database referenced by this expression */ u8 flags; /* Various flags. See below */ + CollSeq *pColl; /* The collation type of the column or 0 */ Expr *pLeft, *pRight; /* Left and right subnodes */ ExprList *pList; /* A list of expressions used as function arguments ** or in "<expr> IN (<expr-list)" */ diff --git a/src/vdbe.c b/src/vdbe.c index 5ec829464..327460ca2 100644 --- a/src/vdbe.c +++ b/src/vdbe.c @@ -43,7 +43,7 @@ ** in this file for details. If in doubt, do not deviate from existing ** commenting and indentation practices when changing or adding code. ** -** $Id: vdbe.c,v 1.415 2004/09/19 00:50:21 drh Exp $ +** $Id: vdbe.c,v 1.416 2004/10/04 13:19:24 drh Exp $ */ #include "sqliteInt.h" #include "os.h" @@ -184,32 +184,6 @@ static int AggInsert(Agg *p, char *zKey, int nKey){ } /* -** Store a pointer to the AggElem currently in focus in *ppElem. Return -** SQLITE_OK if successful, otherwise an error-code. -*/ -static int AggInFocus(Agg *p, AggElem **ppElem){ - int rc; - int res; - - if( p->pCurrent ){ - *ppElem = p->pCurrent; - return SQLITE_OK; - } - - rc = sqlite3BtreeFirst(p->pCsr, &res); - if( rc!=SQLITE_OK ){ - return rc; - } - if( res!=0 ){ - rc = AggInsert(p,"",1); - *ppElem = p->pCurrent; - }else{ - rc = sqlite3BtreeData(p->pCsr, 0, 4, (char *)ppElem); - } - return rc; -} - -/* ** Pop the stack N times. */ static void popStack(Mem **ppTos, int N){ @@ -559,7 +533,9 @@ int sqlite3VdbeExec( ** file looking for lines that begin with "case OP_". The opcodes.h files ** will be filled with #defines that give unique integer values to each ** opcode and the opcodes.c file is filled with an array of strings where -** each string is the symbolic name for the corresponding opcode. +** each string is the symbolic name for the corresponding opcode. If the +** case statement is followed by a comment of the form "/# same as ... #/" +** that comment is used to determine the particular value of the opcode. ** ** Documentation about VDBE opcodes is generated by scanning this file ** for lines of that contain "Opcode:". That line and all subsequent @@ -677,7 +653,7 @@ case OP_Integer: { ** ** The string value P3 is converted to a real and pushed on to the stack. */ -case OP_Real: { +case OP_Real: { /* same as TK_FLOAT */ pTos++; pTos->flags = MEM_Str|MEM_Static|MEM_Term; pTos->z = pOp->p3; @@ -694,7 +670,7 @@ case OP_Real: { ** P3 points to a nul terminated UTF-8 string. This opcode is transformed ** into an OP_String before it is executed for the first time. */ -case OP_String8: { +case OP_String8: { /* same as TK_STRING */ pOp->opcode = OP_String; if( db->enc!=SQLITE_UTF8 && pOp->p3 ){ @@ -745,7 +721,7 @@ case OP_String: { ** The first time this instruction executes, in transforms itself into a ** 'Blob' opcode with a binary blob as P3. */ -case OP_HexBlob: { +case OP_HexBlob: { /* same as TK_BLOB */ pOp->opcode = OP_Blob; pOp->p1 = strlen(pOp->p3)/2; if( pOp->p1 ){ @@ -922,7 +898,7 @@ case OP_Callback: { ** When P1==1, this routine makes a copy of the top stack element ** into memory obtained from sqliteMalloc(). */ -case OP_Concat: { +case OP_Concat: { /* same as TK_CONCAT */ char *zNew; int nByte; int nField; @@ -1030,11 +1006,11 @@ case OP_Concat: { ** function before the division. Division by zero returns NULL. ** If either operand is NULL, the result is NULL. */ -case OP_Add: -case OP_Subtract: -case OP_Multiply: -case OP_Divide: -case OP_Remainder: { +case OP_Add: /* same as TK_PLUS */ +case OP_Subtract: /* same as TK_MINUS */ +case OP_Multiply: /* same as TK_STAR */ +case OP_Divide: /* same as TK_SLASH */ +case OP_Remainder: { /* same as TK_REM */ Mem *pNos = &pTos[-1]; assert( pNos>=p->aStack ); if( ((pTos->flags | pNos->flags) & MEM_Null)!=0 ){ @@ -1233,10 +1209,10 @@ case OP_Function: { ** right by N bits where N is the top element on the stack. ** If either operand is NULL, the result is NULL. */ -case OP_BitAnd: -case OP_BitOr: -case OP_ShiftLeft: -case OP_ShiftRight: { +case OP_BitAnd: /* same as TK_BITAND */ +case OP_BitOr: /* same as TK_BITOR */ +case OP_ShiftLeft: /* same as TK_LSHIFT */ +case OP_ShiftRight: { /* same as TK_RSHIFT */ Mem *pNos = &pTos[-1]; int a, b; @@ -1398,12 +1374,12 @@ case OP_MustBeInt: { ** the 2nd element down on the stack is greater than or equal to the ** top of the stack. See the Eq opcode for additional information. */ -case OP_Eq: -case OP_Ne: -case OP_Lt: -case OP_Le: -case OP_Gt: -case OP_Ge: { +case OP_Eq: /* same as TK_EQ */ +case OP_Ne: /* same as TK_NE */ +case OP_Lt: /* same as TK_LT */ +case OP_Le: /* same as TK_LE */ +case OP_Gt: /* same as TK_GT */ +case OP_Ge: { /* same as TK_GE */ Mem *pNos; int flags; int res; @@ -1469,8 +1445,8 @@ case OP_Ge: { ** two values and push the resulting boolean value back onto the ** stack. */ -case OP_And: -case OP_Or: { +case OP_And: /* same as TK_AND */ +case OP_Or: { /* same as TK_OR */ Mem *pNos = &pTos[-1]; int v1, v2; /* 0==TRUE, 1==FALSE, 2==UNKNOWN or NULL */ @@ -1517,7 +1493,7 @@ case OP_Or: { ** with its absolute value. If the top of the stack is NULL ** its value is unchanged. */ -case OP_Negative: +case OP_Negative: /* same as TK_UMINUS */ case OP_AbsValue: { assert( pTos>=p->aStack ); if( pTos->flags & MEM_Real ){ @@ -1550,7 +1526,7 @@ case OP_AbsValue: { ** with its complement. If the top of the stack is NULL its value ** is unchanged. */ -case OP_Not: { +case OP_Not: { /* same as TK_NOT */ assert( pTos>=p->aStack ); if( pTos->flags & MEM_Null ) break; /* Do nothing to NULLs */ Integerify(pTos); @@ -1566,7 +1542,7 @@ case OP_Not: { ** with its ones-complement. If the top of the stack is NULL its ** value is unchanged. */ -case OP_BitNot: { +case OP_BitNot: { /* same as TK_BITNOT */ assert( pTos>=p->aStack ); if( pTos->flags & MEM_Null ) break; /* Do nothing to NULLs */ Integerify(pTos); @@ -1627,7 +1603,7 @@ case OP_IfNot: { ** to P2. Pop the stack P1 times if P1>0. If P1<0 leave the stack ** unchanged. */ -case OP_IsNull: { +case OP_IsNull: { /* same as TK_ISNULL */ int i, cnt; Mem *pTerm; cnt = pOp->p1; @@ -1650,7 +1626,7 @@ case OP_IsNull: { ** stack if P1 times if P1 is greater than zero. If P1 is less than ** zero then leave the stack unchanged. */ -case OP_NotNull: { +case OP_NotNull: { /* same as TK_NOTNULL */ int i, cnt; cnt = pOp->p1; if( cnt<0 ) cnt = -cnt; @@ -4241,8 +4217,7 @@ case OP_AggFocus: { case OP_AggSet: { AggElem *pFocus; int i = pOp->p2; - rc = AggInFocus(&p->agg, &pFocus); - if( rc!=SQLITE_OK ) goto abort_due_to_error; + pFocus = p->agg.pCurrent; assert( pTos>=p->aStack ); if( pFocus==0 ) goto no_mem; assert( i>=0 && i<p->agg.nMem ); @@ -4260,8 +4235,7 @@ case OP_AggSet: { case OP_AggGet: { AggElem *pFocus; int i = pOp->p2; - rc = AggInFocus(&p->agg, &pFocus); - if( rc!=SQLITE_OK ) goto abort_due_to_error; + pFocus = p->agg.pCurrent; if( pFocus==0 ) goto no_mem; assert( i>=0 && i<p->agg.nMem ); pTos++; |