diff --git a/common/libeval/grammar.c b/common/libeval/grammar.c index 5708d02320..cc9eb22186 100644 --- a/common/libeval/grammar.c +++ b/common/libeval/grammar.c @@ -1,64 +1,92 @@ -/* Driver template for the LEMON parser generator. -** The author disclaims copyright to this source code. +/* +** 2000-05-29 +** +** The author disclaims copyright to this source code. In place of +** a legal notice, here is a blessing: +** +** May you do good and not evil. +** May you find forgiveness for yourself and forgive others. +** May you share freely, never taking more than you give. +** +************************************************************************* +** Driver template for the LEMON parser generator. +** +** The "lemon" program processes an LALR(1) input grammar file, then uses +** this template to construct a parser. The "lemon" program inserts text +** at each "%%" line. Also, any "P-a-r-s-e" identifer prefix (without the +** interstitial "-" characters) contained in this template is changed into +** the value of the %name directive from the grammar. Otherwise, the content +** of this template is copied straight through into the generate parser +** source file. +** +** The following is the concatenation of all %include directives from the +** input grammar file: */ -/* First off, code is included that follows the "include" declaration -** in the input grammar file. */ #include <stdio.h> -#line 27 "grammar.lemon" +/************ Begin %include sections from the grammar ************************/ +#line 28 "grammar.lemon" #include <assert.h> -#include <math.h> #include <libeval/numeric_evaluator.h> -#line 13 "grammar.c" -/* Next is all token values, in a form suitable for use by makeheaders. -** This section will be null unless lemon is run with the -m switch. -*/ -/* -** These constants (all generated automatically by the parser generator) -** specify the various kinds of tokens (terminals) that the parser -** understands. -** -** Each symbol here is a terminal symbol in the grammar. -*/ -/* Make sure the INTERFACE macro is defined. -*/ -#ifndef INTERFACE -# define INTERFACE 1 -#endif -/* The next thing included is series of defines which control +#line 32 "grammar.c" +/**************** End of %include directives **********************************/ +/* These constants specify the various numeric values for terminal symbols +** in a format understandable to "makeheaders". This section is blank unless +** "lemon" is run with the "-m" command-line option. +***************** Begin makeheaders token definitions *************************/ +/**************** End makeheaders token definitions ***************************/ + +/* The next sections is a series of control #defines. ** various aspects of the generated parser. -** YYCODETYPE is the data type used for storing terminal -** and nonterminal numbers. "unsigned char" is -** used if there are fewer than 250 terminals -** and nonterminals. "int" is used otherwise. -** YYNOCODE is a number of type YYCODETYPE which corresponds -** to no legal terminal or nonterminal number. This -** number is used to fill in empty slots of the hash -** table. +** YYCODETYPE is the data type used to store the integer codes +** that represent terminal and non-terminal symbols. +** "unsigned char" is used if there are fewer than +** 256 symbols. Larger types otherwise. +** YYNOCODE is a number of type YYCODETYPE that is not used for +** any terminal or nonterminal symbol. ** YYFALLBACK If defined, this indicates that one or more tokens -** have fall-back values which should be used if the -** original value of the token will not parse. -** YYACTIONTYPE is the data type used for storing terminal -** and nonterminal numbers. "unsigned char" is -** used if there are fewer than 250 rules and -** states combined. "int" is used otherwise. -** ParseTOKENTYPE is the data type used for minor tokens given -** directly to the parser from the tokenizer. -** YYMINORTYPE is the data type used for all minor tokens. +** (also known as: "terminal symbols") have fall-back +** values which should be used if the original symbol +** would not parse. This permits keywords to sometimes +** be used as identifiers, for example. +** YYACTIONTYPE is the data type used for "action codes" - numbers +** that indicate what to do in response to the next +** token. +** ParseTOKENTYPE is the data type used for minor type for terminal +** symbols. Background: A "minor type" is a semantic +** value associated with a terminal or non-terminal +** symbols. For example, for an "ID" terminal symbol, +** the minor type might be the name of the identifier. +** Each non-terminal can have a different minor type. +** Terminal symbols all have the same minor type, though. +** This macros defines the minor type for terminal +** symbols. +** YYMINORTYPE is the data type used for all minor types. ** This is typically a union of many types, one of ** which is ParseTOKENTYPE. The entry in the union -** for base tokens is called "yy0". +** for terminal symbols is called "yy0". ** YYSTACKDEPTH is the maximum depth of the parser's stack. If ** zero the stack is dynamically sized using realloc() ** ParseARG_SDECL A static variable declaration for the %extra_argument ** ParseARG_PDECL A parameter declaration for the %extra_argument ** ParseARG_STORE Code to store %extra_argument into yypParser ** ParseARG_FETCH Code to extract %extra_argument from yypParser -** YYNSTATE the combined number of states. -** YYNRULE the number of rules in the grammar ** YYERRORSYMBOL is the code number of the error symbol. If not ** defined, then do no error processing. +** YYNSTATE the combined number of states. +** YYNRULE the number of rules in the grammar +** YY_MAX_SHIFT Maximum value for shift actions +** YY_MIN_SHIFTREDUCE Minimum value for shift-reduce actions +** YY_MAX_SHIFTREDUCE Maximum value for shift-reduce actions +** YY_MIN_REDUCE Maximum value for reduce actions +** YY_ERROR_ACTION The yy_action[] code for syntax error +** YY_ACCEPT_ACTION The yy_action[] code for accept +** YY_NO_ACTION The yy_action[] code for no-op */ +#ifndef INTERFACE +# define INTERFACE 1 +#endif +/************* Begin control #defines *****************************************/ #define YYCODETYPE unsigned char #define YYNOCODE 19 #define YYACTIONTYPE unsigned char @@ -74,11 +102,17 @@ typedef union { #define ParseARG_PDECL , NumericEvaluator* pEval #define ParseARG_FETCH NumericEvaluator* pEval = yypParser->pEval #define ParseARG_STORE yypParser->pEval = pEval -#define YYNSTATE 26 -#define YYNRULE 16 -#define YY_NO_ACTION (YYNSTATE+YYNRULE+2) -#define YY_ACCEPT_ACTION (YYNSTATE+YYNRULE+1) -#define YY_ERROR_ACTION (YYNSTATE+YYNRULE) +#define YYNSTATE 16 +#define YYNRULE 16 +#define YY_MAX_SHIFT 15 +#define YY_MIN_SHIFTREDUCE 26 +#define YY_MAX_SHIFTREDUCE 41 +#define YY_MIN_REDUCE 42 +#define YY_MAX_REDUCE 57 +#define YY_ERROR_ACTION 58 +#define YY_ACCEPT_ACTION 59 +#define YY_NO_ACTION 60 +/************* End control #defines *******************************************/ /* The yyzerominor constant is used to initialize instances of ** YYMINORTYPE objects to zero. */ @@ -105,16 +139,20 @@ static const YYMINORTYPE yyzerominor = { 0 }; ** Suppose the action integer is N. Then the action is determined as ** follows ** -** 0 <= N < YYNSTATE Shift N. That is, push the lookahead +** 0 <= N <= YY_MAX_SHIFT Shift N. That is, push the lookahead ** token onto the stack and goto state N. ** -** YYNSTATE <= N < YYNSTATE+YYNRULE Reduce by rule N-YYNSTATE. +** N between YY_MIN_SHIFTREDUCE Shift to an arbitrary state then +** and YY_MAX_SHIFTREDUCE reduce by rule N-YY_MIN_SHIFTREDUCE. ** -** N == YYNSTATE+YYNRULE A syntax error has occurred. +** N between YY_MIN_REDUCE Reduce by rule N-YY_MIN_REDUCE +** and YY_MAX_REDUCE + +** N == YY_ERROR_ACTION A syntax error has occurred. ** -** N == YYNSTATE+YYNRULE+1 The parser accepts its input. +** N == YY_ACCEPT_ACTION The parser accepts its input. ** -** N == YYNSTATE+YYNRULE+2 No such action. Denotes unused +** N == YY_NO_ACTION No such action. Denotes unused ** slots in the yy_action[] table. ** ** The action table is constructed as a single large table named yy_action[]. @@ -143,45 +181,48 @@ static const YYMINORTYPE yyzerominor = { 0 }; ** yy_reduce_ofst[] For each state, the offset into yy_action for ** shifting non-terminals after a reduce. ** yy_default[] Default action for each state. -*/ -#define YY_ACTTAB_COUNT (47) +** +*********** Begin parsing tables **********************************************/ +#define YY_ACTTAB_COUNT (51) static const YYACTIONTYPE yy_action[] = { - /* 0 */ 22, 8, 6, 3, 4, 23, 26, 15, 8, 6, - /* 10 */ 3, 4, 7, 25, 9, 24, 16, 2, 8, 6, - /* 20 */ 3, 4, 15, 21, 15, 18, 5, 7, 12, 7, - /* 30 */ 24, 16, 2, 16, 2, 14, 43, 1, 17, 9, - /* 40 */ 3, 4, 13, 11, 20, 19, 10, + /* 0 */ 31, 8, 7, 33, 5, 6, 30, 42, 15, 10, + /* 10 */ 15, 11, 4, 12, 4, 40, 29, 32, 2, 32, + /* 20 */ 2, 8, 7, 33, 5, 6, 15, 28, 9, 41, + /* 30 */ 4, 39, 13, 14, 29, 32, 2, 44, 3, 8, + /* 40 */ 7, 33, 5, 6, 59, 1, 27, 9, 33, 5, + /* 50 */ 6, }; static const YYCODETYPE yy_lookahead[] = { - /* 0 */ 4, 5, 6, 7, 8, 9, 0, 1, 5, 6, - /* 10 */ 7, 8, 6, 16, 17, 9, 10, 11, 5, 6, - /* 20 */ 7, 8, 1, 3, 1, 12, 2, 6, 17, 6, - /* 30 */ 9, 10, 11, 10, 11, 17, 14, 15, 16, 17, - /* 40 */ 7, 8, 17, 17, 17, 17, 17, + /* 0 */ 3, 4, 5, 6, 7, 8, 9, 0, 1, 17, + /* 10 */ 1, 17, 5, 17, 5, 17, 9, 10, 11, 10, + /* 20 */ 11, 4, 5, 6, 7, 8, 1, 16, 17, 12, + /* 30 */ 5, 17, 17, 17, 9, 10, 11, 18, 2, 4, + /* 40 */ 5, 6, 7, 8, 14, 15, 16, 17, 6, 7, + /* 50 */ 8, }; -#define YY_SHIFT_USE_DFLT (-5) -#define YY_SHIFT_COUNT (16) -#define YY_SHIFT_MIN (-4) -#define YY_SHIFT_MAX (33) +#define YY_SHIFT_USE_DFLT (-4) +#define YY_SHIFT_COUNT (15) +#define YY_SHIFT_MIN (-3) +#define YY_SHIFT_MAX (42) static const signed char yy_shift_ofst[] = { - /* 0 */ 21, 6, 23, 23, 23, 23, 23, 23, 23, -4, - /* 10 */ 13, 3, 33, 33, 33, 24, 20, + /* 0 */ 25, 7, 9, 9, 9, 9, 9, 9, 9, -3, + /* 10 */ 17, 35, 42, 42, 42, 36, }; -#define YY_REDUCE_USE_DFLT (-4) +#define YY_REDUCE_USE_DFLT (-9) #define YY_REDUCE_COUNT (8) -#define YY_REDUCE_MIN (-3) -#define YY_REDUCE_MAX (29) +#define YY_REDUCE_MIN (-8) +#define YY_REDUCE_MAX (30) static const signed char yy_reduce_ofst[] = { - /* 0 */ 22, -3, 29, 28, 27, 26, 25, 18, 11, + /* 0 */ 30, 11, -8, -6, -4, -2, 14, 15, 16, }; static const YYACTIONTYPE yy_default[] = { - /* 0 */ 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, - /* 10 */ 42, 36, 37, 38, 34, 35, 32, 27, 41, 40, - /* 20 */ 39, 33, 31, 30, 29, 28, + /* 0 */ 58, 58, 58, 58, 58, 58, 58, 58, 58, 58, + /* 10 */ 58, 52, 50, 54, 53, 51, }; +/********** End of lemon-generated parsing tables *****************************/ -/* The next table maps tokens into fallback tokens. If a construct -** like the following: +/* The next table maps tokens (terminal symbols) into fallback tokens. +** If a construct like the following: ** ** %fallback ID X Y Z. ** @@ -189,6 +230,10 @@ static const YYACTIONTYPE yy_default[] = { ** and Z. Whenever one of the tokens X, Y, or Z is input to the parser ** but it does not parse, the type of the token is changed to ID and ** the parse is retried before an error is thrown. +** +** This feature can be used, for example, to cause some keywords in a language +** to revert to identifiers if they keyword does not apply in the context where +** it appears. */ #ifdef YYFALLBACK static const YYCODETYPE yyFallback[] = { @@ -206,9 +251,13 @@ static const YYCODETYPE yyFallback[] = { ** + The semantic value stored at this level of the stack. This is ** the information used by the action routines in the grammar. ** It is sometimes called the "minor" token. +** +** After the "shift" half of a SHIFTREDUCE action, the stateno field +** actually contains the reduce action for the second half of the +** SHIFTREDUCE. */ struct yyStackEntry { - YYACTIONTYPE stateno; /* The state-number */ + YYACTIONTYPE stateno; /* The state-number, or reduce action in SHIFTREDUCE */ YYCODETYPE major; /* The major token value. This is the code ** number for the token at this stack level */ YYMINORTYPE minor; /* The user-supplied minor token value. This @@ -270,8 +319,8 @@ void ParseTrace(FILE *TraceFILE, char *zTracePrompt){ /* For tracing shifts, the names of all terminals and nonterminals ** are required. The following table supplies these names */ static const char *const yyTokenName[] = { - "$", "VAR", "ASSIGN", "UNIT", - "SEMCOL", "PLUS", "MINUS", "DIVIDE", + "$", "VAR", "ASSIGN", "SEMCOL", + "PLUS", "MINUS", "UNIT", "DIVIDE", "MULT", "ENDS", "VALUE", "PARENL", "PARENR", "error", "main", "in", "stmt", "expr", @@ -289,7 +338,7 @@ static const char *const yyRuleName[] = { /* 4 */ "stmt ::= expr ENDS", /* 5 */ "stmt ::= expr SEMCOL", /* 6 */ "expr ::= VALUE", - /* 7 */ "expr ::= VALUE UNIT", + /* 7 */ "expr ::= expr UNIT", /* 8 */ "expr ::= MINUS expr", /* 9 */ "expr ::= VAR", /* 10 */ "expr ::= VAR ASSIGN expr", @@ -325,6 +374,15 @@ static void yyGrowStack(yyParser *p){ } #endif +/* Datatype of the argument to the memory allocated passed as the +** second argument to ParseAlloc() below. This can be changed by +** putting an appropriate #define in the %include section of the input +** grammar. +*/ +#ifndef YYMALLOCARGTYPE +# define YYMALLOCARGTYPE size_t +#endif + /* ** This function allocates a new parser. ** The only argument is a pointer to a function which works like @@ -337,9 +395,9 @@ static void yyGrowStack(yyParser *p){ ** A pointer to a parser. This pointer is used in subsequent calls ** to Parse and ParseFree. */ -void *ParseAlloc(void *(*mallocProc)(size_t)){ +void *ParseAlloc(void *(*mallocProc)(YYMALLOCARGTYPE)){ yyParser *pParser; - pParser = (yyParser*)(*mallocProc)( (size_t)sizeof(yyParser) ); + pParser = (yyParser*)(*mallocProc)( (YYMALLOCARGTYPE)sizeof(yyParser) ); if( pParser ){ pParser->yyidx = -1; #ifdef YYTRACKMAXSTACKDEPTH @@ -354,10 +412,12 @@ void *ParseAlloc(void *(*mallocProc)(size_t)){ return pParser; } -/* The following function deletes the value associated with a -** symbol. The symbol can be either a terminal or nonterminal. -** "yymajor" is the symbol code, and "yypminor" is a pointer to -** the value. +/* The following function deletes the "minor type" or semantic value +** associated with a symbol. The symbol can be either a terminal +** or nonterminal. "yymajor" is the symbol code, and "yypminor" is +** a pointer to the value to be deleted. The code used to do the +** deletions is derived from the %destructor and/or %token_destructor +** directives of the input grammar. */ static void yy_destructor( yyParser *yypParser, /* The parser */ @@ -373,9 +433,11 @@ static void yy_destructor( ** being destroyed before it is finished parsing. ** ** Note: during a reduce, the only symbols destroyed are those - ** which appear on the RHS of the rule, but which are not used + ** which appear on the RHS of the rule, but which are *not* used ** inside the C code. */ +/********* Begin destructor definitions ***************************************/ +/********* End destructor definitions *****************************************/ default: break; /* If no destructor action specified: do nothing */ } } @@ -385,45 +447,37 @@ static void yy_destructor( ** ** If there is a destructor routine associated with the token which ** is popped from the stack, then call it. -** -** Return the major token number for the symbol popped. */ -static int yy_pop_parser_stack(yyParser *pParser){ - YYCODETYPE yymajor; - yyStackEntry *yytos = &pParser->yystack[pParser->yyidx]; - - if( pParser->yyidx<0 ) return 0; +static void yy_pop_parser_stack(yyParser *pParser){ + yyStackEntry *yytos; + assert( pParser->yyidx>=0 ); + yytos = &pParser->yystack[pParser->yyidx--]; #ifndef NDEBUG - if( yyTraceFILE && pParser->yyidx>=0 ){ + if( yyTraceFILE ){ fprintf(yyTraceFILE,"%sPopping %s\n", yyTracePrompt, yyTokenName[yytos->major]); } #endif - yymajor = yytos->major; - yy_destructor(pParser, yymajor, &yytos->minor); - pParser->yyidx--; - return yymajor; + yy_destructor(pParser, yytos->major, &yytos->minor); } /* -** Deallocate and destroy a parser. Destructors are all called for +** Deallocate and destroy a parser. Destructors are called for ** all stack elements before shutting the parser down. ** -** Inputs: -** <ul> -** <li> A pointer to the parser. This should be a pointer -** obtained from ParseAlloc. -** <li> A pointer to a function used to reclaim memory obtained -** from malloc. -** </ul> +** If the YYPARSEFREENEVERNULL macro exists (for example because it +** is defined in a %include section of the input grammar) then it is +** assumed that the input pointer is never NULL. */ void ParseFree( void *p, /* The parser to be deleted */ void (*freeProc)(void*) /* Function used to reclaim memory */ ){ yyParser *pParser = (yyParser*)p; +#ifndef YYPARSEFREENEVERNULL if( pParser==0 ) return; +#endif while( pParser->yyidx>=0 ) yy_pop_parser_stack(pParser); #if YYSTACKDEPTH<=0 free(pParser->yystack); @@ -444,10 +498,6 @@ int ParseStackPeak(void *p){ /* ** Find the appropriate action for a parser given the terminal ** look-ahead token iLookAhead. -** -** If the look-ahead token is YYNOCODE, then check to see if the action is -** independent of the look-ahead. If it is, return the action, otherwise -** return YY_NO_ACTION. */ static int yy_find_shift_action( yyParser *pParser, /* The parser */ @@ -456,63 +506,64 @@ static int yy_find_shift_action( int i; int stateno = pParser->yystack[pParser->yyidx].stateno; - if( stateno>YY_SHIFT_COUNT - || (i = yy_shift_ofst[stateno])==YY_SHIFT_USE_DFLT ){ - return yy_default[stateno]; - } - assert( iLookAhead!=YYNOCODE ); - i += iLookAhead; - if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ - if( iLookAhead>0 ){ + if( stateno>=YY_MIN_REDUCE ) return stateno; + assert( stateno <= YY_SHIFT_COUNT ); + do{ + i = yy_shift_ofst[stateno]; + if( i==YY_SHIFT_USE_DFLT ) return yy_default[stateno]; + assert( iLookAhead!=YYNOCODE ); + i += iLookAhead; + if( i<0 || i>=YY_ACTTAB_COUNT || yy_lookahead[i]!=iLookAhead ){ + if( iLookAhead>0 ){ #ifdef YYFALLBACK - YYCODETYPE iFallback; /* Fallback token */ - if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0]) - && (iFallback = yyFallback[iLookAhead])!=0 ){ -#ifndef NDEBUG - if( yyTraceFILE ){ - fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n", - yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); - } -#endif - return yy_find_shift_action(pParser, iFallback); - } -#endif -#ifdef YYWILDCARD - { - int j = i - iLookAhead + YYWILDCARD; - if( -#if YY_SHIFT_MIN+YYWILDCARD<0 - j>=0 && -#endif -#if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT - j<YY_ACTTAB_COUNT && -#endif - yy_lookahead[j]==YYWILDCARD - ){ + YYCODETYPE iFallback; /* Fallback token */ + if( iLookAhead<sizeof(yyFallback)/sizeof(yyFallback[0]) + && (iFallback = yyFallback[iLookAhead])!=0 ){ #ifndef NDEBUG if( yyTraceFILE ){ - fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n", - yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[YYWILDCARD]); + fprintf(yyTraceFILE, "%sFALLBACK %s => %s\n", + yyTracePrompt, yyTokenName[iLookAhead], yyTokenName[iFallback]); + } +#endif + assert( yyFallback[iFallback]==0 ); /* Fallback loop must terminate */ + iLookAhead = iFallback; + continue; + } +#endif +#ifdef YYWILDCARD + { + int j = i - iLookAhead + YYWILDCARD; + if( +#if YY_SHIFT_MIN+YYWILDCARD<0 + j>=0 && +#endif +#if YY_SHIFT_MAX+YYWILDCARD>=YY_ACTTAB_COUNT + j<YY_ACTTAB_COUNT && +#endif + yy_lookahead[j]==YYWILDCARD + ){ +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE, "%sWILDCARD %s => %s\n", + yyTracePrompt, yyTokenName[iLookAhead], + yyTokenName[YYWILDCARD]); + } +#endif /* NDEBUG */ + return yy_action[j]; } -#endif /* NDEBUG */ - return yy_action[j]; } - } #endif /* YYWILDCARD */ + } + return yy_default[stateno]; + }else{ + return yy_action[i]; } - return yy_default[stateno]; - }else{ - return yy_action[i]; - } + }while(1); } /* ** Find the appropriate action for a parser given the non-terminal ** look-ahead token iLookAhead. -** -** If the look-ahead token is YYNOCODE, then check to see if the action is -** independent of the look-ahead. If it is, return the action, otherwise -** return YY_NO_ACTION. */ static int yy_find_reduce_action( int stateno, /* Current state number */ @@ -555,9 +606,31 @@ static void yyStackOverflow(yyParser *yypParser, YYMINORTYPE *yypMinor){ while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); /* Here code is inserted which will execute if the parser ** stack every overflows */ +/******** Begin %stack_overflow code ******************************************/ +/******** End %stack_overflow code ********************************************/ ParseARG_STORE; /* Suppress warning about unused %extra_argument var */ } +/* +** Print tracing information for a SHIFT action +*/ +#ifndef NDEBUG +static void yyTraceShift(yyParser *yypParser, int yyNewState){ + if( yyTraceFILE ){ + if( yyNewState<YYNSTATE ){ + fprintf(yyTraceFILE,"%sShift '%s', go to state %d\n", + yyTracePrompt,yyTokenName[yypParser->yystack[yypParser->yyidx].major], + yyNewState); + }else{ + fprintf(yyTraceFILE,"%sShift '%s'\n", + yyTracePrompt,yyTokenName[yypParser->yystack[yypParser->yyidx].major]); + } + } +} +#else +# define yyTraceShift(X,Y) +#endif + /* ** Perform a shift action. */ @@ -592,16 +665,7 @@ static void yy_shift( yytos->stateno = (YYACTIONTYPE)yyNewState; yytos->major = (YYCODETYPE)yyMajor; yytos->minor = *yypMinor; -#ifndef NDEBUG - if( yyTraceFILE && yypParser->yyidx>0 ){ - int i; - fprintf(yyTraceFILE,"%sShift %d\n",yyTracePrompt,yyNewState); - fprintf(yyTraceFILE,"%sStack:",yyTracePrompt); - for(i=1; i<=yypParser->yyidx; i++) - fprintf(yyTraceFILE," %s",yyTokenName[yypParser->yystack[i].major]); - fprintf(yyTraceFILE,"\n"); - } -#endif + yyTraceShift(yypParser, yyNewState); } /* The following table contains information about every rule that @@ -649,29 +713,13 @@ static void yy_reduce( #ifndef NDEBUG if( yyTraceFILE && yyruleno>=0 && yyruleno<(int)(sizeof(yyRuleName)/sizeof(yyRuleName[0])) ){ - fprintf(yyTraceFILE, "%sReduce [%s].\n", yyTracePrompt, - yyRuleName[yyruleno]); + yysize = yyRuleInfo[yyruleno].nrhs; + fprintf(yyTraceFILE, "%sReduce [%s], go to state %d.\n", yyTracePrompt, + yyRuleName[yyruleno], yymsp[-yysize].stateno); } #endif /* NDEBUG */ - - /* Silence complaints from purify about yygotominor being uninitialized - ** in some cases when it is copied into the stack after the following - ** switch. yygotominor is uninitialized when a rule reduces that does - ** not set the value of its left-hand side nonterminal. Leaving the - ** value of the nonterminal uninitialized is utterly harmless as long - ** as the value is never used. So really the only thing this code - ** accomplishes is to quieten purify. - ** - ** 2007-01-16: The wireshark project (www.wireshark.org) reports that - ** without this code, their parser segfaults. I'm not sure what there - ** parser is doing to make this happen. This is the second bug report - ** from wireshark this week. Clearly they are stressing Lemon in ways - ** that it has not been previously stressed... (SQLite ticket #2172) - */ - /*memset(&yygotominor, 0, sizeof(yygotominor));*/ yygotominor = yyzerominor; - switch( yyruleno ){ /* Beginning here are the reduction cases. A typical example ** follows: @@ -681,55 +729,56 @@ static void yy_reduce( ** #line <lineno> <thisfile> ** break; */ +/********** Begin reduce actions **********************************************/ case 4: /* stmt ::= expr ENDS */ #line 49 "grammar.lemon" { pEval->parseSetResult(yymsp[-1].minor.yy0.valid ? yymsp[-1].minor.yy0.dValue : NAN); } -#line 688 "grammar.c" +#line 737 "grammar.c" break; case 5: /* stmt ::= expr SEMCOL */ #line 50 "grammar.lemon" { pEval->parseSetResult(NAN); } -#line 693 "grammar.c" +#line 742 "grammar.c" break; case 6: /* expr ::= VALUE */ #line 52 "grammar.lemon" { yygotominor.yy0.dValue = yymsp[0].minor.yy0.dValue; yygotominor.yy0.valid=true; } -#line 698 "grammar.c" +#line 747 "grammar.c" break; - case 7: /* expr ::= VALUE UNIT */ + case 7: /* expr ::= expr UNIT */ #line 53 "grammar.lemon" -{ yygotominor.yy0.dValue = yymsp[-1].minor.yy0.dValue * yymsp[0].minor.yy0.dValue; yygotominor.yy0.valid=true; } -#line 703 "grammar.c" +{ yygotominor.yy0.dValue = yymsp[-1].minor.yy0.dValue * yymsp[0].minor.yy0.dValue; yygotominor.yy0.valid=yymsp[-1].minor.yy0.valid; } +#line 752 "grammar.c" break; case 8: /* expr ::= MINUS expr */ #line 54 "grammar.lemon" { yygotominor.yy0.dValue = -yymsp[0].minor.yy0.dValue; yygotominor.yy0.valid=yymsp[0].minor.yy0.valid; } -#line 708 "grammar.c" +#line 757 "grammar.c" break; case 9: /* expr ::= VAR */ #line 55 "grammar.lemon" { yygotominor.yy0.dValue = pEval->getVar(yymsp[0].minor.yy0.text); yygotominor.yy0.valid=true; } -#line 713 "grammar.c" +#line 762 "grammar.c" break; case 10: /* expr ::= VAR ASSIGN expr */ #line 56 "grammar.lemon" { pEval->setVar(yymsp[-2].minor.yy0.text, yymsp[0].minor.yy0.dValue); yygotominor.yy0.dValue = yymsp[0].minor.yy0.dValue; yygotominor.yy0.valid=false; } -#line 718 "grammar.c" +#line 767 "grammar.c" break; case 11: /* expr ::= expr PLUS expr */ #line 57 "grammar.lemon" { yygotominor.yy0.dValue = yymsp[-2].minor.yy0.dValue + yymsp[0].minor.yy0.dValue; yygotominor.yy0.valid=yymsp[0].minor.yy0.valid; } -#line 723 "grammar.c" +#line 772 "grammar.c" break; case 12: /* expr ::= expr MINUS expr */ #line 58 "grammar.lemon" { yygotominor.yy0.dValue = yymsp[-2].minor.yy0.dValue - yymsp[0].minor.yy0.dValue; yygotominor.yy0.valid=yymsp[0].minor.yy0.valid; } -#line 728 "grammar.c" +#line 777 "grammar.c" break; case 13: /* expr ::= expr MULT expr */ #line 59 "grammar.lemon" { yygotominor.yy0.dValue = yymsp[-2].minor.yy0.dValue * yymsp[0].minor.yy0.dValue; yygotominor.yy0.valid=yymsp[0].minor.yy0.valid; } -#line 733 "grammar.c" +#line 782 "grammar.c" break; case 14: /* expr ::= expr DIVIDE expr */ #line 60 "grammar.lemon" @@ -740,12 +789,12 @@ static void yy_reduce( else pEval->parseError("Div by zero"); yygotominor.yy0.valid=yymsp[0].minor.yy0.valid; } -#line 744 "grammar.c" +#line 793 "grammar.c" break; case 15: /* expr ::= PARENL expr PARENR */ #line 67 "grammar.lemon" { yygotominor.yy0.dValue = yymsp[-1].minor.yy0.dValue; yygotominor.yy0.valid=yymsp[-1].minor.yy0.valid; } -#line 749 "grammar.c" +#line 798 "grammar.c" break; default: /* (0) main ::= in */ yytestcase(yyruleno==0); @@ -753,14 +802,16 @@ static void yy_reduce( /* (2) in ::= in stmt */ yytestcase(yyruleno==2); /* (3) stmt ::= ENDS */ yytestcase(yyruleno==3); break; +/********** End reduce actions ************************************************/ }; + assert( yyruleno>=0 && yyruleno<sizeof(yyRuleInfo)/sizeof(yyRuleInfo[0]) ); yygoto = yyRuleInfo[yyruleno].lhs; yysize = yyRuleInfo[yyruleno].nrhs; yypParser->yyidx -= yysize; yyact = yy_find_reduce_action(yymsp[-yysize].stateno,(YYCODETYPE)yygoto); - if( yyact < YYNSTATE ){ -#ifdef NDEBUG - /* If we are not debugging and the reduce action popped at least + if( yyact <= YY_MAX_SHIFTREDUCE ){ + if( yyact>YY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; + /* If the reduce action popped at least ** one element off the stack, then we can push the new element back ** onto the stack here, and skip the stack overflow test in yy_shift(). ** That gives a significant speed improvement. */ @@ -770,13 +821,12 @@ static void yy_reduce( yymsp->stateno = (YYACTIONTYPE)yyact; yymsp->major = (YYCODETYPE)yygoto; yymsp->minor = yygotominor; - }else -#endif - { + yyTraceShift(yypParser, yyact); + }else{ yy_shift(yypParser,yyact,yygoto,&yygotominor); } }else{ - assert( yyact == YYNSTATE + YYNRULE + 1 ); + assert( yyact == YY_ACCEPT_ACTION ); yy_accept(yypParser); } } @@ -797,6 +847,8 @@ static void yy_parse_failed( while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); /* Here code is inserted which will be executed whenever the ** parser fails */ +/************ Begin %parse_failure code ***************************************/ +/************ End %parse_failure code *****************************************/ ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */ } #endif /* YYNOERRORRECOVERY */ @@ -811,10 +863,12 @@ static void yy_syntax_error( ){ ParseARG_FETCH; #define TOKEN (yyminor.yy0) +/************ Begin %syntax_error code ****************************************/ #line 33 "grammar.lemon" pEval->parseError("Syntax error"); -#line 818 "grammar.c" +#line 871 "grammar.c" +/************ End %syntax_error code ******************************************/ ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */ } @@ -833,10 +887,12 @@ static void yy_accept( while( yypParser->yyidx>=0 ) yy_pop_parser_stack(yypParser); /* Here code is inserted which will be executed whenever the ** parser accepts */ +/*********** Begin %parse_accept code *****************************************/ #line 37 "grammar.lemon" pEval->parseOk(); -#line 840 "grammar.c" +#line 895 "grammar.c" +/*********** End %parse_accept code *******************************************/ ParseARG_STORE; /* Suppress warning about unused %extra_argument variable */ } @@ -867,7 +923,9 @@ void Parse( ){ YYMINORTYPE yyminorunion; int yyact; /* The parser action. */ +#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) int yyendofinput; /* True if we are at the end of input */ +#endif #ifdef YYERRORSYMBOL int yyerrorhit = 0; /* True if yymajor has invoked an error */ #endif @@ -888,26 +946,34 @@ void Parse( yypParser->yyerrcnt = -1; yypParser->yystack[0].stateno = 0; yypParser->yystack[0].major = 0; +#ifndef NDEBUG + if( yyTraceFILE ){ + fprintf(yyTraceFILE,"%sInitialize. Empty stack. State 0\n", + yyTracePrompt); + } +#endif } yyminorunion.yy0 = yyminor; +#if !defined(YYERRORSYMBOL) && !defined(YYNOERRORRECOVERY) yyendofinput = (yymajor==0); +#endif ParseARG_STORE; #ifndef NDEBUG if( yyTraceFILE ){ - fprintf(yyTraceFILE,"%sInput %s\n",yyTracePrompt,yyTokenName[yymajor]); + fprintf(yyTraceFILE,"%sInput '%s'\n",yyTracePrompt,yyTokenName[yymajor]); } #endif do{ yyact = yy_find_shift_action(yypParser,(YYCODETYPE)yymajor); - if( yyact<YYNSTATE ){ - assert( !yyendofinput ); /* Impossible to shift the $ token */ + if( yyact <= YY_MAX_SHIFTREDUCE ){ + if( yyact > YY_MAX_SHIFT ) yyact += YY_MIN_REDUCE - YY_MIN_SHIFTREDUCE; yy_shift(yypParser,yyact,yymajor,&yyminorunion); yypParser->yyerrcnt--; yymajor = YYNOCODE; - }else if( yyact < YYNSTATE + YYNRULE ){ - yy_reduce(yypParser,yyact-YYNSTATE); + }else if( yyact <= YY_MAX_REDUCE ){ + yy_reduce(yypParser,yyact-YY_MIN_REDUCE); }else{ assert( yyact == YY_ERROR_ACTION ); #ifdef YYERRORSYMBOL @@ -957,7 +1023,7 @@ void Parse( yymx != YYERRORSYMBOL && (yyact = yy_find_reduce_action( yypParser->yystack[yypParser->yyidx].stateno, - YYERRORSYMBOL)) >= YYNSTATE + YYERRORSYMBOL)) >= YY_MIN_REDUCE ){ yy_pop_parser_stack(yypParser); } @@ -1007,5 +1073,15 @@ void Parse( #endif } }while( yymajor!=YYNOCODE && yypParser->yyidx>=0 ); +#ifndef NDEBUG + if( yyTraceFILE ){ + int i; + fprintf(yyTraceFILE,"%sReturn. Stack=",yyTracePrompt); + for(i=1; i<=yypParser->yyidx; i++) + fprintf(yyTraceFILE,"%c%s", i==1 ? '[' : ' ', + yyTokenName[yypParser->yystack[i].major]); + fprintf(yyTraceFILE,"]\n"); + } +#endif return; } diff --git a/common/libeval/grammar.lemon b/common/libeval/grammar.lemon index d103eab66d..d172fd9189 100644 --- a/common/libeval/grammar.lemon +++ b/common/libeval/grammar.lemon @@ -20,14 +20,14 @@ %token_type { numEval::TokenType } %extra_argument { NumericEvaluator* pEval } -%nonassoc VAR ASSIGN UNIT SEMCOL. +%nonassoc VAR ASSIGN SEMCOL. %left PLUS MINUS. +%right UNIT. %left DIVIDE MULT. %include { #include <assert.h> -#include <math.h> -#include <libeval/numeric_evaluator.h> +#include "numeric_evaluator.h" } %syntax_error { @@ -50,7 +50,7 @@ stmt ::= expr(A) ENDS. { pEval->parseSetResult(A.valid ? A.dV stmt ::= expr SEMCOL. { pEval->parseSetResult(NAN); } expr(A) ::= VALUE(B). { A.dValue = B.dValue; A.valid=true; } -expr(A) ::= VALUE(B) UNIT(C). { A.dValue = B.dValue * C.dValue; A.valid=true; } +expr(A) ::= expr(B) UNIT(C). { A.dValue = B.dValue * C.dValue; A.valid=B.valid; } expr(A) ::= MINUS expr(B). { A.dValue = -B.dValue; A.valid=B.valid; } expr(A) ::= VAR(B). { A.dValue = pEval->getVar(B.text); A.valid=true; } expr(A) ::= VAR(B) ASSIGN expr(C). { pEval->setVar(B.text, C.dValue); A.dValue = C.dValue; A.valid=false; } diff --git a/common/libeval/numeric_evaluator.cpp b/common/libeval/numeric_evaluator.cpp index 5fa72f9bc0..6945f715bc 100644 --- a/common/libeval/numeric_evaluator.cpp +++ b/common/libeval/numeric_evaluator.cpp @@ -32,6 +32,7 @@ #include <stdlib.h> #include <string.h> #include <ctype.h> +#include <math.h> /* The (generated) lemon parser is written in C. @@ -178,6 +179,7 @@ NumericEvaluator :: newString(const char* s) clear(); auto len = strlen(s); clToken.token = reinterpret_cast<decltype(clToken.token)>(malloc(TokenStat::OutLen+1)); + strcpy(clToken.token, "0"); clToken.inputLen = len; clToken.pos = 0; clToken.input = s; @@ -197,50 +199,55 @@ NumericEvaluator :: getToken() if (clToken.input == nullptr) return retval; if (clToken.pos >= clToken.inputLen) return retval; + auto isDecSep = [&](char ch) -> bool { + if (ch == cClDecSep) return true; + if (cClDecSep == ',' && ch == '.') return true; + return false; + }; + // Lambda: get value as string, store into clToken.token and update current index. - auto extractNumber = [&idx, this]() { + auto extractNumber = [&]() { short sepCount = 0; idx = 0; auto ch = clToken.input[clToken.pos]; do { - if (ch == cClDecSep && sepCount) break; + if (ch == isDecSep(ch) && sepCount) break; clToken.token[idx++] = ch; - if (ch == cClDecSep) sepCount++; + if (isDecSep(ch)) sepCount++; ch = clToken.input[++clToken.pos]; - } while (isdigit(ch) || ch == cClDecSep); + } while (isdigit(ch) || isDecSep(ch)); clToken.token[idx] = 0; + + // Ensure that the systems decimal separator is used + for (int i = strlen(clToken.token); i; i--) if (isDecSep(clToken.token[i-1])) clToken.token[i-1] = cClDecSep; }; - // Lamda: Get unit for current token. Returns Unit::Invalid if token is not a unit. + /* Lamda: Get unit for current token. Returns Unit::Invalid if token is not a unit. + * '"', "in", "th", "mi", "mil" or "mm" + */ auto checkUnit = [this]() -> Unit { - // '"' or "mm" or "mil" - char ch = clToken.input[clToken.pos]; - if (ch == '"' || ch == 'm') { - Unit convertFrom = Unit::Invalid; - if (ch == '"') { - convertFrom = Unit::Inch; - clToken.pos++; - } - else { - // Do not use strcasecmp() as it is not available on all platforms - const char* cptr = &clToken.input[clToken.pos]; - const auto sizeLeft = clToken.inputLen - clToken.pos; - if (sizeLeft >= 2) { - if (tolower(cptr[1]) == 'm' && !isalnum(cptr[2])) { - convertFrom = Unit::Metric; - clToken.pos += 2; - } - else if (sizeLeft >= 3) { - if (tolower(cptr[1]) == 'i' && tolower(cptr[2]) == 'l' && !isalnum(cptr[3])) { - convertFrom = Unit::Mil; - clToken.pos += 3; - } - } - } - } - return convertFrom; + const int sizeLeft = clToken.inputLen - clToken.pos; + Unit convertFrom = Unit::Invalid; + char unit[2] = { 0, 0 }; + for (int i = 0; i < sizeLeft && i < int(sizeof(unit)/sizeof(unit[0])); i++) unit[i] = tolower(clToken.input[clToken.pos+i]); + auto tokcmp = [sizeLeft, unit](const char* s, int len) -> int { + if (len > sizeLeft) return 0; + if (!strncmp(unit, s, len)) return len; + return 0; + }; + int size = 0; + if ((size = tokcmp("\"", 1))) convertFrom = Unit::Inch; + else if ((size = tokcmp("in", 2))) convertFrom = Unit::Inch; + else if ((size = tokcmp("mi", 2))) convertFrom = Unit::Mil; + else if ((size = tokcmp("th", 2))) convertFrom = Unit::Mil; + else if ((size = tokcmp("mm", 2))) convertFrom = Unit::Metric; + clToken.pos += size; + + if (size) { + while (clToken.pos < clToken.inputLen && isalnum(clToken.input[clToken.pos])) clToken.pos++; } - return Unit::Invalid; + + return convertFrom; }; // Start processing of first/next token: Remove whitespace @@ -258,7 +265,7 @@ NumericEvaluator :: getToken() if (ch == 0) { /* End of input */ } - else if (isdigit(ch) || ch == cClDecSep) { // VALUE + else if (isdigit(ch) || isDecSep(ch)) { // VALUE extractNumber(); retval.token = VALUE; retval.value.dValue = atof(clToken.token); @@ -273,22 +280,20 @@ NumericEvaluator :: getToken() retval.token = UNIT; if (eClUnitDefault == Unit::Metric) { - switch (convertFrom) - { - case Unit::Inch : retval.value.dValue = 25.4; break; - case Unit::Mil : retval.value.dValue = 25.4/1000.0; break; - case Unit::Metric : retval.value.dValue = 1.0; break; - case Unit::Invalid : break; + switch (convertFrom) { + case Unit::Inch : retval.value.dValue = 25.4; break; + case Unit::Mil : retval.value.dValue = 25.4/1000.0; break; + case Unit::Metric : retval.value.dValue = 1.0; break; + case Unit::Invalid : break; } } else if (eClUnitDefault == Unit::Inch) { - switch (convertFrom) - { - case Unit::Inch : retval.value.dValue = 1.0; break; - case Unit::Mil : retval.value.dValue = 1.0/1000.0; break; - case Unit::Metric : retval.value.dValue = 1.0/25.4; break; - case Unit::Invalid : break; + switch (convertFrom) { + case Unit::Inch : retval.value.dValue = 1.0; break; + case Unit::Mil : retval.value.dValue = 1.0/1000.0; break; + case Unit::Metric : retval.value.dValue = 1.0/25.4; break; + case Unit::Invalid : break; } } } diff --git a/include/libeval/grammar.h b/include/libeval/grammar.h index 27dddd2848..0017248244 100644 --- a/include/libeval/grammar.h +++ b/include/libeval/grammar.h @@ -1,12 +1,12 @@ -#define VAR 1 -#define ASSIGN 2 -#define UNIT 3 -#define SEMCOL 4 -#define PLUS 5 -#define MINUS 6 -#define DIVIDE 7 -#define MULT 8 -#define ENDS 9 -#define VALUE 10 -#define PARENL 11 -#define PARENR 12 +#define VAR 1 +#define ASSIGN 2 +#define SEMCOL 3 +#define PLUS 4 +#define MINUS 5 +#define UNIT 6 +#define DIVIDE 7 +#define MULT 8 +#define ENDS 9 +#define VALUE 10 +#define PARENL 11 +#define PARENR 12