📄 syntaxanalyzer.cpp
字号:
// Now, get the non-optional term and return it,
// with the appropriate sign.
return(this->sTerm() * Multiplier);
}
// Get a term from the token stream
float CSyntaxAnalyzer::sTerm(void)
{
float ReturnValue = 0;
CToken *Token;
// Get the first factor, non-optional
ReturnValue = this->sFactor();
// Now, get a series of multiplicative
// operator -> factor sequences
Token = *this->m_tokenIterator;
while(Token->GetTokenType() == MULOP)
{
char Mulop = this->sMultiplicativeOperator();
switch(Mulop)
{
case '*':
ReturnValue *= this->sFactor();
break;
case '/':
ReturnValue /= this->sFactor();
break;
default:
throw ILLEGAL_FORMULA;
}
Token = *this->m_tokenIterator;
}
return ReturnValue;
}
// Get a factor from the input stream
float CSyntaxAnalyzer::sFactor(void)
{
float ReturnValue = 0;
CToken *Token = *this->m_tokenIterator;
// First, check to see whether we're looking at
// an identifier.
if(Token->GetTokenType() == ALPHA)
{
ReturnValue = this->sIdentifier();
}
// Second, check to see whether we're looking at
// a constant.
else if(Token->GetTokenType() == DIGIT ||
Token->GetTokenType() == T_DECIMAL)
{
ReturnValue = this->sConstant();
}
// Third, check to see whether it's an expression
else if(Token->GetTokenType() == PARENTHESIS)
{
if(this->sParenthesis() != -1)
{
throw ILLEGAL_FORMULA;
}
ReturnValue = this->sExpression();
if(this->sParenthesis() != 1)
{
throw ILLEGAL_FORMULA;
}
}
else
{
throw ILLEGAL_FORMULA;
}
Token = *this->m_tokenIterator;
// Now, check for an optional exponentiation operator
// and additional factor.
if(Token->GetTokenType() == EXPOP)
{
this->sExponentiationOperator();
ReturnValue = pow(ReturnValue, this->sFactor());
}
return ReturnValue;
}
// Return true and increment token iterator if the next operator is an exponentiation operator
bool CSyntaxAnalyzer::sExponentiationOperator(void)
{
CToken *Token = *this->m_tokenIterator;
// Make sure it's an exponentiation operator
if(Token->GetTokenType() != EXPOP)
{
throw ILLEGAL_FORMULA;
}
this->m_tokenIterator++;
return (bool)(Token->GetLexeme() == "^");
}
// Return with a character for +/- and increment iterator
char CSyntaxAnalyzer::sAdditiveOperator(void)
{
CToken *Token = *this->m_tokenIterator;
// Make sure it's an addop
if(Token->GetTokenType() != ADDOP)
{
throw ILLEGAL_FORMULA;
}
this->m_tokenIterator++;
return Token->GetLexeme().c_str()[0];
}
// Return a mulop and increment iterator
char CSyntaxAnalyzer::sMultiplicativeOperator(void)
{
char ReturnValue = NULL;
CToken *Token = *this->m_tokenIterator;
// Make sure it's a mulop
if(Token->GetTokenType() != MULOP)
{
throw ILLEGAL_FORMULA;
}
this->m_tokenIterator++;
return Token->GetLexeme().c_str()[0];
}
// Return relop and increment iterator, or return NULL
relop_t CSyntaxAnalyzer::sRelationalOperator(void)
{
relop_t ReturnValue;
CToken *Token = *this->m_tokenIterator;
// First, make sure that we're looking at a
// valid relational operator
if(Token->GetTokenType() != RELOP)
{
throw ILLEGAL_RELATION;
}
// Evaluate the relational operator
string Lexeme = Token->GetLexeme();
if(Lexeme == "<")
ReturnValue = LESSER_THAN;
else if(Lexeme == "<=")
ReturnValue = LESSER_THAN_OR_EQUAL;
else if(Lexeme == ">")
ReturnValue = GREATER_THAN;
else if(Lexeme == ">=")
ReturnValue = GREATER_THAN_OR_EQUAL;
else if(Lexeme == "<>")
ReturnValue = NOT_EQUAL;
else if(Lexeme == "=")
ReturnValue = EQUAL;
else
throw ILLEGAL_RELATION;
// Increment the token iterator and return
this->m_tokenIterator++;
return ReturnValue;
}
// Returns -1 for left parenthesis, 1 for right parenthesis, and 0 for no parenthesis
int CSyntaxAnalyzer::sParenthesis(void)
{
int ReturnValue = 0;
CToken *CurToken = *this->m_tokenIterator;
// Next, figure out which one it is
switch(CurToken->GetLexeme().c_str()[0])
{
case '(':
ReturnValue = -1;
break;
case ')':
ReturnValue = 1;
break;
default:
ReturnValue = 0;
}
this->m_tokenIterator++;
return ReturnValue;
}
// Return a constant from the token stream
float CSyntaxAnalyzer::sConstant(void)
{
float ReturnValue = 0;
float Mantissa = 0;
int Exponent = 0;
CToken *Token = *this->m_tokenIterator;
// Technically, any digits preceding a
// decimal point are optional, meaning
// that numbers in the form of
// .12345 are acceptable.
// The grammar states:
// [(Digit)*][.](Digit)*[Exponent]
// However, if we lead off with digits
// and find neither a decimal nor a
// letter 'E', we have to retain the value.
while(Token->GetTokenType() == DIGIT)
{
ReturnValue *= 10;
ReturnValue += this->sDigit();
Token = *this->m_tokenIterator;
}
// Now, see if there's a decimal point, and if
// so, process the mantissa
if(Token->GetTokenType() == T_DECIMAL)
{
// Verify the token
if(Token->GetLexeme() != ".")
{
throw ILLEGAL_CONSTANT;
}
this->m_tokenIterator++;
Token = *this->m_tokenIterator;
// Process the mantissa.
// (must have at least one digit in the mantissa,
// if there is a leading decimal).
// First, grab the mantissa into a string
string strMantissa = "0.";
do
{
strMantissa.append(string(1, (char)this->sDigit() + '0'));
Token = *this->m_tokenIterator;
} while(Token->GetTokenType() == DIGIT);
// Use sscanf to read in the floating point number
sscanf_s(strMantissa.c_str(), "%f", &Mantissa, sizeof(float));
}
// Grab the exponent value, if there is one
if(Token->GetLexeme() == "E")
{
Exponent = this->sExponent();
}
// Return the value plus the mantissa times 10 to the exponent
return((ReturnValue + Mantissa) * pow((float)10, Exponent));
}
// Get an exponent portion of a constant (x.xEx)
int CSyntaxAnalyzer::sExponent(void)
{
int ReturnValue = NULL;
int Multiplier = 1;
CToken *Token = *this->m_tokenIterator;
// First, get the 'E'
if(Token->GetLexeme() != "E")
{
throw ILLEGAL_CONSTANT;
}
this->m_tokenIterator++;
Token = *this->m_tokenIterator;
// Next, get an optional addition operator (+/-)
if(Token->GetTokenType() == ADDOP)
{
char Addop = this->sAdditiveOperator();
switch(Addop)
{
case '+':
// Leave the multiplier alone
break;
case '-':
Multiplier = -1;
break;
default:
throw ILLEGAL_CONSTANT;
}
}
// Finally, get a non-optional sequence of digits,
// concatenate them into an integer, and multiply
// it by the sign multiplier.
do
{
ReturnValue *= 10;
ReturnValue += this->sDigit();
Token = *this->m_tokenIterator;
} while(Token->GetTokenType() == DIGIT);
return(ReturnValue * Multiplier);
}
// Get an identifier from the token stream
float CSyntaxAnalyzer::sIdentifier(void)
{
float ReturnValue = NULL;
CToken *Token = *this->m_tokenIterator;
tokenlist_t::iterator LastChar = this->m_tokenIterator;
// Our options for parsing identifiers
// are somewhat limited, since we need
// to support both functions and variables,
// but we only have single-character tokens.
// To implement this, I've decided to go
// ahead with using a lookahead to determine
// whether the forthcoming string meets
// the qualifications of being a function
// identifier, and if not, default to
// evaluating it as a variable.
// This is inefficient, as it requires
// a lookup in the function table with almost
// every run. Maybe I'll fix this later.
stringstream tempStringStream;
string tempString;
// Look up the next three characters
for(int i = 0; i < 3; i++)
{
CToken *LastToken = *LastChar;
tempStringStream << LastToken->GetLexeme();
LastChar++;
if(LastChar == this->m_tokenlist->end())
break;
}
getline(tempStringStream, tempString);
// See if it matches the DEF FN profile or it
// exists in the function table
if(tempString.substr(0, 2) == "FN" ||
this->m_Context->GetFunctionTable()->Find(tempString))
{
ReturnValue = this->sFunction();
}
else
{
// Otherwise, it's a variable
ReturnValue = this->sVariable()->Get();
}
return ReturnValue;
}
// Get an unsubscripted variable from the token stream
string CSyntaxAnalyzer::sUnsubscriptedVariable(void)
{
string ReturnValue = "";
CToken *Token = *this->m_tokenIterator;
this->m_tokenIterator++;
// An unsubscripted variable takes the form
// ('A'...'Z')[digit]
// First, get the letter (nonoptional)
if(Token->GetTokenType() != ALPHA)
{
throw ILLEGAL_VARIABLE;
}
ReturnValue = Token->GetLexeme();
// Now, fetch the optional digit
Token = *this->m_tokenIterator;
if(Token->GetTokenType() == DIGIT)
{
// Retrieve the token, convert it to a string and
// return it
int Digit = this->sDigit();
ReturnValue.append((size_t)1, (char)Digit + '0');
}
return ReturnValue;
}
// Get a subscripted variable from the token stream
string CSyntaxAnalyzer::sSubscriptedVariable(void)
{
string ReturnValue = "";
stringstream ReturnValueStream;
CToken *Token = *this->m_tokenIterator;
this->m_tokenIterator++;
// A subscripted variable takes the form
// ('A'...'Z') '(' Expression[','Expression] ')'
// Start with the nonoptional letter
if(Token->GetTokenType() != ALPHA)
{
throw ILLEGAL_VARIABLE;
}
ReturnValueStream << Token->GetLexeme();
// Next, get a non-optional left-parenthesis
if(this->sParenthesis() != -1)
{
throw ILLEGAL_VARIABLE;
}
// Now, evaluate a non-optional expression, and take
// its integer value
ReturnValueStream << '(' << (int)this->sExpression();
// At this point, there may be a optional second dimension
// subscript that requires evaluating.
Token = *this->m_tokenIterator;
if(Token->GetTokenType() == COMMA)
{
// If there was a comma, evaluate for another subscript
this->m_tokenIterator++;
ReturnValueStream << ',' << (int)this->sExpression();
}
// And finally, a nonoptional right parenthesis
if(this->sParenthesis() != 1)
{
throw ILLEGAL_VARIABLE;
}
ReturnValueStream << ')';
// Grab the full string and return it
getline(ReturnValueStream, ReturnValue);
return ReturnValue;
}
// Get a single digit from the token stream
int CSyntaxAnalyzer::sDigit(void)
{
CToken *Token = *this->m_tokenIterator;
// If the current token is not a digit,
// throw an exception
if(Token->GetTokenType() != DIGIT)
{
throw ILLEGAL_FORMULA;
}
// Otherwise, increment the iterator and return
// the digit as an integer
int DigitValue = atoi(Token->GetLexeme().c_str());
this->m_tokenIterator++;
return DigitValue;
}
// Evaluate a function from the token stream
float CSyntaxAnalyzer::sFunction(void)
{
float ReturnValue = 0;
string FunctionDef;
// Grab a function identifier, and evaluate
// the expression within its parentheses
string FunctionID = this->sFunctionIdentifier();
// If the next token is not a left parenthesis
if(this->sParenthesis() != -1)
{
throw ILLEGAL_FORMULA;
}
// Evaluate the expression in the parentheses
float ExpValue = this->sExpression();
// If the next token is not a right parenthesis
if(this->sParenthesis() != 1)
{
throw ILLEGAL_FORMULA;
}
// Determine which type of function it is, and run it
CFunction *Function = this->m_Context->GetFunctionTable()->Find(FunctionID);
if(Function == NULL)
{
throw UNDEFINED_FUNCTION;
}
switch(Function->GetBuiltin())
{
case true:
// If it's a builtin, run the builtin
ReturnValue = Function->ExecuteBuiltin(ExpValue);
break;
case false:
// Otherwise, we'll need to lex and parse the
// function definition within the current runtime
// context, but outside of the current syntax
// context. This will necessitate a recursive
// call to CSyntaxAnalyzer
FunctionDef = Function->GetExpression();
Function->GetSymbol()->Set(ExpValue);
ReturnValue = this->Expression(FunctionDef);
break;
}
return ReturnValue;
}
// Get a function identifier from the token stream
string CSyntaxAnalyzer::sFunctionIdentifier(void)
{
string FunctionValue;
// Grab the next three characters from the
// input stream. If any of the next three
// tokens are not characters, throw an
// exception
for(int i = 0; i < 3; i++)
{
CToken *CurToken = *this->m_tokenIterator;
if(CurToken->GetTokenType() != ALPHA)
{
throw UNDEFINED_FUNCTION;
}
FunctionValue += CurToken->GetLexeme();
this->m_tokenIterator++;
}
return FunctionValue;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -