C++ Samples
The code below parses strings of the form coef*sin(f*val) or coef*cos(f*val) and generates a waveform based on the string.
This code was used in my Frequency Analyzer application.
MathParser.h Sample:
#pragma once
#include <math.h>
#include <vector>
#include <string>
using namespace std;
//From application "FrequencyAnalyzer.sln" (VS 2005) by John Alway
//MathParser.h/cpp:
//Parses equations of the form coef*sin(f*val), or coef*cos(f*val) or just coef;
//or if f = 0, then coef*sin(val) or coef*cos(val)
struct SMathUnit{
float coef;
int SinCos; //0 if neither, 1 if sin(), 2 if cos()
int f; // f=1 and then 2*pi*f is part in
float val; //the value in the sin(val) or cos(val) if there is one
};
class CMathParser {
vector<SMathUnit> m_MathUnit;
public:
CMathParser();
int parseMathString(string &mathString);
void calculate(int timeWave[]);
int strToNumber(string str);
void clear();
~CMathParser();
private:
float calcSin(float coef,float val,float samplePoint);
float calcCos(float coef,float val,float samplePoint);
void replace(string &str,string &str1,string &str2);
int produceMathUnits(string &mathString,vector<string> &mathUnits);
int processProducts(string &mathUnit,SMathUnit &mu);
int putInProperForm(string &mathUnit);
bool isValidChar(char chr,string str);
};
MathParser.cpp Sample:
#include "stdafx.h"
#include "MathParser.h"
extern int g_SampleRate;
CMathParser::CMathParser()
{
m_MathUnit.clear();
}
int CMathParser::parseMathString(string &mathString)
{
vector<string> mathUnits;
SMathUnit mu;
char chr;
int pos, start;
//search for cos, sin and p2f sub strings
//and replace them by c, s and f respectively
if(mathString.length() == 0){
mathString = "Error -- no equation";
return 1;
}
replace(mathString,(string)" ",(string)"");
replace(mathString,(string)"p2f",(string)"f");
replace(mathString,(string)"cos",(string)"c");
replace(mathString,(string)"sin",(string)"s");
replace(mathString,(string)"-c",(string)"-1*c");
replace(mathString,(string)"-s",(string)"-1*s");
//break down elements that are additive (and subtracted)
if(produceMathUnits(mathString,mathUnits))
return 1; //error found
for(int i=0;i<mathUnits.size();i++){
processProducts(mathUnits[i],mu);
m_MathUnit.push_back(mu);
}
mathUnits.clear();
return 0;
}
int CMathParser::putInProperForm(string &mathUnit)
{
int pos, start;
char chr;
//If character before any 'c' is a number, insert an *
pos = mathUnit.find('c',0);
if(pos != string::npos){
if(pos == 0){
replace(mathUnit,(string)"c",(string)"1*c");
}else{
if(isValidChar(mathUnit[pos-1],"0123456789.")){
replace(mathUnit,(string)"c",(string)"*c");
}
}
}
pos = mathUnit.find('s',0);
if(pos != string::npos){
if(pos == 0){
replace(mathUnit,(string)"s",(string)"1*s");
}else{
if(isValidChar(mathUnit[pos-1],"0123456789.")){
replace(mathUnit,(string)"s",(string)"*s");
}
}
}
pos = mathUnit.find('f',0);
if(pos != string::npos){
if(isValidChar(mathUnit[pos+1],"0123456789.")){
replace(mathUnit,(string)"f",(string)"f*");
}
}
return 0;
}
int CMathParser::processProducts(string &mathUnit,SMathUnit &mu)
{
string num;
char chr;
int pos;
mu.SinCos = 0;
mu.coef = 1.0f;
mu.f = 0;
mu.val = 1.0f;
//Put in proper form
putInProperForm(mathUnit);
//Is there an f?
if(mathUnit.find('f',0) != string::npos){
mu.f = 1;
replace(mathUnit,(string)"f",(string)"");
}
//Is there an 's'?
if(mathUnit.find('s',0) != string::npos){
mu.SinCos = 1;
replace(mathUnit,(string)"s",(string)"");
}
//Is there an 'c'?
if(mathUnit.find('c',0) != string::npos){
mu.SinCos = 2;
replace(mathUnit,(string)"c",(string)"");
}
if(mu.SinCos == 0){//only a coefficient
sscanf_s((char *)mathUnit.c_str(),"%f",&mu.coef);
}
else{ //Extract coefficient from front of sin() or cos()
pos = mathUnit.find('*',0);
num = mathUnit.substr(0,pos);
//convert from string to float
sscanf_s((char *)num.c_str(),"%f",&mu.coef);
//Get val part
mathUnit = mathUnit.substr(pos+2);
replace(mathUnit,(string)"*",(string)"");
replace(mathUnit,(string)")",(string)"");
if(mathUnit.length() > 0)
sscanf_s((char *)mathUnit.c_str(),"%f",&mu.val);
}
return 0;
}
int CMathParser::produceMathUnits(string &mathString,vector<string> &mathUnits)
{
string str="";
int pos;
char chr;
bool openParen=false;
int start;
for(int i=0;i < mathString.length();i++){
chr = mathString[i];//.at(i);
if(chr == '-' && i != 0 && openParen == false){
mathUnits.push_back(str);
str = "";
}else if(chr == '+' && i!=0 && openParen == false){
mathUnits.push_back(str);
str = "";
continue;
}
else if(chr == '('){
if(openParen)
{
mathString = "Error -- two opening parentheses in a row";
return 1;
}
openParen = true;
}
else if(chr == ')'){
if(openParen == false)
{
mathString = "Error -- two closing parentheses in a row";
return 1;
}
openParen = false;
}else if(isValidChar(chr,"0123456789.-+*csf") == false){
mathString = "Error -- invalid character found";
return 1;
}
str += chr;
}
mathUnits.push_back(str);
return 0;
}
bool CMathParser::isValidChar(char chr,string str)
{
//string str="0123456789.-+*csf";
int pos = str.find(chr,0);
if(pos == string::npos)//not a valid character
return false;
return true;
}
//replace str1 with str2 in str
void CMathParser::replace(string &str,string &str1,string &str2)
{
int pos;
int start=0;
while(true){
pos = str.find(str1,start);
if(pos == string::npos) break;
str.erase(pos,str1.length());
str.insert(pos,str2,0,str2.length());
start = pos + str2.length();
}
}
void CMathParser::calculate(int timeWave[])
{
SMathUnit mu;
float value, total, samplePoint;
for(int i=0;i<2048;i++){
total = 0.0f;
samplePoint = (float)i/(float)g_SampleRate;
for(int j=0;j<(int)m_MathUnit.size();j++){
mu = m_MathUnit[j];
if(mu.SinCos == 0) { //just a constant
value = mu.coef;
}else if(mu.SinCos == 1) { // a sine function
value = calcSin(mu.coef,mu.val,samplePoint);
}else if(mu.SinCos == 2) { // a cosine function
value = calcCos(mu.coef,mu.val,samplePoint);
}
total += value;
}
timeWave[i] = (int)total;
}
}
float CMathParser::calcSin(float coef,float val,float samplePoint)
{
float result;
val *= 2.0f*3.14159265f;
result = coef*sin(val*samplePoint);
return result;
}
float CMathParser::calcCos(float coef,float val,float samplePoint)
{
float result;
val *= 2.0f*3.14159265f;
result = coef*cos(val*samplePoint);
return result;
}
//Converts str to a number if it is valid,
//otherwise returns val as a 0
int CMathParser::strToNumber(string str)
{ int val=0;
//Remove any spaces
replace(str,(string)" ",(string)"");
//isValidChar
for(int i=0;i<str.length();i++){
if(i == 0 && str[0] == '-'){
continue;
}
else if(isValidChar(str[i],"0123456789") == false){
return val;
}
}
sscanf_s(str.c_str(),"%d",&val);
return val;
}
void CMathParser::clear()
{
m_MathUnit.clear();
}
CMathParser::~CMathParser()
{
m_MathUnit.clear();
}