📄 syntaxanalyzer.cpp
字号:
// Iterate from the first token, lookahead for the keyword
tokenlist_t::iterator Curtoken = this->m_tokenIterator;
for(int i = 0; i < 5; i++)
{
CToken *Token = *Curtoken;
string ch = Token->GetLexeme();
KeyStream << ch;
Curtoken++;
if(Curtoken == this->m_tokenlist->end())
break;
}
getline(KeyStream, Keyword);
// Make sure we're looking at an end statement
if(Keyword != "GOSUB")
{
return false;
}
// Go ahead and soak up the line
CToken *Token = *this->m_tokenIterator;
KeyStream.clear();
while(Token->GetTokenType() == ALPHA)
{
KeyStream << Token->GetLexeme();
this->m_tokenIterator++;
Token = *this->m_tokenIterator;
if(this->m_tokenIterator == this->m_tokenlist->end())
break;
}
getline(KeyStream, Keyword);
// Verify that the command was constructed correctly
if(Keyword != "GOSUB")
{
throw ILLEGAL_INSTRUCTION;
}
// Get a line number from the token stream
int LineNumber = this->sLineNumber();
// Push the next (return) line number into the
// return stack.
CCodeLine *CodeLine = this->GetContext()->GetCode()->GetNext();
// If there is no next code line, then end is not last
if(CodeLine == NULL)
{
throw END_IS_NOT_LAST;
}
this->GetContext()->GetReturnStack()->push(CodeLine->GetLineNumber());
// Branch to the subroutine
this->GetContext()->GetCode()->Find(LineNumber);
this->GetContext()->SetBranching(true);
return true;
}
// Get a RETURN statement from the token stream
bool CSyntaxAnalyzer::sReturnStatement(void)
{
// This statement should occur on its own,
// with no parameters
stringstream KeyStream;
string Keyword;
// Iterate from the first token, lookahead for the keyword
tokenlist_t::iterator Curtoken = this->m_tokenIterator;
for(int i = 0; i < 6; i++)
{
CToken *Token = *Curtoken;
string ch = Token->GetLexeme();
KeyStream << ch;
Curtoken++;
if(Curtoken == this->m_tokenlist->end())
break;
}
getline(KeyStream, Keyword);
// Make sure we're looking at an end statement
if(Keyword != "RETURN")
{
return false;
}
// Go ahead and soak up the line
CToken *Token = *this->m_tokenIterator;
KeyStream.clear();
while(Token->GetTokenType() == ALPHA)
{
KeyStream << Token->GetLexeme();
this->m_tokenIterator++;
Token = *this->m_tokenIterator;
if(this->m_tokenIterator == this->m_tokenlist->end())
break;
}
getline(KeyStream, Keyword);
// Verify that the command was constructed correctly
if(Keyword != "RETURN")
{
throw ILLEGAL_INSTRUCTION;
}
// If so, pop a return value from the return stack
// and set the context to branching
if(this->GetContext()->GetReturnStack()->empty())
{
throw ILLEGAL_RETURN;
}
// Perform the branching
int LineNumber = this->GetContext()->GetReturnStack()->top();
this->GetContext()->GetReturnStack()->pop();
CCodeLine *CodeLine = this->GetContext()->GetCode()->Find(LineNumber);
this->GetContext()->SetBranching(true);
// If the line number isn't found, exception
if(CodeLine == NULL)
{
throw ILLEGAL_LINE_NUMBER;
}
return true;
}
// Get a STOP statement from the token stream
bool CSyntaxAnalyzer::sStopStatement(void)
{
// This statement should occur on its own,
// with no parameters
stringstream KeyStream;
string Keyword;
// Iterate from the first token, lookahead for the keyword
tokenlist_t::iterator Curtoken = this->m_tokenIterator;
for(int i = 0; i < 4; i++)
{
CToken *Token = *Curtoken;
string ch = Token->GetLexeme();
KeyStream << ch;
Curtoken++;
if(Curtoken == this->m_tokenlist->end())
break;
}
getline(KeyStream, Keyword);
// Make sure we're looking at an end statement
if(Keyword != "STOP")
{
return false;
}
// Go ahead and soak up the line
CToken *Token = *this->m_tokenIterator;
KeyStream.clear();
while(Token->GetTokenType() == ALPHA)
{
KeyStream << Token->GetLexeme();
this->m_tokenIterator++;
Token = *this->m_tokenIterator;
if(this->m_tokenIterator == this->m_tokenlist->end())
break;
}
getline(KeyStream, Keyword);
// Verify that the command was constructed correctly
if(Keyword != "STOP")
{
throw ILLEGAL_INSTRUCTION;
}
// If so, stop the program
this->m_Context->SetRunning(false);
return true;
}
// Get an END statement from the input stream
bool CSyntaxAnalyzer::sEndStatement(void)
{
// This statement should occur on its own,
// with no parameters
stringstream KeyStream;
string Keyword;
// Iterate from the first token, lookahead for the keyword
tokenlist_t::iterator Curtoken = this->m_tokenIterator;
for(int i = 0; i < 3; i++)
{
CToken *Token = *Curtoken;
string ch = Token->GetLexeme();
KeyStream << ch;
Curtoken++;
if(Curtoken == this->m_tokenlist->end())
break;
}
getline(KeyStream, Keyword);
// Make sure we're looking at an end statement
if(Keyword != "END")
{
return false;
}
// Go ahead and soak up the line
CToken *Token = *this->m_tokenIterator;
KeyStream.clear();
while(Token->GetTokenType() == ALPHA)
{
KeyStream << Token->GetLexeme();
this->m_tokenIterator++;
Token = *this->m_tokenIterator;
if(this->m_tokenIterator == this->m_tokenlist->end())
break;
}
getline(KeyStream, Keyword);
// Verify that the command was constructed correctly
if(Keyword != "END")
{
throw ILLEGAL_INSTRUCTION;
}
// If so, stop the program
this->m_Context->SetRunning(false);
return true;
}
// Get a variable from the token stream
// Make sure to set up the selection for
// subscripted variables. If the variable
// doesn't exist yet, go ahead and create it.
CSymbol * CSyntaxAnalyzer::sVariable(void)
{
CSymbol *ReturnValue = NULL;
CToken *Token;
bool unsubscripted = true;
// The complications here are that in order
// to tell the difference between a subscripted
// and an unsubscripted variable, we'll need to
// look ahead to see whether there is a
// parenthesis. Fortunately, it won't be too
// far ahead.
tokenlist_t::iterator Curtoken = this->m_tokenIterator;
tokenlist_t::iterator Lasttoken = this->m_tokenIterator;
// Start at the next token in the stream
Lasttoken++;
for(int i = 0; i < 2; i++)
{
Token = *Lasttoken;
if(Token->GetTokenType() == PARENTHESIS &&
Token->GetLexeme() == "(")
{
unsubscripted = false;
}
Lasttoken++;
if(Lasttoken == this->m_tokenlist->end())
break;
}
// Now, get the string that represents the variable
string Variable;
// If the variable is unsubscripted
if(unsubscripted)
{
Variable = this->sUnsubscriptedVariable();
// Check the symbol table for its existence
ReturnValue = this->m_Context->GetSymbolTable()->Find(Variable);
// If it doesn't already exist, add it and default it to 0
if(ReturnValue == NULL)
{
ReturnValue = new CSymbol(Variable, VARIABLE);
ReturnValue->Set(0);
this->m_Context->GetSymbolTable()->Add(ReturnValue);
}
}
// Otherwise, we have to do a lot of additional parsing
else
{
Variable = this->sSubscriptedVariable();
// Tokenize the variable into portions
size_t OpenParen = Variable.find_first_of('(');
size_t CloseParen = Variable.find_last_of(')');
size_t Comma = Variable.find_first_of(',');
string VariableName = Variable.substr(0, OpenParen);
// If there is a comma, it's a matrix. Otherwise,
// it's a vector.
if(Comma != string::npos)
{
int FirstDim = atoi(Variable.substr(OpenParen + 1, Comma - (OpenParen + 1)).c_str());
int SecondDim = atoi(Variable.substr(Comma + 1, CloseParen - (Comma + 1)).c_str());
// Check the symbol for existence
ReturnValue = this->m_Context->GetSymbolTable()->Find(VariableName);
// If it doesn't exist, create it with defaults
if(ReturnValue == NULL && this->m_Dim == false)
{
ReturnValue = new CSymbol(VariableName, MATRIX);
this->m_Context->GetSymbolTable()->Add(ReturnValue);
}
// If we're in a DIM statement, create it with appropriate
// dimensions
else if(ReturnValue == NULL && this->m_Dim == true)
{
ReturnValue = new CSymbol(VariableName);
ReturnValue->CreateMatrix(FirstDim, SecondDim);
this->m_Context->GetSymbolTable()->Add(ReturnValue);
}
// Select the subscript
ReturnValue->SetSubscript(FirstDim, SecondDim);
}
// Select for vector
else
{
int Dim = atoi(Variable.substr(OpenParen + 1, CloseParen - 1).c_str());
// Check for existence
ReturnValue = this->m_Context->GetSymbolTable()->Find(VariableName);
// If it doesn't exist, create it
if(ReturnValue == NULL && this->m_Dim == false)
{
ReturnValue = new CSymbol(VariableName, VECTOR);
this->m_Context->GetSymbolTable()->Add(ReturnValue);
}
else if(ReturnValue == NULL && this->m_Dim == true)
{
ReturnValue = new CSymbol(VariableName);
ReturnValue->CreateVector(Dim);
this->m_Context->GetSymbolTable()->Add(ReturnValue);
}
// Select the subscript
ReturnValue->SetSubscript(Dim);
}
}
// Return the symbol
return ReturnValue;
}
// Get a string from the token list
string CSyntaxAnalyzer::sString(void)
{
// The next token is expected to be a string
CToken *Token = *this->m_tokenIterator;
if(Token->GetTokenType() != STRING)
{
throw INCORRECT_FORMAT;
}
string ReturnValue = Token->GetLexeme();
this->m_tokenIterator++;
// If it passes the test, just return the token lexeme.
return(ReturnValue);
}
// Get a variable list from the token stream
list<CSymbol *> * CSyntaxAnalyzer::sVariableList(void)
{
// Return a list of symbol pointers
list<CSymbol *> *ReturnList = new list<CSymbol *>();
CToken *Token;
// Get at least one variable
ReturnList->push_back(this->sVariable());
// And get a list of optional variables
Token = *this->m_tokenIterator;
while(Token->GetTokenType() == COMMA)
{
this->m_tokenIterator++;
ReturnList->push_back(this->sVariable());
Token = *this->m_tokenIterator;
}
return ReturnList;
}
// Get a list of evaluated expressions
list<float> * CSyntaxAnalyzer::sExpressionList(void)
{
list<float> *ReturnList = new list<float>();
// One non-optional expression in the list
ReturnList->push_back(this->sExpression());
// And any number of optional expressions
CToken *Token = *this->m_tokenIterator;
while(Token->GetTokenType() == COMMA)
{
this->m_tokenIterator++;
// Evaluate the expression and add it to the list
ReturnList->push_back(this->sExpression());
Token = *this->m_tokenIterator;
}
return ReturnList;
}
// Get a label/expression list from the token stream
string CSyntaxAnalyzer::sLabelExpressionList(void)
{
string ReturnValue;
stringstream ListStream;
// At least one LabelExpression
ListStream << this->sLabelExpression() << "\t";
// And a list of optional LabelExpressions
CToken *Token = *this->m_tokenIterator;
while(Token->GetTokenType() == COMMA)
{
this->m_tokenIterator++;
ListStream << this->sLabelExpression() << "\t";
Token = *this->m_tokenIterator;
}
getline(ListStream, ReturnValue);
return ReturnValue;
}
// Get a label/expression from the token stream, return it as a string
string CSyntaxAnalyzer::sLabelExpression(void)
{
stringstream LabelExpressionStream;
string ReturnValue;
CToken *Token = *this->m_tokenIterator;
// This should be either a string, an expression,
// or both, in order.
if(Token->GetTokenType() == STRING)
{
LabelExpressionStream << this->sString();
}
// If we hit either a comma or the end of line,
// no need to process an expression.
// This is a bit of a cheat, but I couldn't find
// a truly elegant way to validate an expression
// in advance of actually calculating it.
Token = *this->m_tokenIterator;
if(Token->GetTokenType() != COMMA &&
Token->GetTokenType() != EOL)
{
LabelExpressionStream << this->sExpression();
}
getline(LabelExpressionStream, ReturnValue);
return ReturnValue;
}
// Evaluate an expression
float CSyntaxAnalyzer::sExpression(void)
{
float ReturnValue = 0;
CToken *Token;
// Get a non-optional signed term
ReturnValue = this->sSignedTerm();
// Now, get optional addition operator
// -> term sequences
Token = *this->m_tokenIterator;
while(Token->GetTokenType() == ADDOP)
{
char Addop = this->sAdditiveOperator();
switch(Addop)
{
case '+':
ReturnValue += this->sFactor();
break;
case '-':
ReturnValue -= this->sFactor();
break;
}
Token = *this->m_tokenIterator;
}
return ReturnValue;
}
// Get a signed term from the token stream
float CSyntaxAnalyzer::sSignedTerm(void)
{
float ReturnValue = 0;
int Multiplier = 1;
CToken *Token = *this->m_tokenIterator;
// Get an optional sign modifier
if(Token->GetTokenType() == ADDOP)
{
char Addop = this->sAdditiveOperator();
switch(Addop)
{
case '+':
// Leave the multiplier be
break;
case '-':
Multiplier = -1;
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -