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

📄 codeline.cpp

📁 由一个古老的BASIC解释器改进而成, 保留了ANSI C固有的艺术美感.
💻 CPP
字号:
//	codeline.cpp

//#include "codeline.h"
#include "program.h"
#include "keyword.h"
#include "token.h"
#include "var.h"
#include "error.h"

#include <iostream>
#include <sstream>
#include <algorithm>
#include <cmath>
#include <cctype>
using std::isxdigit;

#include <iostream>
using std::cerr;
using std::endl;

namespace {

inline bool isbindigit (char c)
{
        return c == '0' || c == '1';
}

inline bool isoctdigit (char c)
{
        return c >= '0' && c <= '7';
}

inline bool isbeginidentifier (char c)
{
	return isalpha (c) /* || c == '_' */;
}

inline bool isidentifier (char c)
{
	return isalnum (c) || c == '_';
}

} // namespace

BlNumber CodeLine::Token::number (const std::string & str)
{
	size_t i= 0, l= str.size ();
	if (i >= l) return 0;
	BlNumber n= 0;
	unsigned char c;
	if (str [0] == '&')
	{
                if (l > 1)
                {
			long num= 0;
                        c= str [1];
                        if (c == 'X' || c == 'x')
                        {
			// Binary
                                i= 1;
                                while (++i < l && isbindigit (c= str [i]) )
                                {
                                        num*= 2;
                                        num+= c- '0';
                                }
                        }
                        else if (c == 'O' || c == 'o')
                        {
			// Octal
                                i= 1;
                                while (++i < l && isoctdigit (c= str [i]) )
                                {
                                        num*= 8;
                                        num+= c- '0';
                                }
                        }
                        else
                        {
                        // Hexadecimal
                                if (c == 'H' || c == 'h')
                                        i= 1;
                                while (++i < l && isxdigit (c= str [i] ) )
                                {
                                        num*= 16;
                                        if (c >= 'a' && c <= 'f')
                                                c= (unsigned char) (c + '9' - 'a' + 1);
                                        else if (c >= 'A' && c <= 'F')
                                                c= (unsigned char) (c + '9' - 'A' + 1);
                                        num+= c - '0';
                                }
                        }
			n= num;
                }
	}
	else {
		// Decimal
		#if 0
		while (i < l && isdigit (c= str [i]) )
		{
			n*= 10;
			n+= c - '0';
			++i;
		}
		if (i < l && str [i] == '.')
		{
			++i;
			BlNumber mult= 0.1;
			while (i < l && isdigit (c= str [i] ) )
			{
				n+= (c - '0') * mult;
				mult/= 10;
				++i;
			}
		}
		if (i < l && (str [i] == 'E' || str [i] == 'e') )
		{
			++i;
			BlNumber e= 0;
			bool neg= false;
			if (str [i] == '-')
			{
				neg= true;
				++i;
			}
			while (i < l && (isdigit (c= str [i] ) ) )
			{
				e*= 10;
				e+= c - '0';
				++i;
			}
			if (neg) e= -e;
			n*= pow (10, e);
		}
		#else
		std::istringstream iss (str);
		iss >> n;
		#endif
	}
	return n;
}

BlNumber CodeLine::Token::number () const
{
        switch (code)
        {
        case keyNUMBER:
        case keySTRING:
                return number (str);
        case keyINTEGER:
                return valueint;
        default:
        	cerr << "Codeline::Token::number called but code= " <<
        		code << " is not valid." << endl;
                throw ErrBlassicInternal;
        }
}

CodeLine::CodeLine () :
	strcontent (0),
	owner (false),
	pos (0),
	chk (0),
	lastcode (0)
{
}

CodeLine::CodeLine (BlChar * str, BlLineNumber number, BlLineLength length) :
	strcontent (str),
	linenumber (number),
	len (length),
	owner (false),
	pos (0),
	chk (0),
	lastcode (0)
{
}

CodeLine::CodeLine (const CodeLine & old) :
	strcontent (old.strcontent),
	linenumber (old.linenumber),
	len (old.len),
	owner (false),
	pos (0),
	chk (0),
	lastcode (0)
{
}

CodeLine::~CodeLine ()
{
	if (owner && strcontent)
		delete [] strcontent;
}

void CodeLine::assign (BlChar * str, BlLineNumber number, BlLineLength length)
{
	if (owner)
		delete strcontent;
	strcontent= str;
	linenumber= number;
	len= length;
	owner= false;
	pos= 0;
	chk= 0;
	lastcode= 0;
}

CodeLine & CodeLine::operator= (const CodeLine & old)
{
	if (& old != this)
	{
		if (owner && strcontent)
			delete [] strcontent;
		strcontent= old.strcontent;
		linenumber= old.linenumber;
		len= old.len;
		owner= false;
		pos= 0;
		chk= 0;
		lastcode= 0;
	}
	return * this;
}

CodeLine::Token CodeLine::getdata ()
{
        while (pos < len && isspace (strcontent [pos] ) )
                ++pos;
        Token r;
        if (pos >= len)
        {
                r.code= lastcode= keyENDLINE;
                return r;
        }
        char c= strcontent [pos];
        if (c == '"')
        {
		++pos;
		while ( (c= strcontent [pos++]) != '\0')
			r.str+= c;
        }
        else if (c == INTEGER_PREFIX)
        {
                //BlInteger n;
                //n= * (BlInteger *) (strcontent + pos + 1);
                //r.valueint= n;
		r.valueint= peek32 (strcontent + pos + 1);
                r.code= keyINTEGER;
                pos+= 5;
                return r;
        }
        else
	{
		while (pos < len && (c= strcontent [pos]) != ',' && c != ':')
		{
			if (c == INTEGER_PREFIX)
			{
				r.str+= util::to_string
					(peek32 (strcontent + pos + 1) );
				pos+= 5;
			}
			else
			{
				r.str+= c;
				++pos;
			}
		}
	}
        r.code= keySTRING;
        return r;
}

namespace {

BlChar validinitident [256];
BlChar validident [256];

bool inittables ()
{
	std::fill_n (& validident [0], 256, 0);
	std::fill_n (& validinitident [0], 256, 0);
	validident ['_']= '_';
	for (BlChar i= '0'; i <= '9'; ++i)
		validident [i]= i;
	for (BlChar i= 'A'; i <= 'Z'; ++i)
	{
		validident [i]= i;
		validinitident [i]= i;
	}
	for (BlChar i= 'a'; i <= 'z'; ++i)
	{
		validident [i]= BlChar (i - 'a' + 'A');
		validinitident [i]= BlChar (i - 'a' + 'A');
	}
	return true;
}

bool initiated= inittables ();

} // namespace

//CodeLine::Token CodeLine::gettoken ()
void CodeLine::gettoken (Token & r)
{
	while (pos < len && isspace (strcontent [pos] ) )
		++pos;
	if (pos >= len)
	{
		r.code= lastcode= keyENDLINE;
		++chk;
		return;
	}
	BlChar c= strcontent [pos];
	BlChar c2;
	if (iskey (c) )
	{
		r.code= c;
		++pos;
		r.code<<= 8;
		r.code|= strcontent [pos++];
		if (r.code == keyTHEN || r.code == keyELSE)
			++chk;
	}
	else if ( (c2= validinitident [c]) != 0)
	{
		r.code= keyIDENTIFIER;
		#if 0
		r.str.erase ();
		do {
			r.str+= char (toupper (c) );
			++pos;
		} while (pos < len && isidentifier (c= strcontent [pos]) );
		#else
		r.str= c2;
		while ( ++pos < len &&
			(c2= validident [ (c= strcontent [pos] ) ] ) != 0)
		{
			r.str+= c2;
		}
		#endif

		if (pos < len && c == '$' || c == '%' || c == '!')
		{
			++pos;
			r.str+= c;
		}
	}
	else if (isdigit (c) || c == '.')
	{
		r.code= keyNUMBER;
		{
		std::string strnum;
		while (pos < len && (isdigit (c= strcontent [pos]) ) )
		{
			strnum+= c;
			++pos;
		}
		if (pos < len && (c= strcontent [pos] ) == '.')
		{
			strnum+= '.';
			++pos;
			while (pos < len && (isdigit (c= strcontent [pos]) ) )
			{
				strnum+= c;
				++pos;
			}
		}
		if (pos < len && (c == 'E' || c == 'e') )
		{
			strnum+= c;
			++pos;
			if ( (c= strcontent [pos]) == '-' || c == '+')
			{
				strnum+= c;
				++pos;
			}
			while (pos < len && (isdigit (c= strcontent [pos] ) ) )
			{
				strnum+= c;
				++pos;
			}
		}
		r.str= strnum;
		}
	}
	else if (c == '&')
	{
		// Hexadecimal, octal or binary number.
		r.code= keyNUMBER;
		r.str= '&';
                ++pos;
                if (pos < len)
                {
                        c= strcontent [pos];
                        if (c == 'X' || c == 'x')
                        {
				// Binary
                                ++pos;
                                r.str+= c;
                                while (pos < len && isbindigit (strcontent [pos] ) )
                                {
                			r.str+= strcontent [pos];
                                        ++pos;
		                }
                        }
                        else if (c == 'O' || c == 'o')
                        {
				// Octal
                                ++pos;
                                r.str+= c;
                                while (pos < len && isoctdigit (strcontent [pos] ) )
                                {
                                        r.str+= strcontent [pos];
                                        ++pos;
                                }
                        }
                        else
                        {
				// Hexadecimal
                                if (c == 'H' || c == 'h')
                                {
                                        ++pos;
                                        r.str+= c;
                                }
        	        	while (pos < len && isxdigit (strcontent [pos] ) )
        	        	{
                			r.str+= strcontent [pos];
                                        ++pos;
		                }
                        }
                }
	}
	else
	{
		++pos;
		switch (c)
		{
		case INTEGER_PREFIX:
			r.code= keyINTEGER;
			{
				//r.valueint= * (BlInteger *) (strcontent + pos);
				r.valueint= peek32 (strcontent + pos);
				pos+= 4;
			}
			break;
		case '"':
			r.code= keySTRING;
			r.str.erase ();
			while ( (c= strcontent [pos++]) != '\0')
				r.str+= c;
			break;
		case '<':
			if (pos < len)
			{
				switch (strcontent [pos] )
				{
				case '>':
					r.code= keyDISTINCT;
					++pos;
					break;
				case '=':
					r.code= keyMINOREQUAL;
					++pos;
					break;
				default:
					r.code= '<';
				}
			}
			else r.code= '<';
			break;
		case '>':
			if (pos < len)
			{
				switch (strcontent [pos] )
				{
				case '=':
					r.code= keyGREATEREQUAL;
					++pos;
					break;
				default:
					r.code= '>';
				}
			}
			else r.code= '>';
			break;
		case '\'':
			r.code= lastcode= keyENDLINE;
			++chk;
			pos= len;
			break;
		case ':':
			r.code= ':';
			++chk;
		break;
		default:
			r.code= c;
		}
	}
	lastcode= r.code;
}

void CodeLine::gotochunk (BlChunk chknew)
{
	pos= 0; chk= 0;
	if (chknew == 0)
	{
		lastcode= 0;
		return;
	}
	while (chk < chknew)
	{
		if (pos >= len)
		{
			lastcode= keyENDLINE;
			return;
		}
		char c= strcontent [pos];
		if (iskey (c) )
		{
			BlCode code;
			code= strcontent [pos++];
			code<<= 8;
			code|= strcontent [pos++];
			if (code == keyTHEN || code == keyELSE)
			{
				lastcode= code;
				++chk;
			}
		}
		else
			if (c == '"')
			{
				++pos;
				while (strcontent [pos] != '\0')
					++pos;
				++pos;
			}
			else
			{
				if (c == ':')
				{
					lastcode= ':';
					++chk;
				}
				++pos;
			}
	}
}

void CodeLine::scan (const std::string & line)
{
	linenumber= 0;
	len= 0;
	pos= 0;
	if (line.empty () )
		return;
	int i= 0, l= line.size ();
	while (i < l && isspace (line [i] ) )
		++i;
	if (i < l && isdigit (line [i] ) )
	{
		while (i < l && isdigit (line [i] ) )
		{
			linenumber*= 10;
			linenumber+= line [i] - '0';
			++i;
		}
		if (i < l && line [i] == ' ') ++i;
	}
	else i= 0;

	std::string newcontent;
	Tokenizer t (line.substr (i) );
	//std::string str;
        Tokenizer::Token token;
        BlCode code;
	bool incomment= false;
        bool addspace;
	while ( ! (token= t.get () ).empty () )
	{
		//std::cerr << '(' << str << ')' << std::flush;
                switch (token.type)
                {
                case Tokenizer::Literal:
                        newcontent+= '"';
			newcontent+= token.str;
			newcontent+= '\0';
                        break;
                case Tokenizer::Integer:
                        newcontent+= INTEGER_PREFIX;
                        //newcontent+= std::string ( (char *) & token.n, 4);
			newcontent+= makestring (token.n);
                        break;
                case Tokenizer::Plain:
			code= 0;
			addspace= false;
			if (! incomment)
			{
				if (token.str == "?")
				{
					code= keyPRINT;
					char c= t.peek ();
					if (c != '\0' && ! isspace (c) )
						addspace= true;
				}
				else
					code= keyword (token.str);
			}
			if (code == 0)
			{
				newcontent+= token.str;
				if (token.str == "'")
					incomment= true;
			}
			else
			{
				newcontent+= char (code >> 8);
				newcontent+= char (code & 0xFF);
				if (code == keyREM)
					incomment= true;
			}
			if (addspace)
				newcontent+= ' ';
                        break;
                default:
                        throw ErrBlassicInternal;
		}
	}
	if (owner && strcontent)
		delete [] strcontent;
	len= newcontent.size ();
	if (len > 0)
	{
		strcontent= new unsigned char [len];
		owner= true;
		memcpy (strcontent, newcontent.data (), len);
	}
	else
	{
		owner= false;
		strcontent= NULL;
	}
}

// Fin de codeline.cpp

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -