📄 runtime.cpp
字号:
#include "StdAfx.h"
#include "RunTime.h"
CRunTime::CRunTime(void)
: m_Context(new CContext()),
m_LexicalAnalyzer(new CLexicalAnalyzer()),
m_SyntaxAnalyzer(new CSyntaxAnalyzer())
{
this->m_SyntaxAnalyzer->SetContext(this->m_Context);
}
CRunTime::~CRunTime(void)
{
delete this->m_SyntaxAnalyzer;
delete this->m_LexicalAnalyzer;
delete this->m_Context;
}
// Start the BASIC runtime engine
int CRunTime::Start(void)
{
string Command = "";
string uCommand = "";
// Error flag
bool CommandError = false;
// Tokenlist
tokenlist_t *TokenList;
// Initialize the environment
this->cInitialize();
// Main loop
while(1)
{
Command.clear();
uCommand.clear();
// Get a command from the input
cout << "? ";
getline(cin, Command);
// Convert the command to uppercase
char *cmd = (char *)Command.c_str();
char ch;
while(ch = *(cmd++))
{
uCommand.append(1, toupper(ch));
}
// Check to see whether one of the runtime commands
// has been issued
if(uCommand.length() == 0)
{
continue;
}
else if(uCommand.substr(0, 4) == "LIST")
{
// Create a string iterator and skip over the
// first four characters
string::iterator strIterator = uCommand.begin();
for(int i = 0; i < 4; i++)
{
strIterator++;
}
// We need to check here whether there was a parameter
// to this command, in the form of
// LIST--20
if(strIterator == uCommand.end())
{
// If not, go ahead and list full source
this->cList();
}
else
{
string sLineNumber = "";
int LineNumber = 0;
// Otherwise, get the two dashes
for(int i = 0; i < 2; i++)
{
if(*strIterator != '-')
CommandError = true;
strIterator++;
}
// And get the number
sLineNumber.assign(strIterator, uCommand.end());
// Convert the number to an integer
LineNumber = atoi(sLineNumber.c_str());
// And list the source
if(CommandError)
{
cout << "ILLEGAL COMMAND" << endl;
}
else
{
this->cList(LineNumber);
}
}
}
else if(uCommand == "SAVE")
{
this->cSave();
}
else if(uCommand == "UNSAVE")
{
this->cUnSave();
}
else if(uCommand == "CATALOG")
{
this->cCatalog();
}
else if(uCommand == "NEW")
{
this->cNew();
}
else if(uCommand == "OLD")
{
this->cOld();
}
else if(uCommand == "SCRATCH")
{
this->cScratch();
}
else if(uCommand == "RENAME")
{
this->cRename();
}
else if(uCommand == "RUN")
{
this->cRun();
}
else if(uCommand == "HELP")
{
this->cHelp();
}
else if(uCommand == "QUIT")
{
return 0;
}
else
{
// If anything other than one of the above
// commands is typed, throw it at the parser
// and see what comes up.
TokenList = this->m_LexicalAnalyzer->Analyze(Command);
this->m_SyntaxAnalyzer->SetTokenList(TokenList);
try
{
this->m_SyntaxAnalyzer->Analyze();
}
catch(int error)
{
this->cError(error);
this->m_Context->SetRunning(false);
}
}
}
return 0;
}
// Print out the entire source listing.
void CRunTime::cList()
{
CCodeLine *CodeLine;
this->m_Context->GetCode()->Reset();
while(CodeLine = this->m_Context->GetCode()->GetNext())
{
cout << CodeLine->GetLineNumber() << " " << CodeLine->GetCode() << endl;
}
}
// Print out the source listing at a given line.
void CRunTime::cList(int LineNumber = 0)
{
CCodeLine *CodeLine;
CodeLine = this->m_Context->GetCode()->Find(LineNumber);
if(CodeLine == NULL)
{
cout << "ILLEGAL LINE NUMBER" << endl;
}
else
{
cout << CodeLine->GetLineNumber() << " " << CodeLine->GetCode() << endl;
}
}
// Save a file to disk
void CRunTime::cSave(void)
{
string saveName = this->m_Name + ".bas";
ofstream saveFile(saveName.c_str(), ios::out, ios::trunc);
// This does basically the same thing as cList, but to a file stream
CCodeLine *CodeLine;
this->m_Context->GetCode()->Reset();
while(CodeLine = this->m_Context->GetCode()->GetNext())
{
saveFile << CodeLine->GetLineNumber() << " " << CodeLine->GetCode() << endl;
}
saveFile.close();
cout << "SAVED PROBLEM " << this->m_Name << endl;
}
// Unsave (delete) the current program from disk
void CRunTime::cUnSave(void)
{
string unSaveName = this->m_Name + ".bas";
remove(unSaveName.c_str());
cout << "REMOVED PROBLEM " << this->m_Name << endl;
}
// Display the catalog of source files
void CRunTime::cCatalog(void)
{
// Windows directory structure data
WIN32_FIND_DATA CatalogFileData;
HANDLE hFind = INVALID_HANDLE_VALUE;
// Catalog data
list<wstring> Catalog;
// Find the first file
hFind = FindFirstFileEx(L"*.bas", FindExInfoStandard, &CatalogFileData,
FindExSearchNameMatch, NULL, 0);
if(hFind == INVALID_HANDLE_VALUE)
{
cout << "NO SAVED PROBLEMS" << endl;
return;
}
else
{
// Remove the file extension
wstring Fullname(CatalogFileData.cFileName);
wstring Basename; // Base filename, without extension
size_t Extension = Fullname.find_last_of('.');
Basename = Fullname.substr(0, Extension);
// If we get here, at least one file was found
Catalog.push_back(Basename);
// Now, search for any remaining files
while(FindNextFile(hFind, &CatalogFileData))
{
Fullname = CatalogFileData.cFileName;
Basename; // Base filename, without extension
Extension = Fullname.find_last_of('.');
Basename = Fullname.substr(0, Extension);
Catalog.push_back(Basename);
}
}
// At this point, we have a full catalog of files.
// Print it out.
list<wstring>::iterator catIterator = Catalog.begin();
while(catIterator != Catalog.end())
{
wstring CurrentFile = *catIterator;
wcout << CurrentFile << endl;
catIterator++;
}
}
// Creates a new program
void CRunTime::cNew(void)
{
// First, unload all current data
delete this->m_SyntaxAnalyzer;
delete this->m_LexicalAnalyzer;
delete this->m_Context;
this->m_Name.clear();
// Create a new context
this->m_Context = new CContext();
this->m_SyntaxAnalyzer = new CSyntaxAnalyzer();
this->m_SyntaxAnalyzer->SetContext(this->m_Context);
this->m_LexicalAnalyzer = new CLexicalAnalyzer();
// Make sure the user enters a proper name
while(this->m_Name.empty())
{
cout << "NEW PROBLEM NAME--";
cin >> this->m_Name;
}
// Clear out the newline from the buffer
if(cin.peek())
{
cin.ignore(1);
}
}
// Read an existing source file
void CRunTime::cOld(void)
{
string Filename;
ifstream InputFile;
// First, unload all current data
delete this->m_LexicalAnalyzer;
delete this->m_SyntaxAnalyzer;
delete this->m_Context;
this->m_Name.clear();
// Create a new context
this->m_Context = new CContext();
this->m_SyntaxAnalyzer = new CSyntaxAnalyzer();
this->m_SyntaxAnalyzer->SetContext(this->m_Context);
this->m_LexicalAnalyzer = new CLexicalAnalyzer();
do
{
InputFile.clear();
this->m_Name.clear();
// Make sure the user enters a proper name
while(this->m_Name.empty())
{
this->cCatalog();
cout << "OLD PROBLEM NAME--";
cin >> this->m_Name;
}
// Clear out the newline from the buffer
if(cin.peek())
{
cin.ignore(1);
}
// Build the filename
Filename = this->m_Name + ".bas";
InputFile.open(Filename.c_str(), ios::in);
} while(InputFile.fail());
// Read the files contents, and parse each line,
// which should automatically load the codelist
string InputLine;
while(!InputFile.eof())
{
getline(InputFile, InputLine);
if(InputLine.length() < 1)
continue;
// Parse the input line
tokenlist_t *TokenList = this->m_LexicalAnalyzer->Analyze(InputLine);
this->m_SyntaxAnalyzer->SetTokenList(TokenList);
this->m_SyntaxAnalyzer->Analyze();
}
InputFile.close();
}
// Scratch the existing contents of the current program, creating a clean slate
void CRunTime::cScratch(void)
{
// First, unload all current data
delete this->m_SyntaxAnalyzer;
delete this->m_LexicalAnalyzer;
delete this->m_Context;
// Create a new context
this->m_Context = new CContext();
this->m_SyntaxAnalyzer = new CSyntaxAnalyzer();
this->m_SyntaxAnalyzer->SetContext(this->m_Context);
this->m_LexicalAnalyzer = new CLexicalAnalyzer();
}
// Rename the program
void CRunTime::cRename(void)
{
this->m_Name.clear();
// Make sure the user enters a proper name
while(this->m_Name.empty())
{
cout << "NEW PROBLEM NAME--";
cin >> this->m_Name;
}
// Clear out the newline from the buffer
if(cin.peek())
{
cin.ignore(1);
}
}
// Run the startup process
void CRunTime::cInitialize(void)
{
string Command = "";
string uCommand = "";
// Error flag
bool CommandError = true;
// Output some header info
cout << "HELLO" << endl;
cout << "SYSTEM--BASIC" << endl;
// Ask the user for new or old until the entry is correct
while(CommandError)
{
Command.clear();
uCommand.clear();
// Ask the user whether to create or load
cout << "NEW OR OLD--";
getline(cin, Command);
// Convert the command to uppercase
char *cmd = (char *)Command.c_str();
char ch;
while(ch = *(cmd++))
{
uCommand.append(1, toupper(ch));
}
if(uCommand == "NEW")
{
this->cNew();
CommandError = false;
}
else if(uCommand == "OLD")
{
this->cOld();
CommandError = false;
}
}
// And we're ready.
cout << "READY." << endl;
}
// Run the code listing
void CRunTime::cRun(void)
{
// Current line of code
CCodeLine *CurrentLine;
// Maintain a token list
tokenlist_t *TokenList;
// Reset the code list to the beginning
this->m_Context->GetCode()->Reset();
// Set the running context
this->m_Context->SetRunning(true);
// Execute the program
while(this->m_Context->GetRunning())
{
// Fetch the next line of code
CurrentLine = this->m_Context->GetCode()->GetNext();
// If the current line is null, then there wasn't an end statement
if(CurrentLine == NULL)
{
this->cError(NO_END_INSTRUCTION);
break;
}
// Lex the line
TokenList = this->m_LexicalAnalyzer->Analyze(CurrentLine->GetCode());
// Parse and execute
this->m_SyntaxAnalyzer->SetTokenList(TokenList);
try
{
this->m_SyntaxAnalyzer->Analyze();
}
catch(int error)
{
this->cError(error);
this->m_Context->SetRunning(false);
}
}
// Reset the code list
this->m_Context->GetCode()->Reset();
}
// Catch exceptions and print out the corresponding error message.
void CRunTime::cError(int Error)
{
string errStr;
switch(Error)
{
case DIMENSION_TOO_LARGE:
errStr = "DIMENSION TOO LARGE";
break;
case ILLEGAL_CONSTANT:
errStr = "ILLEGAL CONSTANT";
break;
case ILLEGAL_FORMULA:
errStr = "ILLEGAL FORMULA";
break;
case ILLEGAL_RELATION:
errStr = "ILLEGAL RELATION";
break;
case ILLEGAL_LINE_NUMBER:
errStr = "ILLEGAL LINE NUMBER";
break;
case ILLEGAL_INSTRUCTION:
errStr = "ILLEGAL INSTRUCTION";
break;
case ILLEGAL_VARIABLE:
errStr = "ILLEGAL VARIABLE";
break;
case INCORRECT_FORMAT:
errStr = "INCORRECT FORMAT";
break;
case END_IS_NOT_LAST:
errStr = "END IS NOT LAST";
break;
case NO_END_INSTRUCTION:
errStr = "NO END INSTRUCTION";
break;
case ERR_NO_DATA:
errStr = "NO DATA";
break;
case UNDEFINED_FUNCTION:
errStr = "UNDEFINED FUNCTION";
break;
case UNDEFINED_NUMBER:
errStr = "UNDEFINED NUMBER";
break;
case PROGRAM_TOO_LONG:
errStr = "PROGRAM TOO LONG";
break;
case TOO_MUCH_DATA:
errStr = "TOO MUCH DATA";
break;
case TOO_MANY_LABELS:
errStr = "TOO MANY LABELS";
break;
case NOT_MATCH_WITH_FOR:
errStr = "NOT MATCH WITH FOR";
break;
case FOR_WITHOUT_NEXT:
errStr = "FOR WITHOUT NEXT";
break;
case CUT_PROGRAM_OR_DIMS:
errStr = "CUT PROGRAM OR DIMS";
break;
case SUBSCRIPT_ERROR:
errStr = "SUBSCRIPT ERROR";
break;
case ILLEGAL_RETURN:
errStr = "ILLEGAL RETURN";
break;
}
cout << errStr;
// Only print out the line number if we're in a numbered source line
if(this->m_Context->GetCode()->GetCurrentLineNumber())
cout << " ON LINE: " << this->m_Context->GetCode()->GetCurrentLineNumber();
cout << endl;
}
// Show help
void CRunTime::cHelp(void)
{
cout << "COMMANDS:" << endl;
cout << " LIST - DISPLAY SOURCE LISTING." << endl;
cout << " LIST--XX - DISPLAY LINE NUMBER XX." << endl;
cout << " SAVE - SAVE CURRENT PROGRAM." << endl;
cout << " UNSAVE - REMOVE CURRENT PROGRAM FROM STORAGE." << endl;
cout << " CATALOG - DISPLAY SAVED PROGRAMSS." << endl;
cout << " NEW - CREATE A NEW PROGRAM." << endl;
cout << " OLD - LOAD AN EXISTING PROGRAM." << endl;
cout << " SCRATCH - DELETE ALL PROGRAM DATA, RETAINS NAME." << endl;
cout << " RENAME - RENAME CURRENT PROGRAM." << endl;
cout << " RUN - RUN CURRENT PROGRAM." << endl;
cout << " HELP - DISPLAY THIS TEXT." << endl;
cout << " QUIT - QUIT BASIC AND RETURN TO SYSTEM." << endl;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -