Evaluateur d'expression avec variables indexées

Description

Voici encore un code d'évaluation d'expressions.

Il s'agit d'une classe de base s'occupant de l'analyse de la chaine de caractère et de la création une pile d'instructions qui peut être exécutée rapidement autant de fois que l'ont veut.
Le principal défaut est de ne pratiquement pas avoir de controle de la syntaxe.
Son intéret est d'avoir un minimum de travail à faire pour évaluer des expressions contenant des constantes, des variables, des variables indexées et des fonction.
La classe de base s'appelle ExpressionBase, un exemple de dérivation est la classe ExpressionArithmetique et le code de test/lancement est le fichier Public.cpp.

Source / Exemple :


#include "../StdAfx.h"

#include "memory.h"

#include "ExpressionBase.h"

#define MAX_INSTRUCTION 50

static const char* parentheseFermante[] = { ")", NULL};
static const char* crochetFermant[] = { "]", NULL};
static const char* virguleSeparatrice[] = { ",", NULL};

static const char* LOW_PRIORITY_OPERATORS[] = {NULL};
static char* HIGH_PRIORITY_OPERATORS[] = {NULL};
static char* CONSTANTS_PREFIX = "";
static char* CONSTANTS_CONTENT = "";
static char* VARIABLES[] = {NULL}; // NULL terminated array of strings
static char* INDEXED_VARIABLES[] = {NULL}; // NULL terminated array of strings
static char* UNARY_FUNCTIONS[] = {NULL}; // NULL terminated array of strings
static char* BINARY_FUNCTIONS[] = {NULL}; // NULL terminated array of strings

/**

  • /
Expression::Expression(){ // ---------- instructions = new struct operation *[MAX_INSTRUCTION]; instructionFiller = instructions; instructions[ 0] = NULL; lowPriorityOperators = LOW_PRIORITY_OPERATORS; highPriorityOperators = HIGH_PRIORITY_OPERATORS; constantsPrefix = CONSTANTS_PREFIX; constantsContent = CONSTANTS_CONTENT; variables = VARIABLES; indexedVariables = INDEXED_VARIABLES; unaryFunctions = UNARY_FUNCTIONS; binaryFunctions = BINARY_FUNCTIONS; TraceEnabled = FALSE; } // Constructor /**
  • /
BOOL Expression::analyse( char* expression){ // ------- char* char_index; char* position_operateur; const char** operateur; char* buffer; char** symbol_index; int taille_memoire; BOOL result; while( *expression == ' ') expression++; if( *expression == '\0') return TRUE; result = TRUE; // Trouver une addition ou soustraction de niveau 0 chercheNiveauZero( expression, lowPriorityOperators, position_operateur, operateur); if( *position_operateur != '\0'){
  • position_operateur = '\0';
analyse( expression); analyse( position_operateur + strlen( *operateur)); pushInstruction( LOW_PRIORITY_OPERATOR_CODE_OFFSET + (operateur - lowPriorityOperators), NULL ); }else{ // Plus que des opérateurs prioritaires if( strchr( constantsPrefix, *expression) != NULL){ // Les constantes numériques char_index = expression + 1; while( (*char_index != '\0') && (strchr( constantsContent, *char_index) != NULL)){ char_index++; } taille_memoire = (char_index - expression + 1) * sizeof( char); buffer = (char*)malloc( taille_memoire); strncpy_s( buffer, taille_memoire, expression, (char_index - expression)); buffer[ char_index - expression] = '\0'; pushInstruction( CONSTANT_CODE, buffer); analyse( char_index); }else if( (symbol_index = chercheChaine( expression, variables)) != NULL){ // Les variables pushInstruction( VARIABLES_CODE_OFFSET + (symbol_index - variables), NULL); analyse( expression + strlen( *symbol_index)); }else if( (symbol_index = chercheChaine( expression, indexedVariables)) != NULL){ // Les variables indexées chercheNiveauZero( expression + strlen( *symbol_index) + 1, crochetFermant, position_operateur, operateur);
  • position_operateur = '\0';
analyse( expression + strlen( *symbol_index) + 1); pushInstruction( INDEXED_VARIABLES_CODE_OFFSET + (symbol_index - indexedVariables), NULL); analyse( position_operateur + 1); }else if( *expression == '('){ // Gestion des parentheses imbriquées chercheNiveauZero( expression + 1, parentheseFermante, position_operateur, operateur);
  • position_operateur = '\0';
analyse( expression + 1); analyse( position_operateur + 1); }else if( (symbol_index = chercheChaine( expression, highPriorityOperators)) != NULL){ // Operateurs prioritaires analyse( expression + strlen( *symbol_index)); pushInstruction( HIGH_PRIORITY_OPERATOR_CODE_OFFSET + ( symbol_index - highPriorityOperators), NULL ); }else if( (symbol_index = chercheChaine( expression, unaryFunctions)) != NULL){ // Fonctions avec un seul argument chercheNiveauZero( expression + strlen( *symbol_index) + 1, parentheseFermante, position_operateur, operateur);
  • position_operateur = '\0';
analyse( expression + strlen( *symbol_index) + 1); pushInstruction( UNARY_FUNCTIONS_CODE_OFFSET + (symbol_index - unaryFunctions), NULL); analyse( position_operateur + 1); }else if( (symbol_index = chercheChaine( expression, binaryFunctions)) != NULL){ // Fonctions avec eux arguments chercheNiveauZero( expression + strlen( *symbol_index) + 1, virguleSeparatrice, position_operateur, operateur);
  • position_operateur = '\0';
analyse( expression + strlen( *symbol_index) + 1); expression = position_operateur + 1; chercheNiveauZero( expression, parentheseFermante, position_operateur, operateur);
  • position_operateur = '\0';
analyse( expression); pushInstruction( BINARY_FUNCTIONS_CODE_OFFSET + (symbol_index - binaryFunctions), NULL ); analyse( position_operateur + 1); }else{ result = FALSE; } } return result; } // analyse() /**
  • /
void* Expression::eval(){ // ---- void* stack[ 50]; int stack_size; struct operation ** scan; void* operande_1; void* operande_2; void* resultat; stack_size = 0; scan = instructions; while( *scan != NULL){ if( (*scan)->codeOperation == CONSTANT_CODE){ // Constante resultat = evalConstant( (*scan)->operande); if( resultat == NULL) return FALSE; stack[ stack_size++] = resultat; }else if( (*scan)->codeOperation < HIGH_PRIORITY_OPERATOR_CODE_OFFSET){ // Operateur de faible priorité operande_1 = stack[ stack_size - 2]; operande_2 = stack[ stack_size - 1]; resultat = evalLowPriorityOperator( (*scan)->codeOperation - LOW_PRIORITY_OPERATOR_CODE_OFFSET, operande_1, operande_2); free( stack[ --stack_size]); free( stack[ --stack_size]); if( resultat == NULL) return FALSE; stack[ stack_size++] = resultat; }else if( (*scan)->codeOperation < VARIABLES_CODE_OFFSET){ // Operateur de forte priorité operande_1 = stack[ stack_size - 2]; operande_2 = stack[ stack_size - 1]; resultat = evalHighPriorityOperator( (*scan)->codeOperation - HIGH_PRIORITY_OPERATOR_CODE_OFFSET, operande_1, operande_2); free( stack[ --stack_size]); free( stack[ --stack_size]); if( resultat == NULL) return FALSE; stack[ stack_size++] = resultat; }else if( (*scan)->codeOperation < INDEXED_VARIABLES_CODE_OFFSET){ // Variable resultat = evalVariable( (*scan)->codeOperation - VARIABLES_CODE_OFFSET); if( resultat == NULL) return FALSE; stack[ stack_size++] = resultat; }else if( (*scan)->codeOperation < UNARY_FUNCTIONS_CODE_OFFSET){ // Variables indexées operande_1 = stack[ stack_size - 1]; resultat = evalIndexedVariable( (*scan)->codeOperation - INDEXED_VARIABLES_CODE_OFFSET, operande_1); free( stack[ --stack_size]); if( resultat == NULL) return FALSE; stack[ stack_size++] = resultat; }else if( (*scan)->codeOperation < BINARY_FUNCTIONS_CODE_OFFSET){ // Fonction à un seul argument operande_1 = stack[ stack_size - 1]; resultat = evalUnaryFunction( (*scan)->codeOperation - UNARY_FUNCTIONS_CODE_OFFSET, operande_1); free( stack[ --stack_size]); if( resultat == NULL) return FALSE; stack[ stack_size++] = resultat; }else{ // Fonction à un deux arguments operande_1 = stack[ stack_size - 2]; operande_2 = stack[ stack_size - 1]; resultat = evalBinaryFunction( (*scan)->codeOperation - BINARY_FUNCTIONS_CODE_OFFSET, operande_1, operande_2); free( stack[ --stack_size]); free( stack[ --stack_size]); if( resultat == NULL) return FALSE; stack[ stack_size++] = resultat; } scan++; } return (stack_size == 1) ? stack[ 0] : NULL; } // eval() /**
  • /
void* Expression::evalConstant( void* donnees){ // ------------ return NULL; } // evalConstant() /**
  • /
void* Expression::evalLowPriorityOperator( int code, void* donnees_1, void* donnees_2){ // ----------------------- return NULL; } // evalLowPriorityOperator() /**
  • /
void* Expression::evalHighPriorityOperator( int code, void* donnees_1, void* donnees_2){ // ------------------------ return NULL; } // evalHighPriorityOperator() /**
  • /
void* Expression::evalVariable( int code){ // ------------ return NULL; } // evalVariable() /**
  • /
void* Expression::evalIndexedVariable( int code, void* donnees){ // ------------------- return NULL; } // evalIndexedVariable() /**
  • /
void* Expression::evalUnaryFunction( int code, void* donnees){ // ------------------ return NULL; } // evalUnaryFunction() /**
  • /
void* Expression::evalBinaryFunction( int code, void* donnees_1, void* donnees_2){ // ------------------- return NULL; } // evalBinaryFunction() /**
  • Retourne la position dans la chaine 's' d'un operateur contenu dans 'cibles'.
  • Rend NULL si il n'existe pas, la position dans 's' et la chaine dans 'cibles'
  • /
void Expression::chercheNiveauZero( char* s, const char** cibles, char* &position, const char** &operateur){ // ----------------- int niveau; position = s; do{ if( (*position == '(') || (*position == '[')){ niveau = 0; do{ if( *position == '(') niveau++; if( *position == '[') niveau++; if( *position == ')') niveau--; if( *position == ']') niveau--; position++; }while( (niveau > 0) && (*position != '\0')); }else{ position++; } if( *position != '\0'){ operateur = cibles; while( (*operateur != NULL) && ((**operateur != *position) || (strncmp( *operateur, position, strlen( *operateur)) != 0)) ){ operateur++; } } }while( (*position != '\0') && (*operateur == NULL)); } // chercheNiveauZero() /**
  • Cherche 'liste' la pemière chaine qui est le préfixe de 's'.
  • Rend NULL si rien trouvé, la chaine dans 'liste' sinon.
  • /
char** Expression::chercheChaine( char* s, char** liste){ // ------------- char** scan; scan = liste; while( *scan != NULL){ if( strncmp( s, *scan, strlen( *scan)) == 0) return scan; scan++; } return NULL; } // chercheChaine() /**
  • /
void Expression::pushInstruction( int _code_operation, char* _operande){ // --------------- if( TraceEnabled){ printf( "pushInstruction(): %d, %s\n", _code_operation, _operande); if( (instructionFiller - instructions + 1) >= MAX_INSTRUCTION){ printf( "Instruction stack overflow\n"); } }
  • instructionFiller = new( struct operation);
(*instructionFiller)->codeOperation = _code_operation; (*instructionFiller)->operande = _operande; instructionFiller++;
  • instructionFiller = NULL;
} // pushInstruction() /**
  • /
Expression::~Expression(){ // ---------- struct operation **scan; if( instructions != NULL){ for( scan = instructions; *scan != NULL; scan++){ if( (*scan)->operande != NULL) free( (*scan)->operande); free( *scan); } free( instructions); } } // Destructor // ---------------------------------------------------------------------------

Conclusion :


Je vais utiliser cette classe pour d'autres projet, elle va surement évoluer en bien.

Codes Sources

A voir également

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.