⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 runtime.cpp

📁 a basic interpreter free basic
💻 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 + -