Click here to Skip to main content
15,891,906 members
Please Sign up or sign in to vote.
2.33/5 (3 votes)
See more:
sample
pi = 3.14 radius = 3 sin( pi / 2 ) + pi * radius ^ 2 + 0x1F - 1100b
it will give error due to the binary and hexadecimal numbers.

What I have tried:

C++
#include "parser.h"


// returns a number from 0 up to, but excluding x
const int getrandom (const int x)
{
	if (x <= 0)
		return 0;

	// r will be between 0 and 1 (but below 1 as we are dividing by RAND_MAX+1)
	double r = static_cast<double> (std::rand () % RAND_MAX) / (static_cast<double> (RAND_MAX) + 1.0);
	return floor (r * x);

}   // end of getrandom

const int roll (const int howmany, const int die)
{
	int count;
	int total = 0;

	for (count = 0; count < howmany; ++count)
		total += getrandom (die) + 1;

	return total;

} // end of roll


// returns true if a x% probability exists
// eg. percent (80) will be true 80% of the time


static int initRandom ()
  {
  srand   (time (NULL));
#ifndef WIN32
  srand48 (time (NULL));
#endif
  return 0;
  }

// initialise random number generator
static int someNumber = initRandom ();



// functions we can call from an expression

double DoInt (double arg)
  {
  return (double) arg;   // drop fractional part
  }
double toInteger(char c)
{
    if (c >= '0' && c <= '9') return c -'0';
    if (c >= 'a' && c <= 'f') return c -'a' + 0xa;
    if (c >= 'A' && c <= 'F') return c -'A' + 0xa;
    double noDigit = 0xf + 1;
    return noDigit;
}
double toHex(char c)
{
    return (std::tolower(c) == 'x' && toInteger(c) <= 0xf);
}
double DoRandom (double arg)
  {
  return getrandom (static_cast <double> (arg));  // random number in range 0 to arg
  }




const double DoIf (const double arg1, const double arg2, const double arg3)
  {
  if (arg1 != 0.0)
    return arg2;
  else
    return arg3;
  }
typedef double (*OneArgFunction)  (double arg);
typedef const double (*TwoArgFunction)  (const double arg1, const double arg2);
typedef const double (*ThreeArgFunction)  (const double arg1, const double arg2, const double arg3);

// maps of function names to functions
static std::map<std::string, OneArgFunction>    OneArgumentFunctions;
static std::map<std::string, TwoArgFunction>    TwoArgumentFunctions;
static std::map<std::string, ThreeArgFunction>  ThreeArgumentFunctions;

// for standard library functions
#define STD_FUNCTION(arg) OneArgumentFunctions [#arg] = arg

static int LoadOneArgumentFunctions ()
  {
  OneArgumentFunctions ["abs"] = fabs;
  STD_FUNCTION (acos);
  STD_FUNCTION (asin);
  STD_FUNCTION (atan);
#ifndef WIN32   // doesn't seem to exist under Visual C++ 6
  STD_FUNCTION (atanh);
#endif
  //STD_FUNCTION (ceil);
  STD_FUNCTION (cos);
  //STD_FUNCTION (cosh);
  STD_FUNCTION (exp);
  STD_FUNCTION (exp);
 // STD_FUNCTION (floor);
  STD_FUNCTION (log);
  STD_FUNCTION (log10);
  STD_FUNCTION (sin);
  //STD_FUNCTION (sinh);
  STD_FUNCTION (sqrt);
  STD_FUNCTION (tan);
  //STD_FUNCTION (tanh);

  OneArgumentFunctions ["int"] = DoInt;
  OneArgumentFunctions ["rand"] = DoRandom;
  OneArgumentFunctions ["rand"] = DoRandom;
 // OneArgumentFunctions ["percent"] = DoPercent;
  return 0;
  } // end of LoadOneArgumentFunctions


static int LoadThreeArgumentFunctions ()
  {
  ThreeArgumentFunctions ["if"]  = DoIf;
  return 0;
  } // end of LoadThreeArgumentFunctions

const Parser::TokenType Parser::GetToken (const bool ignoreSign)
  {
  word_.erase (0, std::string::npos);

  // skip spaces
  while (*pWord_ && isspace (*pWord_))
    ++pWord_;

  pWordStart_ = pWord_;   // remember where word_ starts *now*

  // look out for unterminated statements and things
  if (*pWord_ == 0 &&  // we have EOF
      type_ == END)  // after already detecting it
    throw std::runtime_error ("Unexpected end of expression.");

  unsigned char cFirstCharacter = *pWord_;        // first character in new word_

  if (cFirstCharacter == 0)    // stop at end of file
    {
    word_ = "<end of expression>";
    return type_ = END;
    }

  unsigned char cNextCharacter  = *(pWord_ + 1);  // 2nd character in new word_

  // look for number
  // can be: + or - followed by a decimal point
  // or: + or - followed by a digit
  // or: starting with a digit
  // or: decimal point followed by a digit
  if ((!ignoreSign &&
	   (cFirstCharacter == '+' || cFirstCharacter == '-') &&
	   (isdigit (cNextCharacter) || cNextCharacter == '.')
	   )
	  || isdigit (cFirstCharacter)
	  // allow decimal numbers without a leading 0. e.g. ".5"

	  || (cFirstCharacter == '.' && isdigit (cNextCharacter)) )
	  {
    // skip sign for now
    if ((cFirstCharacter == '+' || cFirstCharacter == '-'))
      pWord_++;
    while (isdigit (*pWord_) || *pWord_ == '.')
      pWord_++;

    // allow for 1.53158e+15
    if (*pWord_ == 'e' || *pWord_ == 'E')
      {
      pWord_++; // skip 'e'
      if ((*pWord_  == '+' || *pWord_  == '-'))
        pWord_++; // skip sign after e
      while (isdigit (*pWord_))  // now digits after e
        pWord_++;
      }

    word_ = std::string (pWordStart_, pWord_ - pWordStart_);

    std::istringstream is (word_);
    // parse std::string into double value
    is >> value_;

    if (is.fail () && !is.eof ())
      throw std::runtime_error ("Bad numeric literal: " + word_);
    return type_ = NUMBER;
    }   // end of number found

  // special test for 2-character sequences: <= >= == !=
  // also +=, -=, /=, *=
  if (cNextCharacter == '=')
    {
    switch (cFirstCharacter)
      {
      // comparisons
      case '=': type_ = EQ;   break;
      case '<': type_ = LE;   break;
      case '>': type_ = GE;   break;
      case '!': type_ = NE;   break;
      // assignments
      case '+': type_ = ASSIGN_ADD;   break;
      case '-': type_ = ASSIGN_SUB;   break;
      case '*': type_ = ASSIGN_MUL;   break;
      case '/': type_ = ASSIGN_DIV;   break;
      // none of the above
      default:  type_ = NONE; break;
      } // end of switch on cFirstCharacter

    if (type_ != NONE)
      {
      word_ = std::string (pWordStart_, 2);
      pWord_ += 2;   // skip both characters
      return type_;
      } // end of found one
    } // end of *=

  switch (cFirstCharacter)
    {
    case '&': if (cNextCharacter == '&')    // &&
                {
                word_ = std::string (pWordStart_, 2);
                pWord_ += 2;   // skip both characters
                return type_ = AND;
                }
              break;
   case '|': if (cNextCharacter == '|')   // ||
                {
                word_ = std::string (pWordStart_, 2);
                pWord_ += 2;   // skip both characters
                return type_ = OR;
                }
              break;
    // single-character symboles
    case '=':
    case '<':
    case '>':
    case '+':
    case '-':
    case '/':
    case '*':
    case '(':
    case ')':
    case ',':
    case '!':
      word_ = std::string (pWordStart_, 1);
      ++pWord_;   // skip it
      return type_ = TokenType (cFirstCharacter);
    } // end of switch on cFirstCharacter

  if (!isalpha (cFirstCharacter))
    {
    if (cFirstCharacter < ' ')
      {
      std::ostringstream s;
      s << "Unexpected character (decimal " << int (cFirstCharacter) << ")";
      throw std::runtime_error (s.str ());
      }
    else
      throw std::runtime_error ("Unexpected character: " + std::string (1, cFirstCharacter));
    }

  // we have a word (starting with A-Z) - pull it out
  while (isalnum (*pWord_) || *pWord_ == '_')
    ++pWord_;

  word_ = std::string (pWordStart_, pWord_ - pWordStart_);
  return type_ = NAME;
  }   // end of Parser::GetToken

// force load of functions at static initialisation time
static int doLoadOneArgumentFunctions = LoadOneArgumentFunctions ();
//static int doLoadTwoArgumentFunctions = LoadTwoArgumentFunctions ();
static int doLoadThreeArgumentFunctions = LoadThreeArgumentFunctions ();

const double Parser::Primary (const bool get)   // primary (base) tokens
  {

  if (get)
    GetToken ();    // one-token lookahead

  switch (type_)
    {
    case NUMBER:
      {
      double v = value_;
      GetToken (true);  // get next one (one-token lookahead)
      return v;
      }

         case 0xf :
        {
        if( type_==0xf){


         GetToken(true);
           return value_;
        }
        }
    case NAME:
      {
      std::string word = word_;
      GetToken (true);
      if (type_ == LHPAREN)
        {
        // might be single-argument function (eg. abs (x) )
        std::map<std::string, OneArgFunction>::const_iterator si;
        si = OneArgumentFunctions.find (word);
        if (si != OneArgumentFunctions.end ())
          {
          double v = Expression (true);   // get argument
          CheckToken (RHPAREN);
          GetToken (true);        // get next one (one-token lookahead)
          return si->second (v);  // evaluate function
          }

        // might be double-argument function (eg. roll (6, 2) )
        std::map<std::string, TwoArgFunction>::const_iterator di;
        di = TwoArgumentFunctions.find (word);
        if (di != TwoArgumentFunctions.end ())
          {
          double v1 = Expression (true);   // get argument 1 (not commalist)
          CheckToken (COMMA);
          double v2 = Expression (true);   // get argument 2 (not commalist)
          CheckToken (RHPAREN);
          GetToken (true);            // get next one (one-token lookahead)
          return di->second (v1, v2); // evaluate function
          }

       // might be double-argument function (eg. roll (6, 2) )
        std::map<std::string, ThreeArgFunction>::const_iterator ti;
        ti = ThreeArgumentFunctions.find (word);
        if (ti != ThreeArgumentFunctions.end ())
          {
          double v1 = Expression (true);   // get argument 1 (not commalist)
          CheckToken (COMMA);
          double v2 = Expression (true);   // get argument 2 (not commalist)
          CheckToken (COMMA);
          double v3 = Expression (true);   // get argument 3 (not commalist)
          CheckToken (RHPAREN);
          GetToken (true);  // get next one (one-token lookahead)
          return ti->second (v1, v2, v3); // evaluate function
          }

        throw std::runtime_error ("Function '" + word + "' not implemented.");
        }

      // not a function? must be a symbol in the symbol table
      double & v = symbols_ [word];  // get REFERENCE to symbol table entry
      // change table entry with expression? (eg. a = 22, or a = 22)
      switch (type_)
        {
        // maybe check for NaN or Inf here (see: isinf, isnan functions)
        case ASSIGN:     v  = Expression (true); break;
        case ASSIGN_ADD: v += Expression (true); break;
        case ASSIGN_SUB: v -= Expression (true); break;
        case ASSIGN_MUL: v *= Expression (true); break;
        case ASSIGN_DIV:
            {
            double d = Expression (true);
            if (d == 0.0)
              throw std::runtime_error ("Divide by zero");
            v /= d;
            break;   // change table entry with expression
            } // end of ASSIGN_DIV
        default: break;   // do nothing for others
        } // end of switch on type_
      return v;               // and return new value
      }

    case MINUS:               // unary minus
      return - Primary (true);

    case NOT:   // unary not
      return (Primary (true) == 0.0) ? 1.0 : 0.0;;

    case LHPAREN:
      {
      double v = CommaList (true);    // inside parens, you could have commas
      CheckToken (RHPAREN);
      GetToken (true);                // eat the )
      return v;
      }

    default:
      throw std::runtime_error ("Unexpected token: " + word_);

    } // end of switch on type

  } // end of Parser::Primary

const double Parser::Term (const bool get)    // multiply and divide
  {
  double left = Primary (get);
  while (true)
    {
    switch (type_)
      {
      case MULTIPLY:
        left *= Primary (true); break;
      case DIVIDE:
          {
          double d = Primary (true);
          if (d == 0.0)
            throw std::runtime_error ("Divide by zero");
          left /= d;
          break;
          }
      default:    return left;
      } // end of switch on type
    }   // end of loop
  } // end of Parser::Term

const double Parser::AddSubtract (const bool get)  // add and subtract
  {
  double left = Term (get);
  while (true)
    {
    switch (type_)
      {
      case PLUS:  left += Term (true); break;
      case MINUS: left -= Term (true); break;
      default:    return left;
      } // end of switch on type
    }   // end of loop
  } // end of Parser::AddSubtract

const double Parser::Comparison (const bool get)  // LT, GT, LE, EQ etc.
  {
  double left = AddSubtract (get);
  while (true)
    {
    switch (type_)
      {
      case LT:  left = left <  AddSubtract (true) ? 1.0 : 0.0; break;
      case GT:  left = left >  AddSubtract (true) ? 1.0 : 0.0; break;
      case LE:  left = left <= AddSubtract (true) ? 1.0 : 0.0; break;
      case GE:  left = left >= AddSubtract (true) ? 1.0 : 0.0; break;
      case EQ:  left = left == AddSubtract (true) ? 1.0 : 0.0; break;
      case NE:  left = left != AddSubtract (true) ? 1.0 : 0.0; break;
           default:    return left;
      } // end of switch on type
    }   // end of loop
  } // end of Parser::Comparison

const double Parser::Expression (const bool get)  // AND and OR
  {
  double left = Comparison (get);
  while (true)
    {
    switch (type_)
      {
      case AND:
            {
            double d = Comparison (true);   // don't want short-circuit evaluation
            left = (left != 0.0) && (d != 0.0);
            }
          break;
      case OR:
            {
            double d = Comparison (true);   // don't want short-circuit evaluation
            left = (left != 0.0) || (d != 0.0);
            }
          break;
      default:    return left;
      } // end of switch on type
    }   // end of loop
  } // end of Parser::Expression

const double Parser::CommaList (const bool get)  // expr1, expr2
  {
  double left = Expression (get);
  while (true)
    {
    switch (type_)
      {
      case COMMA:  left = Expression (true); break; // discard previous value
      default:    return left;
      } // end of switch on type
    }   // end of loop
  } // end of Parser::CommaList

const double Parser::Evaluate ()  // get result
  {
  pWord_    = program_.c_str ();
  type_     = NONE;
  double v = CommaList (true);
  if (type_ != END)
    throw std::runtime_error ("Unexpected text at end of expression: " + std::string (pWordStart_));
  return v;
  }

// change program and evaluate it
const double Parser::Evaluate (const std::string & program)  // get result
  {
  program_  = program;
  return Evaluate ();
  }
Posted
Updated 21-Dec-18 4:07am
v3
Comments
[no name] 20-Dec-18 13:33pm    
Seriously, you like that somebody here will dive into your stuff?

"it will give error due to the binary and hexadecimal numbers.":
1.) Check whether your Parser is ready to recognize hex and binary number.
2.) Use the Debugger to check where the Problem is.
2.a.) Start with a simple Expression like x= 0x1F and check what Problem your Parser has with it.
2.b) Do the same for binary data
Leigh Omar Alpha 20-Dec-18 14:07pm    
okay man. but dont think of me that way.
[no name] 20-Dec-18 15:00pm    
What do you mean with "but dont think of me that way"? Btw. I have no prejudice against you! I only tried to give some Input.

Nobody is going to wade through that much code in search of a vague error like "it will give error due to the binary and hexadecimal numbers."

You need to remember that compiling does not mean your code is right! :laugh:
Think of the development process as writing an email: compiling successfully means that you wrote the email in the right language - English, rather than German for example - not that the email contained the message you wanted to send.

So now you enter the second stage of development (in reality it's the fourth or fifth, but you'll come to the earlier stages later): Testing and Debugging.

Start by looking at what it does do, and how that differs from what you wanted. This is important, because it give you information as to why it's doing it. For example, if a program is intended to let the user enter a number and it doubles it and prints the answer, then if the input / output was like this:
Input   Expected output    Actual output
  1            2                 1
  2            4                 4
  3            6                 9
  4            8                16
Then it's fairly obvious that the problem is with the bit which doubles it - it's not adding itself to itself, or multiplying it by 2, it's multiplying it by itself and returning the square of the input.
So with that, you can look at the code and it's obvious that it's somewhere here:
C#
int Double(int value)
   {
   return value * value;
   }

Once you have an idea what might be going wrong, start using the debugger to find out why. Put a breakpoint on the first line of the method, and run your app. When it reaches the breakpoint, the debugger will stop, and hand control over to you. You can now run your code line-by-line (called "single stepping") and look at (or even change) variable contents as necessary (heck, you can even change the code and try again if you need to).
Think about what each line in the code should do before you execute it, and compare that to what it actually did when you use the "Step over" button to execute each line in turn. Did it do what you expect? If so, move on to the next line.
If not, why not? How does it differ?
Hopefully, that should help you locate which part of that code has a problem, and what the problem is.
This is a skill, and it's one which is well worth developing as it helps you in the real world as well as in development. And like all skills, it only improves by use!
 
Share this answer
 
Quote:
it will give error due to the binary and hexadecimal numbers.

Your code do not behave the way you expect, or you don't understand why !

There is an almost universal solution: Run your code on debugger step by step, inspect variables.
The debugger is here to show you what your code is doing and your task is to compare with what it should do.
There is no magic in the debugger, it don't know what your code is supposed to do, it don't find bugs, it just help you to by showing you what is going on. When the code don't do what is expected, you are close to a bug.
To see what your code is doing: Just set a breakpoint and see your code performing, the debugger allow you to execute lines 1 by 1 and to inspect variables as it execute.

Debugger - Wikipedia, the free encyclopedia[^]

Mastering Debugging in Visual Studio 2010 - A Beginner's Guide[^]
Basic Debugging with Visual Studio 2010 - YouTube[^]

1.11 — Debugging your program (stepping and breakpoints) | Learn C++[^]

The debugger is here to only show you what your code is doing and your task is to compare with what it should do.
 
Share this answer
 
You must write parser which firstly parses the text and than understands its logic correct.

Example: 3 * 2 + 5

first step ist finding the numbers and operators "3", "*", "2", "+" and "5"
than you need to concatenate them with the correct logic:("3", "*", "2") and ( "+" ,"5")
than you can start the operations.
 
Share this answer
 
You Need to extend Parser::GetToken in the way that it recognize Hex and Binary numbers. At the Moment Parser::GetToken does only handle int and double values.

I hope it helps.
 
Share this answer
 
Comments
Leigh Omar Alpha 22-Dec-18 14:53pm    
that is what i am trying to do now . but getting a function to do it bit of a problem for me
[no name] 23-Dec-18 7:45am    
Quote: "but getting a function to do it bit of a problem for me"
I feel with you! I try to dive into the code and help, but I can't promise an answer.
Leigh Omar Alpha 24-Dec-18 10:50am    
i have tried a lot of functions but up till now to no avail.
[no name] 24-Dec-18 11:23am    
For me the big confusion is the parameter ignoreSign) of the method GetToken...From my point of view GetToken should return the sign as a "factor"... but pls. give me some more time.
[Edit: why sign should be returned as factor]
a valid number is also "----+----1". And to resolve this should not be the work of the tokenizer... at least this is my understanding.



The thing needed to solve is:
a.) Token beginning with "0x" and following by a stream of chars '0'-'F' and ended with a whitechar=> it is a hex number
b.) Token contains only '0' and '1' and ends with a 'b' followed by a whitechar => it is a binary

[Edit1]
whitechar in the above is not really correct. It can also be an Operator like "+,-,*,/" and maybe other
Leigh Omar Alpha 6-Jan-19 14:48pm    
now i have solve the problem but i have some many lines but only one can read and the other lines will not be read.
ifstream file ("input.txt");
ofstream file1;
file1.open("output.txt");

freopen("output.txt", "w", stdout);
if(file.is_open()){
string inputLine;
while (std::getline (file, inputLine))
{
if( strncmp( "----", inputLine.c_str(), 4 ) == 0 )


continue;
Parser p(str2);
double value = p.Evaluate ();
std::cout<<"----------------------"<<endl;
std::cout << "Result = " << value << std::endl;

std::cout<<"----------------------"<<endl;

return 0;
}
file.close();
}

}
please can any body help

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900