Click here to Skip to main content
15,891,905 members
Articles / Programming Languages / C++

MyBasic - A Custom-BASIC language interpreter written in C++

Rate me:
Please Sign up or sign in to vote.
4.75/5 (18 votes)
12 Oct 2003 227.7K   4.5K   46  
A Custom-BASIC language interpreter written in C++
// Basic.cpp: implementation of the CBasic class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "MyBasic.h"
#include "Basic.h"

#ifdef _DEBUG
#undef THIS_FILE
static char THIS_FILE[]=__FILE__;
#define new DEBUG_NEW
#endif


//////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////
// Please do not remove the folowing comment !!!
// This code is writen by LiuXueSong����ѩ�ɣ�aladeing@163.com
// Thanks for Zoly Farkas I used the code of tokenizer from him
// You may use this code free
// Please if any bug found send a mail to me
// Thankx




//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CBasic::CBasic()
{
	m_VariableTable.InitHashTable(MAX_VAR);
	m_LabelTable.InitHashTable(MAX_LABEL);
}

CBasic::~CBasic()
{
}

void CBasic::Init()
{
	help_init_stack();
	help_init_gstack();

	m_VariableTable.RemoveAll( );
	m_LabelTable.RemoveAll( );
}

/////////////////////////////////////////////////////////////////

//���ڼ���+,-��
void CBasic::help_level2(_Variable*result)
{
	_Variable hold;
	help_level3(result);
	int nToken = m_BasicLex.NextToken();
	while(nToken == '+' || nToken == '-')
	{
		help_level3(&hold);
		help_arith(nToken,result,&hold);
		nToken =m_BasicLex.NextToken();
	}
	m_BasicLex.PushBack();
}

//���ڼ���*,/,%��
void CBasic::help_level3(_Variable*result)
{
	_Variable hold;

	help_level4(result);

	int nToken = m_BasicLex.NextToken();
	while(nToken == '*' || nToken == '/' || nToken == '%')
	{
		help_level4(&hold);
		help_arith(nToken,result,&hold);
		nToken =m_BasicLex.NextToken();
	}
	m_BasicLex.PushBack();
}

//���ڼ���^��
void CBasic::help_level4(_Variable*result)
{
	_Variable hold;

	help_level6(result);

	int nToken = m_BasicLex.NextToken();
	while(nToken == '^')
	{
		help_level6(&hold);
		help_arith(nToken,result,&hold);
		nToken =m_BasicLex.NextToken();
	}
	m_BasicLex.PushBack();
}
//���ڼ��㵥Ŀ����+,-
void CBasic::help_level5(_Variable*result)
{
}
//���ڼ���( )��
void CBasic::help_level6(_Variable*result)
{
	int nToken = m_BasicLex.NextToken();
	if(nToken == '(')
	{
		help_level2(result);
		nToken =m_BasicLex.NextToken();
		if(nToken != ')')
		{
			Error(1,"û���ҵ�ƥ��� ')' !");
		}
	}
	else
	{
		m_BasicLex.PushBack();
		help_primitive(result);
	}

}

//���ڷ������֡�����
void CBasic::help_primitive(_Variable*result)
{

	int nToken = m_BasicLex.NextToken();

	if(nToken ==TT_INTEGER)
	{
		result->m_nVariableType = typeVariableInt;
		result->m_nValue = (int) m_BasicLex.GetNumValue();
		return;
	}else if(nToken ==TT_REAL)
	{
		result->m_nVariableType = typeVariableFloat;
		result->m_fValue = (float) m_BasicLex.GetNumValue();
		return;
	}else if(nToken ==TT_WORD)
	{
		_Variable value;
		CString strLalueName=m_BasicLex.GetStrValue();
		if(!m_VariableTable.Lookup(strLalueName,value))
		{
			//�����δ�����,���ó�ʼֵ��ʼ�������������������
			m_VariableTable[strLalueName]=value;//Ӧ���ڴ˲��Ա��Ƿ��Ѿ�������DZ����
		} 
		*result = value;
		return;
	}
	Error(1,"��Ԥ�ڵ��������������������");

}

//���ڼ���result = result o hold
void CBasic::help_arith(char o,_Variable*result , _Variable*hold)
{
	int t,ex;
	float fex;

	//�������͵�ת��
	switch(o)
	{
	case '-':
		if(result->m_nVariableType == typeVariableInt && hold->m_nVariableType == typeVariableInt)
		{
			result->m_nValue -= hold->m_nValue;
			result->m_nVariableType = typeVariableInt;
		}
		else if(result->m_nVariableType == typeVariableInt && hold->m_nVariableType == typeVariableFloat)
		{
			result->m_fValue = result->m_nValue - hold->m_fValue;
			result->m_nVariableType = typeVariableFloat;
		}
		else if(result->m_nVariableType == typeVariableFloat && hold->m_nVariableType == typeVariableInt)
		{
			result->m_fValue = result->m_fValue - hold->m_nValue;
			result->m_nVariableType = typeVariableFloat;
		}
		else if(result->m_nVariableType == typeVariableFloat && hold->m_nVariableType == typeVariableFloat)
		{
			result->m_fValue = result->m_fValue - hold->m_fValue;
			result->m_nVariableType = typeVariableFloat;
		}

		break;
	case '+':
		if(result->m_nVariableType == typeVariableInt && hold->m_nVariableType == typeVariableInt)
		{
			result->m_nValue += hold->m_nValue;
			result->m_nVariableType = typeVariableInt;
		}
		else if(result->m_nVariableType == typeVariableInt && hold->m_nVariableType == typeVariableFloat)
		{
			result->m_fValue = result->m_nValue + hold->m_fValue;
			result->m_nVariableType = typeVariableFloat;
		}
		else if(result->m_nVariableType == typeVariableFloat && hold->m_nVariableType == typeVariableInt)
		{
			result->m_fValue = result->m_fValue + hold->m_nValue;
			result->m_nVariableType = typeVariableFloat;
		}
		else if(result->m_nVariableType == typeVariableFloat && hold->m_nVariableType == typeVariableFloat)
		{
			result->m_fValue = result->m_fValue + hold->m_fValue;
			result->m_nVariableType = typeVariableFloat;
		}
		break;
	case '*':
		if(result->m_nVariableType == typeVariableInt && hold->m_nVariableType == typeVariableInt)
		{
			result->m_nValue *= hold->m_nValue;
			result->m_nVariableType = typeVariableInt;
		}
		else if(result->m_nVariableType == typeVariableInt && hold->m_nVariableType == typeVariableFloat)
		{
			result->m_fValue = result->m_nValue * hold->m_fValue;
			result->m_nVariableType = typeVariableFloat;
		}
		else if(result->m_nVariableType == typeVariableFloat && hold->m_nVariableType == typeVariableInt)
		{
			result->m_fValue = result->m_fValue * hold->m_nValue;
			result->m_nVariableType = typeVariableFloat;
		}
		else if(result->m_nVariableType == typeVariableFloat && hold->m_nVariableType == typeVariableFloat)
		{
			result->m_fValue = result->m_fValue * hold->m_fValue;
			result->m_nVariableType = typeVariableFloat;
		}
		break;
	case '/':
		if(result->m_nVariableType == typeVariableInt && hold->m_nVariableType == typeVariableInt)
		{
			if(hold->m_nValue==0)
			{
				Error(1,"������������");
				break;
			}
			result->m_nValue /= hold->m_nValue;
			result->m_nVariableType = typeVariableInt;
		}
		else if(result->m_nVariableType == typeVariableInt && hold->m_nVariableType == typeVariableFloat)
		{
			if(hold->m_fValue==0)
			{
				Error(1,"������������");
				break;
			}
			result->m_fValue = result->m_nValue / hold->m_fValue;
			result->m_nVariableType = typeVariableFloat;
		}
		else if(result->m_nVariableType == typeVariableFloat && hold->m_nVariableType == typeVariableInt)
		{
			if(hold->m_nValue==0)
			{
				Error(1,"������������");
				break;
			}
			result->m_fValue = result->m_fValue / hold->m_nValue;
			result->m_nVariableType = typeVariableFloat;
		}
		else if(result->m_nVariableType == typeVariableFloat && hold->m_nVariableType == typeVariableFloat)
		{
			if(hold->m_fValue==0)
			{
				Error(1,"������������");
				break;
			}
			result->m_fValue = result->m_fValue / hold->m_fValue;
			result->m_nVariableType = typeVariableFloat;
		}		
		break;
	case '%':
		if(result->m_nVariableType != typeVariableFloat || hold->m_nVariableType != typeVariableFloat)
		{
			Error(1,"%������������������");
			break;
		}
		if(hold->m_nValue==0)
		{
			Error(1,"������������");
			break;
		}
		result->m_nValue %= hold->m_nValue;
		result->m_nVariableType = typeVariableInt;
		break;
	case '^':
		if(hold->m_nVariableType!=typeVariableInt)
		{
			Error(1,"ָ������Ϊ����");
			break;
		}
		if(result->m_nVariableType == typeVariableFloat)
		{
			fex = result->m_fValue;
			if(hold->m_nValue==0)
			{
				hold->m_nValue=1;
				break;
			}
			for(t=hold->m_nValue-1;t>0;--t)
				result->m_fValue=result->m_fValue*fex;
			result->m_nVariableType = typeVariableFloat;
		}

		if(result->m_nVariableType == typeVariableInt)
		{
			ex = result->m_nValue;
			if(hold->m_nValue==0)
			{
				hold->m_nValue=1;
				break;
			}
			for(t=hold->m_nValue-1;t>0;--t)
				result->m_nValue=result->m_nValue*ex;
			result->m_nVariableType = typeVariableInt;
		}
		break;
	};
}

//�ɴ���IJ�������+,-,*,/,%,^,��Ŀ+,-,����
void CBasic::help_exp(_Variable*result)
{
	
	help_level2(result);

}
/////////////////////////////////////////////////////////////////
void CBasic::help_scan_labels()
{
	_Label value;
	CString strLable;

	m_BasicLex.Locate(0);
	m_BasicLex.EolIsSignificant(TRUE);

	int nToken= m_BasicLex.NextToken();
	if(nToken == TT_INTEGER)
	{
		strLable = m_BasicLex.GetStrValue();
		value.m_nAddress = m_BasicLex.GetLocation();
		value.m_strName = strLable;
		m_LabelTable[strLable]=value;//Ӧ���ڴ˲��Ա��Ƿ��Ѿ�������DZ����
		//lxs		AfxMessageBox("Scanlabels "+strLable);
	}
	if(nToken==TT_EOF)
		goto ex;
	else if(nToken!=TT_EOL)
		while((nToken = m_BasicLex.NextToken())!=TT_EOF && nToken!=TT_EOL);
	
	do{
		nToken = m_BasicLex.NextToken();
		if(nToken == TT_INTEGER)
		{
			strLable = m_BasicLex.GetStrValue();
			if(m_LabelTable.Lookup(strLable,value))
			{
				Error(1,"��ű��ظ����壡");
			}
			else
			{
				value.m_nAddress = m_BasicLex.GetLocation();
				value.m_strName = strLable;
				m_LabelTable[strLable]=value;//Ӧ���ڴ˲��Ա��Ƿ��Ѿ�������DZ����
				//lxs				AfxMessageBox("Scanlabels "+strLable);
			}
	
		}
		
		if(nToken==TT_EOF)
			goto ex;
		else if(nToken!=TT_EOL)
			while((nToken = m_BasicLex.NextToken())!=TT_EOF && nToken!=TT_EOL);

	}while(nToken!=TT_EOF);	
ex:;
	m_BasicLex.EolIsSignificant(FALSE);
}

/////////////////////////////////////////////////////////////////
void CBasic::exec_default()
{
	m_BasicLex.EolIsSignificant(TRUE);

	int nToken= m_BasicLex.NextToken();

	do{
		nToken = m_BasicLex.NextToken();
	}while(nToken!=TT_EOL&&nToken!=TT_EOF);	

	m_BasicLex.EolIsSignificant(FALSE);
}

void CBasic::exec_lable()
{
//	int nToken= m_BasicLex.NextToken();
//	AfxMessageBox("���"+m_BasicLex.GetStrValue());
}

void CBasic::exec_goto()
{
	_Label value;
	CString strLable;
	int nToken= m_BasicLex.NextToken();
	if(nToken!=TT_INTEGER)
		Error(1,"goto ��Ҫ�����ֱ��");

	strLable = m_BasicLex.GetStrValue();
	if(!m_LabelTable.Lookup(strLable,value))
		Error(1,"goto �������");

	m_BasicLex.Locate(value.m_nAddress);

//	AfxMessageBox("���"+m_BasicLex.GetStrValue());
}
void CBasic::exec_print()
{
	_Variable result;
	int nToken;

	CString strOut;
	m_BasicLex.EolIsSignificant(TRUE);

	do
	{
		nToken= m_BasicLex.NextToken();
		if(nToken==TT_STRING)
		{
			strOut+=m_BasicLex.GetStrValue();
		}
		else
		{
			CString strTrik;
			
			m_BasicLex.PushBack();

			help_exp(&result);

			if(result.m_nVariableType == typeVariableInt)
			{
				strTrik.Format("%d",result.m_nValue);
			}
			else if(result.m_nVariableType == typeVariableFloat)
			{
				strTrik.Format("%f",result.m_fValue);
			}
			strOut+=strTrik;
		}
		nToken= m_BasicLex.NextToken();
	}while(nToken!=TT_EOF&&nToken!=TT_EOL&&(nToken==';'||nToken==','));

	if(nToken!=TT_EOF&&nToken!=TT_EOL)
		Error(1,"PRINT�����������");

	AfxMessageBox(strOut);

	m_BasicLex.EolIsSignificant(FALSE);
}
void CBasic::exec_end()
{
	int nToken= m_BasicLex.NextToken();
//�����Լ����END�Ժ��н�����ǰ�Ƿ��б���ַ�����б������
}

void CBasic::exec_assignment()
{
	_Variable value;
	CString strLalueName;
	m_BasicLex.EolIsSignificant(TRUE);

	//���������
	int nToken= m_BasicLex.NextToken();
	strLalueName = m_BasicLex.GetStrValue();
	//�����δ�����,���ó�ʼֵ��ʼ�������������������
	m_VariableTable[strLalueName]=value;//Ӧ���ڴ˲��Ա��Ƿ��Ѿ�������DZ����

	//����=��
	nToken= m_BasicLex.NextToken();
	if(nToken!='=')
	{
		Error(1,"��ֵ���δ����'='");
	}

	//���ʽ����
	_Variable result;
	help_exp(&result);

	//�����δ������ı����ͼ������������������͸ı����ֵ
	m_VariableTable[strLalueName]= result;

	nToken= m_BasicLex.NextToken();
	if(nToken!=TT_EOF&&nToken!=TT_EOL)
		Error(1,"��ֵ��������������");
	m_BasicLex.EolIsSignificant(FALSE);

}

void CBasic::exec_for()
{
	_Variable value;
	struct _StackCell i;

	//���������
	int nToken= m_BasicLex.NextToken();
	if(nToken!=TT_WORD)
		Error(1,"����ȷ�ı�����");

	i.m_strValueName = m_BasicLex.GetStrValue();

	//����=��
	nToken= m_BasicLex.NextToken();
	if(nToken!='=')
	{
		Error(1,"FOR��������'='");
	}

	//���ʽ����
	help_exp(&value);
	if(value.m_nVariableType!=typeVariableInt)
		Error(1,"FOR �����Ӧ�÷������� ");

	m_VariableTable[i.m_strValueName]= value;

	//����TO
	nToken= m_BasicLex.NextToken();
	if(nToken!=TT_KW_TO)
	{
		Error(1,"FOR��������'TO'");
	}
	//���ʽ����
	help_exp(&value);
	if(value.m_nVariableType!=typeVariableInt)
		Error(1,"TO ��Ӧ�÷������� ");

	i.m_nTarget = value.m_nValue;

	//����ִ��
	if(value.m_nValue>=m_VariableTable[i.m_strValueName].m_nValue)
	{
		i.m_nLoc = m_BasicLex.GetLocation();
		help_fPush(i);
	}
	else//����NEXT��
	{
		int iFor = 0;
		do
		{
			nToken = m_BasicLex.NextToken();
			if(nToken ==TT_EOF)
				break;
			else if(nToken ==TT_KW_FOR)
				iFor++;
			else if(nToken ==TT_KW_NEXT)
			{
				if(iFor==0)
					return;
				else
					iFor--;
			}

		}while(TRUE);

		if(iFor!=0||nToken==TT_EOF)
			Error(1,"FOR ... NEXT ����ԣ�");
	}
}

void CBasic::exec_next()
{
	_Variable value;
	struct _StackCell i;

	BOOL re = help_fPop(i);
	if(!re)
		Error(1,"û�����NEXT��ƥ���FOR");

	m_VariableTable[i.m_strValueName].m_nValue++;

	if(m_VariableTable[i.m_strValueName].m_nValue>i.m_nTarget)
		return;
	help_fPush(i);

	m_BasicLex.Locate(i.m_nLoc);
}

void CBasic::exec_if()
{
	float a,b;
	int nToken,op,cond=0;
	_Variable x,y;

	//x���ʽ����
	help_exp(&x);
	if(x.m_nVariableType==typeVariableInt)
		a = (float)x.m_nValue;
	else
		a = (float)x.m_fValue;

	//���벼�������
	op= m_BasicLex.NextToken();

	if((op!=TT_GTE)&&(op!=TT_LWE)&&(op!=TT_IS)&&(op!=TT_NE)&&(op!='>')&&(op!='<'))
			Error(1,"FOR��������'TO'");

	//y���ʽ����
	help_exp(&y);
	if(y.m_nVariableType==typeVariableInt)
		b = (float)y.m_nValue;
	else
		b = (float)y.m_fValue;

	switch(op)
	{
		case TT_GTE://>=
			if(a>=b)
				cond=1;
			break;
		case TT_LWE://<=
			if(a<=b)
				cond=1;
			break;
		case TT_IS://==
			if(a==b)
				cond=1;
			break;
		case TT_NE://<>
			if(a!=b)
				cond=1;
			break;
		case '>': //>
			if(a>b)
				cond=1;
			break;
		case '<': //<
			if(a<b)
				cond=1;
			break;
	};


	nToken = m_BasicLex.NextToken();
	if(nToken!=TT_KW_THEN)
		Error(1,"IF�����THEN��");

	if(cond==1)
		return;
	else//����ENDIF��
	{
		int iIf = 0;
		do
		{
			nToken = m_BasicLex.NextToken();
			if(nToken ==TT_EOF)
				break;
			else if(nToken ==TT_KW_IF)
				iIf++;
			else if(nToken ==TT_KW_ENDIF)
			{
				if(iIf==0)
					return;
				else
					iIf--;
			}
		}while(TRUE);

		if(iIf!=0||nToken==TT_EOF)
			Error(1,"IF ... ENDIF ����ԣ�");
	}
}

void CBasic::exec_endif()
{
}

void CBasic::exec_gosub()
{
	_Label value;
	CString strLable;
	int nToken= m_BasicLex.NextToken();
	if(nToken!=TT_INTEGER)
		Error(1,"GOSUB ��Ҫ�����ֱ��");

	strLable = m_BasicLex.GetStrValue();
	if(!m_LabelTable.Lookup(strLable,value))
		Error(1,"GOSUB �������");

	help_gPush(m_BasicLex.GetLocation());
	m_BasicLex.Locate(value.m_nAddress);
}

void CBasic::exec_return()
{
	int address;
	help_gPop(address);
	m_BasicLex.Locate(address);
}

/////////////////////////////////////////////////////////////////
void CBasic::Error(int nError,CString strError)
{
	_Error*pError = new _Error;
	pError->m_nErrorID = nError;
	pError->m_nLineNo = m_BasicLex.LineNo();
	pError->m_strErrorDes = strError;
	throw pError;
}

void CBasic::Parse(CString & strCode)
{
	try
	{
		m_BasicLex.LoadCode(strCode);
		////////////////////////////////////
		help_scan_labels();
		/////////////////////////////////////
		m_BasicLex.Locate(0);
		int nToken;

		do{
			nToken = m_BasicLex.NextToken();
			switch(nToken)
			{
				case TT_INTEGER://���
					exec_lable();
					break;
				case TT_WORD://��ֵ���
					m_BasicLex.PushBack();
					exec_assignment();
					break;
				case TT_KW_PRINT://��ӡ���
					exec_print();
					break;
				case TT_KW_INPUT:
					m_BasicLex.PushBack();
					exec_default();
					break;
				case TT_KW_IF://IF
					exec_if();
					break;
				case TT_KW_ENDIF://ENDIF
					exec_endif();
					break;
				case TT_KW_FOR://FOR
					exec_for();
					break;
				case TT_KW_NEXT://NEXT
					exec_next();
					break;
				case TT_KW_GOSUB:
					exec_gosub();//gosub
					break;
				case TT_KW_RETURN://return
					exec_return();
					break;
				case TT_KW_GOTO://GOTO���
					exec_goto();
					break;
				case TT_KW_END://END ���
					m_BasicLex.PushBack();
					exec_end();
				case TT_EOF:
					goto ex;
				default://
					Error(0,"��Ԥ�ڵ��п�ʼ!");
			};
		}while(nToken!=TT_EOF);
		ex:;

	}catch(_Error*pError)
		{
			CString ss;
			ss.Format("��%d��:'%s' ",pError->m_nLineNo,pError->m_strErrorDes);
			AfxMessageBox(ss);

		delete pError;
	}
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
China China
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions