9
0
Fork 0
nuttx-bb/misc/pascal/pascal/pcexpr.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;
}
}