You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

284 lines
8.4 KiB

/***************************************************************************
mpformula.cpp
-------------------
begin : Sun Nov 18 2001
copyright : (C) 2001 by Kamil
email : kamil@localhost.localdomain
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
***************************************************************************/
#include "mpformula.h"
#include <iostream.h>
#include <qstring.h>
#include <qobject.h>
//
// TODO: i18n
// ? :
// AND OR XOR
// >=, <= ==
//---------------------------------------------------------------------------//
void yyerr( const char *, void *location_info_ptr, void *formula_ptr )
{
MPFormula *formula = (MPFormula *)formula_ptr;
YYLTYPE *location_info = (YYLTYPE *)location_info_ptr;
formula->m_error->setParseError( location_info->first_column, location_info->last_column );
}
//---------------------------------------------------------------------------//
int yylex( MPParserSymbol *symbol_value, void *location_info_ptr, void *formula_ptr )
{
MPFormula *formula = (MPFormula *)formula_ptr;
YYLTYPE *location_info = (YYLTYPE *)location_info_ptr;
QString token;
QChar c = formula->curr_char();
// eat white spaces
while( c.isSpace() ) {
c = formula->m_formula[++formula->m_char];
}
location_info->first_column = formula->m_char;
// number
if ( c.isDigit() || c == '.' ) {
while ( c.isDigit() ) c = formula->apply_char( token );
if ( c == '.' ) c = formula->apply_char( token );
while ( c.isDigit() ) c = formula->apply_char( token );
if ( c == 'e' || c == 'E' ) {
c = formula->apply_char( token );
if ( c == '+' || c == '-' ) {
c = formula->apply_char( token );
while ( c.isDigit() ) c = formula->apply_char( token );
}
}
*symbol_value = token;
location_info->last_column = formula->m_char-1;
return NUMBER;
}
// identifier - function or variable
else if ( c.isLetter() || c == '_' ) {
while ( c.isLetterOrNumber() || c == '_' ) c = formula->apply_char( token );
location_info->last_column = formula->m_char-1;
MPSymbol *result = formula->get_symbol( token.latin1(), NULL, location_info->first_column, location_info->last_column );
if ( result && result->isVariable() ) {
*symbol_value = result;
return VAR;
}
else if ( result ) {
*symbol_value = result;
return FUNC;
}
else {
*symbol_value = token;
return ID;
}
}
else if ( c.isNull() ) {
location_info->last_column = formula->m_char-1;
*symbol_value = MPParserSymbol();
return END;
}
location_info->last_column = formula->m_char;
// make the next character the current one.
formula->m_char++;
*symbol_value = MPParserSymbol();
return c.latin1();
}
//---------------------------------------------------------------------------//
MPFactoryList MPFormula::m_global_symbols;
//---------------------------------------------------------------------------//
MPFormula::MPFormula()
{
m_char = 0;
m_local_symbols = NULL;
m_root_sym = NULL;
}
//---------------------------------------------------------------------------//
MPFormula::~MPFormula()
{
}
//---------------------------------------------------------------------------//
MPSymbol *MPFormula::parse( const QString& formula, MPError& error, MPFactoryList *locals )
{
m_char = 0;
m_error = &error;
m_formula = formula;
m_root_sym = NULL;
m_local_symbols = locals;
yyparse( (void *)this );
if ( m_root_sym ) {
m_root_sym->checkArgs( error );
if ( error.hasError() ) {
delete m_root_sym;
m_root_sym = NULL;
}
}
return m_root_sym;
}
//---------------------------------------------------------------------------//
QChar MPFormula::curr_char() const
{
return m_formula[m_char];
}
//---------------------------------------------------------------------------//
QChar MPFormula::apply_char( QString& append_to )
{
append_to += m_formula[m_char++];
return m_formula[m_char];
}
//---------------------------------------------------------------------------//
void MPFormula::addGlobalSymbols( MPSymbolFactory *factory )
{
m_global_symbols.prepend( factory );
}
//---------------------------------------------------------------------------//
void MPFormula::delGlobalSymbols( MPSymbolFactory *factory )
{
m_global_symbols.remove( factory );
}
//---------------------------------------------------------------------------//
MPSymbol *MPFormula::get_symbol( const QString &identifier, MPSymbolList *args, int colFrom, int colTo )
// sets undefined error in the case of error
{
// no support for unicode yet
const char *id = identifier.latin1();
MPSymbol *result = NULL;
// search through local symbols
if ( m_local_symbols )
for ( MPSymbolFactory *f=m_local_symbols->first(); ( f && !result ); f=m_local_symbols->next() ) {
result = f->create( id, args, colFrom, colTo );
}
// search through global symbols
for ( MPSymbolFactory *f=m_global_symbols.first(); ( f && !result ); f=m_global_symbols.next() ) {
result = f->create( id, args, colFrom, colTo );
}
return result;
}
//--------------------------------------------------------------------------//
//--------------------------------------------------------------------------//
//--------------------------------------------------------------------------//
//--------------------------------------------------------------------------//
//--------------------------------------------------------------------------//
//--------------------------------------------------------------------------//
MPFormulaError::MPFormulaError()
:MPError()
{
}
//--------------------------------------------------------------------------//
MPFormulaError::~MPFormulaError()
{
}
//--------------------------------------------------------------------------//
void MPFormulaError::setWrongNumberOfArguments( int currArgs, int correctArgs, MPSymbol *expression )
{
if ( m_type == None ) {
MPError::setWrongNumberOfArguments( currArgs, correctArgs, expression );
m_msg = QObject::tr(" Wrong number of arguments ( is %1, sould be %2 ). \n" ).arg(currArgs).arg(correctArgs)+standard_message( expression );
}
}
//--------------------------------------------------------------------------//
void MPFormulaError::setNonconformantArgument( int arg_nr, MPSymbol *expression, MPSymbol *sym )
{
if ( m_type == None ) {
MPError::setNonconformantArgument( arg_nr, expression, sym );
m_msg = QObject::tr( "Nonconformat argument %1 '%2' at columns %3-%4\n" )
.arg( arg_nr )
.arg( expression->identifier() )
.arg( expression->colFrom() )
.arg( expression->colTo() )
+standard_message( sym );
}
}
//--------------------------------------------------------------------------//
void MPFormulaError::setError( const char *message, MPSymbol *expression )
{
if ( m_type == None ) {
MPError::setError( message, expression );
m_msg = QObject::tr(message)+"\n"+standard_message( expression );
}
}
//--------------------------------------------------------------------------//
void MPFormulaError::setUndefinedSymbol( const char *symbol, int colFrom, int colTo )
{
if ( m_type == None ) {
MPError::setUndefinedSymbol( symbol, colFrom, colTo );
m_msg = QObject::tr(" Undefined symbol '%1' at columns %2-%3 ." ).arg( symbol ).arg( colFrom ).arg( colTo );
}
}
//--------------------------------------------------------------------------//
void MPFormulaError::setParseError( int colFrom, int colTo )
{
if ( m_type == None ) {
MPError::setParseError( colFrom, colTo );
m_msg = QObject::tr(" Parse error at columns %2-%3 ." ).arg( colFrom ).arg( colTo );
}
}
//--------------------------------------------------------------------------//
QString MPFormulaError::standard_message( MPSymbol *expression )
{
return QObject::tr(" Evaluating '%1' at columns %2-%3 . " )
.arg( expression->identifier() )
.arg( expression->colFrom() )
.arg( expression->colTo() );
}