From b29b0a52275a8df96fecce1e7b3d3e5830fe13c9 Mon Sep 17 00:00:00 2001 From: drh Date: Sat, 23 Feb 2002 19:39:46 +0000 Subject: [PATCH] Modify lemon to use much less memory for its parser tables. This reduces the size of the library by 50K, which is important for an embedded library. (CVS 389) FossilOrigin-Name: 67a135a051e7c96ddbfe85976539b4b8372c7026 --- manifest | 14 ++++++------ manifest.uuid | 2 +- tool/lemon.c | 60 +++++++++++++++++++++++++++------------------------ tool/lempar.c | 20 +++++++++-------- 4 files changed, 51 insertions(+), 45 deletions(-) diff --git a/manifest b/manifest index 721b6f8326..6d41043211 100644 --- a/manifest +++ b/manifest @@ -1,5 +1,5 @@ -C Bug\sfix\sin\slemon:\s3-way\sconflicts\s(SHIFT/REDUCE/REDUCE)\swere\snot\sdetected\sor\nresolved.\s\sThis\sis\snow\sfixed.\s\sAlso,\stable\scompression\sworks\sa\slittle\sbetter.\s(CVS\s388) -D 2002-02-23T18:45:13 +C Modify\slemon\sto\suse\smuch\sless\smemory\sfor\sits\sparser\stables.\s\sThis\sreduces\nthe\ssize\sof\sthe\slibrary\sby\s50K,\swhich\sis\simportant\sfor\san\sembedded\slibrary.\s(CVS\s389) +D 2002-02-23T19:39:47 F Makefile.in 9fa4277413bf1d9cf91365f07d4108d7d87ed2af F Makefile.template 3372d45f8853afdb70bd30cc6fb50a3cd9069834 F README a4c0ba11354ef6ba0776b400d057c59da47a4cc0 @@ -99,8 +99,8 @@ F test/unique.test 07776624b82221a80c8b4138ce0dd8b0853bb3ea F test/update.test 3cf1ca0565f678063c2dfa9a7948d2d66ae1a778 F test/vacuum.test 8acf8669f3b627e54149b25165b034aa06c2432e F test/where.test 032d581c3de4893eba33b569e581c46b941bb02a -F tool/lemon.c 7502222a5d704d9d5d1ac437f73667855d687862 -F tool/lempar.c 9b604e6a8b3d55c0b9cbcb130a7302fb8bafe2b9 +F tool/lemon.c d4b4e127e70633be1bbea49c2ccba5cdb4b77a5f +F tool/lempar.c 2ff255186fffb38a43a9f7b010e87eee6308edcc F tool/memleak.awk 296dfbce7a9ca499b95ce04e30334e64a50052e0 F tool/opNames.awk 5ba1f48aa854ee3b7c3d2b54233665bc3e649ea2 F tool/opcodeDoc.awk b3a2a3d5d3075b8bd90b7afe24283efdd586659c @@ -125,7 +125,7 @@ F www/speed.tcl 83457b2bf6bb430900bd48ca3dd98264d9a916a5 F www/sqlite.tcl 8b5884354cb615049aed83039f8dfe1552a44279 F www/tclsqlite.tcl 829b393d1ab187fd7a5e978631b3429318885c49 F www/vdbe.tcl 2013852c27a02a091d39a766bc87cff329f21218 -P 39fed2df11382b9855d518502a6c2ca200fa66b8 -R bbf759a9eca350d9e39199c34c6ab1fb +P 8da0ac9a8bb859377613dd18f4f423eb49c7338b +R a10568441a27cde980e4058838f315f0 U drh -Z 95f9230334dd6740861a9a25c1c709f1 +Z 77767b7d4f55ba40f2761ab26d448e78 diff --git a/manifest.uuid b/manifest.uuid index 0115377959..ed839134c2 100644 --- a/manifest.uuid +++ b/manifest.uuid @@ -1 +1 @@ -8da0ac9a8bb859377613dd18f4f423eb49c7338b \ No newline at end of file +67a135a051e7c96ddbfe85976539b4b8372c7026 \ No newline at end of file diff --git a/tool/lemon.c b/tool/lemon.c index 3e641a4d46..eae3c09fd4 100644 --- a/tool/lemon.c +++ b/tool/lemon.c @@ -2927,6 +2927,20 @@ int mhflag; /* True if generating makeheaders output */ *plineno = lineno; } +/* +** Return the name of a C datatype able to represent values between +** 0 and N, inclusive. +*/ +static const char *minimum_size_type(int N){ + if( N<=255 ){ + return "unsigned char"; + }else if( N<65535 ){ + return "unsigned short int"; + }else{ + return "unsigned int"; + } +} + /* Generate C source code for the parser */ void ReportTable(lemp, mhflag) struct lemon *lemp; @@ -2978,10 +2992,10 @@ int mhflag; /* Output in makeheaders format if true */ /* Generate the defines */ fprintf(out,"/* \001 */\n"); fprintf(out,"#define YYCODETYPE %s\n", - lemp->nsymbol>250?"int":"unsigned char"); lineno++; + minimum_size_type(lemp->nsymbol+5)); lineno++; fprintf(out,"#define YYNOCODE %d\n",lemp->nsymbol+1); lineno++; fprintf(out,"#define YYACTIONTYPE %s\n", - lemp->nstate+lemp->nrule>250?"int":"unsigned char"); lineno++; + minimum_size_type(lemp->nstate+lemp->nrule+5)); lineno++; print_stack_union(out,lemp,&lineno,mhflag); if( lemp->stacksize ){ if( atoi(lemp->stacksize)<=0 ){ @@ -3027,13 +3041,16 @@ int mhflag; /* Output in makeheaders format if true */ ** structure: ** struct yyActionEntry { ** YYCODETYPE lookahead; + ** YYCODETYPE next; ** YYACTIONTYPE action; - ** struct yyActionEntry *next; ** } ** ** The entries are grouped into hash tables, one hash table for each - ** parser state. The hash table has a size which is the smallest - ** power of two needed to hold all entries. + ** parser state. The hash table has a size which is the number of + ** entries in that table. In case of a collision, the "next" value + ** contains one more than the index into the hash table of the next + ** entry in the collision chain. A "next" value of 0 means the end + ** of the chain has been reached. */ tablecnt = 0; @@ -3053,8 +3070,7 @@ int mhflag; /* Output in makeheaders format if true */ stp->naction++; } } - tablesize = 1; - while( tablesizenaction ) tablesize += tablesize; + tablesize = stp->naction; assert( tablesize<= sizeof(table)/sizeof(table[0]) ); for(j=0; jsp->index==lemp->nsymbol ){ stp->tabdfltact = action; }else if( action>=0 ){ - h = ap->sp->index & (tablesize-1); + h = ap->sp->index % tablesize; ap->collide = table[h]; table[h] = ap; } @@ -3089,22 +3105,13 @@ int mhflag; /* Output in makeheaders format if true */ /* Print the hash table */ fprintf(out,"/* State %d */\n",stp->index); lineno++; for(j=0; jsp->index, + collide[j]+1, compute_action(lemp,table[j])); - if( collide[j]>=0 ){ - fprintf(out,"&yyActionTable[%4d] }, /* ", - collide[j] + tablecnt); - }else{ - fprintf(out,"0 }, /* "); - } - PrintAction(table[j],out,22); - fprintf(out," */\n"); - } + PrintAction(table[j],out,22); + fprintf(out," */\n"); lineno++; } @@ -3119,18 +3126,15 @@ int mhflag; /* Output in makeheaders format if true */ ** Each entry is an element of the following structure: ** struct yyStateEntry { ** struct yyActionEntry *hashtbl; - ** int mask; + ** YYCODETYPE nEntry; ** YYACTIONTYPE actionDefault; ** } */ for(i=0; instate; i++){ - int tablesize; stp = lemp->sorted[i]; - tablesize = 1; - while( tablesizenaction ) tablesize += tablesize; - fprintf(out," { &yyActionTable[%d], %d, %d},\n", + fprintf(out," { &yyActionTable[%d],%4d,%4d },\n", stp->tabstart, - tablesize - 1, + stp->naction, stp->tabdfltact); lineno++; } tplt_xfer(lemp->name,in,out,&lineno); diff --git a/tool/lempar.c b/tool/lempar.c index a0b066f9d8..6a2cd08747 100644 --- a/tool/lempar.c +++ b/tool/lempar.c @@ -76,8 +76,8 @@ */ struct yyActionEntry { YYCODETYPE lookahead; /* The value of the look-ahead token */ + YYCODETYPE next; /* Next entry + 1. Zero at end of collision chain */ YYACTIONTYPE action; /* Action to take for this look-ahead */ - struct yyActionEntry *next; /* Next look-ahead with the same hash, or NULL */ }; static struct yyActionEntry yyActionTable[] = { %% @@ -89,15 +89,14 @@ static struct yyActionEntry yyActionTable[] = { ** ** + A pointer to the start of the action hash table in yyActionTable. ** -** + A mask used to hash the look-ahead token. The mask is an integer -** which is one less than the size of the hash table. +** + The number of entries in the action hash table. ** ** + The default action. This is the action to take if no entry for ** the given look-ahead is found in the action hash table. */ struct yyStateEntry { struct yyActionEntry *hashtbl; /* Start of the hash table in yyActionTable */ - int mask; /* Mask used for hashing the look-ahead */ + YYCODETYPE nEntry; /* Number of entries in action hash table */ YYACTIONTYPE actionDefault; /* Default action if look-ahead not found */ }; static struct yyStateEntry yyStateTable[] = { @@ -297,13 +296,16 @@ static int yy_find_parser_action( /* if( pParser->idx<0 ) return YY_NO_ACTION; */ pState = &yyStateTable[pParser->top->stateno]; - if( iLookAhead!=YYNOCODE ){ - pAction = &pState->hashtbl[iLookAhead & pState->mask]; - while( pAction ){ + if( pState->nEntry==0 ){ + return pState->actionDefault; + }else if( iLookAhead!=YYNOCODE ){ + pAction = &pState->hashtbl[iLookAhead % pState->nEntry]; + while( 1 ){ if( pAction->lookahead==iLookAhead ) return pAction->action; - pAction = pAction->next; + if( pAction->next==0 ) return pState->actionDefault; + pAction = &pState->hashtbl[pAction->next-1]; } - }else if( pState->mask!=0 || pState->hashtbl->lookahead!=YYNOCODE ){ + }else if( pState->hashtbl->lookahead!=YYNOCODE ){ return YY_NO_ACTION; } return pState->actionDefault;