577 lines
15 KiB
C
577 lines
15 KiB
C
/***************************************************************
|
|
* pexpr.c
|
|
* Constant expression evaluation
|
|
*
|
|
* Copyright (C) 2008-2009 Gregory Nutt. All rights reserved.
|
|
* Author: Gregory Nutt <spudmonkey@racsa.co.cr>
|
|
*
|
|
* Redistribution and use in source and binary forms, with or without
|
|
* modification, are permitted provided that the following conditions
|
|
* are met:
|
|
*
|
|
* 1. Redistributions of source code must retain the above copyright
|
|
* notice, this list of conditions and the following disclaimer.
|
|
* 2. Redistributions in binary form must reproduce the above copyright
|
|
* notice, this list of conditions and the following disclaimer in
|
|
* the documentation and/or other materials provided with the
|
|
* distribution.
|
|
* 3. Neither the name NuttX nor the names of its contributors may be
|
|
* used to endorse or promote products derived from this software
|
|
* without specific prior written permission.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
|
|
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
|
|
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
|
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
|
|
* COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
|
|
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
|
|
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
|
|
* OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
|
|
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
|
|
* ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
|
* POSSIBILITY OF SUCH DAMAGE.
|
|
*
|
|
***************************************************************/
|
|
|
|
/***************************************************************
|
|
* Included Files
|
|
***************************************************************/
|
|
|
|
#include <sys/types.h>
|
|
#include <stdint.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <math.h>
|
|
|
|
#include "keywords.h"
|
|
#include "pasdefs.h"
|
|
#include "ptdefs.h"
|
|
#include "pedefs.h"
|
|
|
|
#include "keywords.h"
|
|
#include "pas.h"
|
|
#include "pstm.h"
|
|
#include "pexpr.h"
|
|
#include "pfunc.h"
|
|
#include "ptkn.h"
|
|
#include "perr.h"
|
|
|
|
/***************************************************************
|
|
* Pre-processor Definitions
|
|
***************************************************************/
|
|
|
|
#define ADDRESS_DEREFERENCE 0x01
|
|
#define ADDRESS_FACTOR 0x02
|
|
#define INDEXED_FACTOR 0x04
|
|
#define VAR_PARM_FACTOR 0x08
|
|
|
|
#define intTrunc(x) ((x) & (~(sINT_SIZE)))
|
|
|
|
#define isRelationalOperator(t) \
|
|
(((t) == tEQ) || ((t) == tNE) || \
|
|
((t) == tLT) || ((t) == tLE) || \
|
|
((t) == tGT) || ((t) == tGE) || \
|
|
((t) == tIN))
|
|
|
|
#define isRelationalType(t) \
|
|
(((t) == tINT_CONST) || ((t) == tCHAR_CONST) || \
|
|
(((t) == tBOOLEAN_CONST) || ((t) == tREAL_CONST)))
|
|
|
|
#define isAdditiveType(t) \
|
|
(((t) == tINT_CONST) || ((t) == tREAL_CONST))
|
|
|
|
#define isMultiplicativeType(t) \
|
|
(((t) == tINT_CONST) || ((t) == tREAL_CONST))
|
|
|
|
#define isLogicalType(t) \
|
|
(((t) == tINT_CONST) || ((t) == tBOOLEAN_CONST))
|
|
|
|
/***************************************************************
|
|
* Private Type Declarations
|
|
***************************************************************/
|
|
|
|
/***************************************************************
|
|
* Private Function Prototypes
|
|
***************************************************************/
|
|
|
|
static void constantSimpleExpression(void);
|
|
static void constantTerm(void);
|
|
static void constantFactor(void);
|
|
|
|
/***************************************************************
|
|
* Global Variables
|
|
***************************************************************/
|
|
|
|
int constantToken;
|
|
int32_t constantInt;
|
|
double constantReal;
|
|
char *constantStart;
|
|
|
|
/***************************************************************
|
|
* Private Variables
|
|
***************************************************************/
|
|
|
|
/***************************************************************/
|
|
/* Evaluate a simple expression of constant values */
|
|
|
|
void constantExpression(void)
|
|
{
|
|
TRACE(lstFile,"[constantExpression]");
|
|
|
|
/* Get the value of a simple constant expression */
|
|
|
|
constantSimpleExpression();
|
|
|
|
/* Is it followed by a relational operator? */
|
|
|
|
if (isRelationalOperator(token) && isRelationalType(constantToken))
|
|
{
|
|
int simple1 = constantToken;
|
|
int32_t simple1Int = constantInt;
|
|
double simple1Real = constantReal;
|
|
int operator = token;
|
|
|
|
/* Get the second simple expression */
|
|
|
|
constantSimpleExpression();
|
|
if (simple1 != constantToken)
|
|
{
|
|
/* Handle the case where the 1st argument is REAL and the
|
|
* second is INTEGER. */
|
|
|
|
if ((simple1 == tREAL_CONST) && (constantToken == tINT_CONST))
|
|
{
|
|
simple1Real = (double)simple1Int;
|
|
simple1 = tREAL_CONST;
|
|
}
|
|
|
|
/* Handle the case where the 1st argument is Integer and the
|
|
* second is REAL. */
|
|
|
|
else if ((simple1 == tINT_CONST) && (constantToken == tREAL_CONST))
|
|
{
|
|
constantReal = (double)constantInt;
|
|
}
|
|
|
|
/* Allow the case of <scalar type> IN <set type>
|
|
* Otherwise, the two terms must agree in type
|
|
* -- NOT YET implemented.
|
|
*/
|
|
|
|
else
|
|
{
|
|
error(eEXPRTYPE);
|
|
}
|
|
}
|
|
|
|
/* Generate the comparison by type */
|
|
|
|
switch (simple1)
|
|
{
|
|
case tINT_CONST :
|
|
case tCHAR_CONST :
|
|
case tBOOLEAN_CONST :
|
|
switch (operator)
|
|
{
|
|
case tEQ :
|
|
constantInt = (simple1Int == constantInt);
|
|
break;
|
|
case tNE :
|
|
constantInt = (simple1Int != constantInt);
|
|
break;
|
|
case tLT :
|
|
constantInt = (simple1Int < constantInt);
|
|
break;
|
|
case tLE :
|
|
constantInt = (simple1Int <= constantInt);
|
|
break;
|
|
case tGT :
|
|
constantInt = (simple1Int > constantInt);
|
|
break;
|
|
case tGE :
|
|
constantInt = (simple1Int >= constantInt);
|
|
break;
|
|
case tIN :
|
|
/* Not yet */
|
|
default :
|
|
error(eEXPRTYPE);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case tREAL_CONST:
|
|
switch (operator)
|
|
{
|
|
case tEQ :
|
|
constantInt = (simple1Real == constantReal);
|
|
break;
|
|
case tNE :
|
|
constantInt = (simple1Real != constantReal);
|
|
break;
|
|
case tLT :
|
|
constantInt = (simple1Real < constantReal);
|
|
break;
|
|
case tLE :
|
|
constantInt = (simple1Real <= constantReal);
|
|
break;
|
|
case tGT :
|
|
constantInt = (simple1Real > constantReal);
|
|
break;
|
|
case tGE :
|
|
constantInt = (simple1Real >= constantReal);
|
|
break;
|
|
case tIN :
|
|
/* Not yet */
|
|
default :
|
|
error(eEXPRTYPE);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default :
|
|
error(eEXPRTYPE);
|
|
break;
|
|
}
|
|
|
|
/* The type resulting from these operations becomes BOOLEAN */
|
|
|
|
constantToken = tBOOLEAN_CONST;
|
|
}
|
|
}
|
|
|
|
/***************************************************************/
|
|
/* Process Simple Expression */
|
|
|
|
static void constantSimpleExpression(void)
|
|
{
|
|
int16_t unary = ' ';
|
|
int term;
|
|
int32_t termInt;
|
|
double termReal;
|
|
|
|
TRACE(lstFile,"[constantSimpleExpression]");
|
|
|
|
/* FORM: [+|-] <term> [{+|-} <term> [{+|-} <term> [...]]] */
|
|
/* get +/- unary operation */
|
|
|
|
if ((token == '+') || (token == '-'))
|
|
{
|
|
unary = token;
|
|
getToken();
|
|
}
|
|
|
|
/* Process first (non-optional) term and apply unary operation */
|
|
|
|
constantTerm();
|
|
term = constantToken;
|
|
if ((unary != ' ') && !isAdditiveType(term))
|
|
{
|
|
error(eINVSIGNEDCONST);
|
|
}
|
|
else if (unary == '-')
|
|
{
|
|
termInt = -constantInt;
|
|
termReal = -constantReal;
|
|
}
|
|
else
|
|
{
|
|
termInt = constantInt;
|
|
termReal = constantReal;
|
|
}
|
|
|
|
/* Process subsequent (optional) terms and binary operations */
|
|
|
|
for (;;)
|
|
{
|
|
int operator;
|
|
|
|
/* Check for binary operator */
|
|
|
|
if ((((token == '+') || (token == '-')) )&& isAdditiveType(term))
|
|
operator = token;
|
|
else if ((token == tOR) && isLogicalType(term))
|
|
operator = token;
|
|
else
|
|
break;
|
|
|
|
/* Get the 2nd term */
|
|
|
|
getToken();
|
|
constantTerm();
|
|
|
|
/* Before generating the operation, verify that the types match.
|
|
* Perform automatic type conversion from INTEGER to REAL as
|
|
* necessary.
|
|
*/
|
|
|
|
if (term != constantToken)
|
|
{
|
|
/* Handle the case where the 1st argument is REAL and the
|
|
* second is INTEGER. */
|
|
|
|
if ((term == tREAL_CONST) && (constantToken == tINT_CONST))
|
|
{
|
|
constantReal = (double)constantInt;
|
|
constantToken = tREAL_CONST;
|
|
}
|
|
|
|
/* Handle the case where the 1st argument is Integer and the
|
|
* second is REAL. */
|
|
|
|
else if ((term == tINT_CONST) && (constantToken == tREAL_CONST))
|
|
{
|
|
termReal = (double)termInt;
|
|
term = tREAL_CONST;
|
|
}
|
|
|
|
/* Otherwise, the two terms must agree in type */
|
|
|
|
else
|
|
{
|
|
error(eTERMTYPE);
|
|
}
|
|
} /* end if */
|
|
|
|
|
|
/* Perform the selected binary operation */
|
|
|
|
switch (term)
|
|
{
|
|
case tINT_CONST :
|
|
if (operator == '+')
|
|
{
|
|
termInt += constantInt;
|
|
}
|
|
else
|
|
{
|
|
termInt -= constantInt;
|
|
}
|
|
break;
|
|
|
|
case tREAL_CONST :
|
|
if (operator == '+')
|
|
{
|
|
termReal += constantReal;
|
|
}
|
|
else
|
|
{
|
|
termReal -= constantReal;
|
|
}
|
|
break;
|
|
|
|
case tBOOLEAN_CONST :
|
|
termInt |= constantInt;
|
|
break;
|
|
|
|
default :
|
|
error(eEXPRTYPE);
|
|
break;
|
|
}
|
|
}
|
|
|
|
constantToken = term;
|
|
constantInt = termInt;
|
|
constantReal = termReal;
|
|
}
|
|
|
|
/***************************************************************/
|
|
/* Evaluate a TERM */
|
|
|
|
void constantTerm(void)
|
|
{
|
|
int operator;
|
|
int factor;
|
|
int32_t factorInt;
|
|
double factorReal;
|
|
|
|
TRACE(lstFile,"[constantTerm]");
|
|
|
|
/* FORM: <factor> [<operator> <factor>[<operator><factor>[...]]] */
|
|
|
|
constantFactor();
|
|
factor = constantToken;
|
|
factorInt = constantInt;
|
|
factorReal = constantReal;
|
|
for (;;) {
|
|
/* Check for binary operator */
|
|
|
|
if (((token == tMUL) || (token == tMOD)) &&
|
|
(isMultiplicativeType(factor)))
|
|
operator = token;
|
|
else if (((token == tDIV) || (token == tSHL) || (token == tSHR)) &&
|
|
(factor == tINT_CONST))
|
|
operator = token;
|
|
else if ((token == tFDIV) && (factor == tREAL_CONST))
|
|
operator = token;
|
|
#if 0
|
|
else if ((token == tFDIV) && (factor == tINT_CONST))
|
|
{
|
|
factorReal = (double)factorInt;
|
|
factor = tREAL_CONST;
|
|
operator = token;
|
|
}
|
|
#endif
|
|
else if ((token == tAND) && isLogicalType(factor))
|
|
operator = token;
|
|
else
|
|
{
|
|
constantToken = factor;
|
|
constantInt = factorInt;
|
|
constantReal = factorReal;
|
|
break;
|
|
}
|
|
|
|
/* Get the next factor */
|
|
|
|
getToken();
|
|
constantFactor();
|
|
|
|
/* Before generating the operation, verify that the types match.
|
|
* Perform automatic type conversion from INTEGER to REAL as
|
|
* necessary.
|
|
*/
|
|
|
|
if (factor != constantToken)
|
|
{
|
|
/* Handle the case where the 1st argument is REAL and the
|
|
* second is INTEGER. */
|
|
|
|
if ((factor == tREAL_CONST) && (constantToken == tINT_CONST))
|
|
{
|
|
constantReal = (double)constantInt;
|
|
}
|
|
|
|
/* Handle the case where the 1st argument is Integer and the
|
|
* second is REAL. */
|
|
|
|
else if ((factor == tINT_CONST) && (constantToken == tREAL_CONST))
|
|
{
|
|
factorReal = (double)factorInt;
|
|
factor = tREAL_CONST;
|
|
}
|
|
|
|
/* Otherwise, the two factors must agree in type */
|
|
|
|
else
|
|
{
|
|
error(eFACTORTYPE);
|
|
}
|
|
} /* end if */
|
|
|
|
/* Generate code to perform the selected binary operation */
|
|
|
|
switch (operator)
|
|
{
|
|
case tMUL :
|
|
if (factor == tINT_CONST)
|
|
factorInt *= constantInt;
|
|
else if (factor == tREAL_CONST)
|
|
factorReal *= constantReal;
|
|
else
|
|
error(eFACTORTYPE);
|
|
break;
|
|
|
|
case tDIV :
|
|
if (factor == tINT_CONST)
|
|
factorInt /= constantInt;
|
|
else
|
|
error(eFACTORTYPE);
|
|
break;
|
|
|
|
case tFDIV :
|
|
if (factor == tREAL_CONST)
|
|
factorReal /= constantReal;
|
|
else
|
|
error(eFACTORTYPE);
|
|
break;
|
|
|
|
case tMOD :
|
|
if (factor == tINT_CONST)
|
|
factorInt %= constantInt;
|
|
else if (factor == tREAL_CONST)
|
|
factorReal = fmod(factorReal, constantReal);
|
|
else
|
|
error(eFACTORTYPE);
|
|
break;
|
|
|
|
case tAND :
|
|
if ((factor == tINT_CONST) || (factor == tBOOLEAN_CONST))
|
|
factorInt &= constantInt;
|
|
else
|
|
error(eFACTORTYPE);
|
|
break;
|
|
|
|
case tSHL :
|
|
if (factor == tINT_CONST)
|
|
factorInt <<= constantInt;
|
|
else
|
|
error(eFACTORTYPE);
|
|
break;
|
|
|
|
case tSHR :
|
|
if (factor == tINT_CONST)
|
|
factorInt >>= constantInt;
|
|
else
|
|
error(eFACTORTYPE);
|
|
break;
|
|
|
|
}
|
|
}
|
|
}
|
|
|
|
/***************************************************************/
|
|
/* Process a FACTOR */
|
|
|
|
static void constantFactor(void)
|
|
{
|
|
TRACE(lstFile,"[constantFactor]");
|
|
|
|
/* Process by token type */
|
|
|
|
switch (token)
|
|
{
|
|
case tINT_CONST :
|
|
case tBOOLEAN_CONST :
|
|
case tCHAR_CONST :
|
|
constantToken = token;
|
|
constantInt = tknInt;
|
|
getToken();
|
|
break;
|
|
|
|
case tREAL_CONST :
|
|
constantToken = token;
|
|
constantReal = tknReal;
|
|
getToken();
|
|
break;
|
|
|
|
case tSTRING_CONST :
|
|
constantToken = token;
|
|
constantStart = tkn_strt;
|
|
getToken();
|
|
break;
|
|
|
|
/* Highest Priority Operators */
|
|
|
|
case tNOT:
|
|
getToken();
|
|
constantFactor();
|
|
if ((constantToken != tINT_CONST) && (constantToken != tBOOLEAN_CONST))
|
|
error(eFACTORTYPE);
|
|
constantInt = ~constantInt;
|
|
break;
|
|
|
|
/* Built-in function? */
|
|
|
|
case tFUNC:
|
|
builtInFunctionOfConstant();
|
|
break;
|
|
|
|
/* Hmmm... Try the standard functions */
|
|
|
|
default :
|
|
error(eINVFACTOR);
|
|
break;
|
|
}
|
|
}
|