maekawatoshiki
4/7/2015 - 9:52 AM

Interpreter "CON"

Interpreter "CON"

/*
	Interpreter "CON"
	
	Using:
		fizzbuzz.a :
		i = 0
		:loop
			if i < 40
				if i % 15 == 0
					print "FizzBuzz"
				else
				if i % 3 == 0
					print "Fizz"
				else
				if i % 5 == 0
					print "Buzz"
				else
					print i
				end
				print "\n"
			i = i + 1
			goto :loop
		end
		
		Command Line:
		$ g++ Main.cpp
		$ ./a.out fizzbuzz.a
		
	Copyright(C) 2015 MAEKAWA TOSHIKI.
*/

// Main.cpp
// C++ Libaries
#include <iostream>
#include <fstream>
#include <string>
#include <stack>
#include <vector>
#include <sstream>
#include <iomanip>
#include <map>
// C Libaries
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <cmath>

using namespace std;
#define ASSIG 100
#define SAME 200
#define DIFFER 201
#define BIGLEFT 202
#define BIGRIGHT 203
#define SAME_BIGLEFT 204
#define SAME_BIGRIGHT 205
#define IF_TRUE 1
#define IF_FALSE 0


class Calculator
{
private:
	vector<string> array;
	vector<string> ans;
public:
	char *str;
	string Strexpr;
	double answer;
 
	int expression();
	int fac();
	int term();
	int toRpn();
	double calc();
	Calculator();
	~Calculator();
};
 
 
Calculator::Calculator()
{
	str = new char[0xFFFF]();
}
 
 
Calculator::~Calculator()
{
	delete[] str;
}
 
 
int Calculator::fac()
{
	if (array.back() == "(")
	{
		if (array.size() >= 2) array.pop_back();
		expression();
		if (array.back() == ")")  
			if (array.size() >= 2) 
				array.pop_back();
	}
	else {
		ans.push_back(array.back());
		if (array.size() >= 2) 
			array.pop_back();
	}
	return 0;
}
 
 
int Calculator::term()
{
	fac();
	while (1)
	{
		string c = array.back();
		if ( (c == "*" || c == "/") && array.size() >= 1)
		{
			array.pop_back(); 
			fac(); 
			ans.push_back(c);
		}
		else
			break;
	}
	return 0;
}
 
 
int Calculator::expression()
{
	term();
	while (1)
	{
		string c = array.back();
		if ((c == "+" || c == "-" || c == "%") && array.size())
		{
			array.pop_back();
			term();
			ans.push_back(c);
		}
		else
			break;
	}
	return 0;
}

int Calculator::toRpn()
{
	string olds = "";
	bool nm = false;
	vector<string> siki2;
 
	for (int i = 0; i < Strexpr.length(); i++)
	{
		switch (Strexpr[i])
		{
		case '+':
		case '-':
		case '*':
		case '/':
		case '%':
		case '(':
		case ')':
			if (nm == true)
			{
				siki2.push_back(olds);
				olds = "";
				nm = false;
			}
			olds = Strexpr[i];
			siki2.push_back(olds);
			olds = "";
			break;
		default:
			olds += Strexpr[i];
			nm = true;
		}
	}
	if (nm == true) siki2.push_back(olds);
 
	// vector の順番を反対にします。
	for (int i = 0; siki2.empty() != true; i++)
	{
		array.push_back(siki2.back());
		siki2.pop_back();
	}
	expression();
 
	return 0;
}
 
double Calculator::calc()
{
	double num = 0, num2 = 0;
	int i = 0, pos = 0;
	stack<double> arr;
	string s; char c;
 
	Strexpr = str;
	memset(str, 0, 0xFFFF);
	toRpn();
	while (i < ans.size())
	{
		switch (ans[i][0])
		{
		case '+':
			num = arr.top(); arr.pop();
			num2 = arr.top(); arr.pop();
			arr.push(num2 + num);
			break;
		case '-':
			num = arr.top(); arr.pop();
			num2 = arr.top(); arr.pop();
			arr.push(num2 - num);
			break;
		case '%':
			num = arr.top(); arr.pop();
			num2 = arr.top(); arr.pop();
			arr.push( (int) fmod(num2, num) );
			break;
		case '*':
			num = arr.top(); arr.pop();
			num2 = arr.top(); arr.pop();
			arr.push(num2 * num);
			break;
		case '/':
			num = arr.top(); arr.pop();
			num2 = arr.top(); arr.pop();
			arr.push(num2 / num);
			break;
		default:
			arr.push( atof( ans[i].c_str() ) );
		}
		i++; pos++;
	}
	return answer = arr.top();
}


char *checkFunc(int pos, char *code, char *funcNameBuf)
{
	int i;
	const char functions[2][8] = {
		"print",
		"input"
	};

	for(i=0; i < 2; i++)
	{
		if( strncmp(&code[pos], functions[i], strlen( functions[i] )) == 0)
		{
			strcpy(funcNameBuf, functions[i]);
			return funcNameBuf;
		}
	}
	return NULL;
}

char *checkString(int pos, char *code, char *stringBuf)
{
	int i;

	memset(stringBuf, 0, 0xFF);
	for(i = pos; ; i++)
	{
		switch(code[i])
		{
		case '\"':
			sprintf( stringBuf, "%s%c", stringBuf, code[i]);
			return stringBuf;
		}
		sprintf( stringBuf, "%s%c", stringBuf, code[i]);
	}
	return NULL;
}

char *checkWord(int pos, char *code, char *WordNameBuf)
{
	int i;
	const char words[11][8] = {
		"if",
		"for",
		"else",
		"==",
		"!=",
		"<=",
		">=",
		"<",
		">",
		"end",
		"goto"
	};

	for(i=0; i < 11; i++)
	{
		if( strncmp(&code[pos], words[i], strlen( words[i] )) == 0)
		{
			strcpy(WordNameBuf, words[i]);
			return WordNameBuf;
		}
	}
	return NULL;
}

char *checkVar(int pos, char *code, char *varNameBuf)
{
	int i;

	memset(varNameBuf, 0, 0xFF);
	for(i = pos; ; i++)
	{
		switch(code[i])
		{
		case ';':
		case '(':
		case ')':	
		case '=':
		case '+':
		case '-':
		case '*':
		case '/':
		case '%':
		case '<':
		case '>':
		case '!':
		case '\0':
		case '\n':
		case ' ':
		case ':':
		case '\t':
		case '\"':
			return varNameBuf;
		}
		sprintf( varNameBuf, "%s%c", varNameBuf, code[i]);
	}
	return NULL;
}

char *checkNumber(int pos, char *code, char *numberBuf)
{
	int i;

	memset(numberBuf, 0, 0xFF);
	for(i = pos; ; i++)
	{
		switch(code[i])
		{
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		case '.':
			sprintf( numberBuf, "%s%c", numberBuf, code[i]);
			break;
		default: 
			return numberBuf;
		}
	}
	return NULL;
}

string Token(string code)
{
	string output;
	char funcname[0xFF]  = { 0 }, 
		varname[0xFF] = { 0 }, 
		wordname[0xFF] = { 0 }, 
		labelname[0xFF] = { 0 },
		stringname[0xFF] = { 0 },
		number[0xFF] = { 0 };
	int nowpos, startToken = 0;
	bool nameFlag = false, intFlag = false;

	for(nowpos=0; nowpos<code.size(); nowpos++)
	{
		switch(code[nowpos])
		{
		case ';':
		case '\n':
		case '(':
		case ')':	
		case '=':
		case '+':
		case '-':
		case '*':
		case '/':
		case '%':
		case '<':
		case '>':
		case '!':
		case ',':
			if( checkWord(nowpos, (char *)code.c_str(), wordname) != NULL )
			{
				output += "W";
				output += wordname;
				output += " ";
				nowpos += strlen(wordname)-1;
			}
			else
				output += "S" + code.substr(nowpos, 1) + " ";
			break;
		case '0':
		case '1':
		case '2':
		case '3':
		case '4':
		case '5':
		case '6':
		case '7':
		case '8':
		case '9':
		case '.':
			output += "I";
			checkNumber(nowpos, (char *)code.c_str(), number);
			output += number;
			output += " ";
			nowpos += strlen(number)-1;
			break;
		case ' ': 
		case '\t':
			break;
		case ':':	
			nowpos++;
			if( checkVar(nowpos, (char *)code.c_str(), labelname) != NULL )
			{
				output += "L";
				output += labelname;
				output += " ";
				nowpos += strlen(labelname) - 1;
			}
			break;
		case '\"':
			nowpos++;
			checkString(nowpos, (char *)code.c_str(), stringname);
			output += "\"";
			output += stringname;
			output += " ";
			nowpos += strlen(stringname) - 1;
			break;
		default:
			if( checkWord(nowpos, (char *)code.c_str(), wordname) != NULL )
			{
				output += "W";
				output += wordname;
				output += " ";
				nowpos += strlen(wordname) - 1;
			}
			else
			if( checkFunc(nowpos, (char *)code.c_str(), funcname) != NULL )
			{
				output += "F";
				output += funcname;
				output += " ";
				nowpos += strlen(funcname) - 1;
			}
			else if(checkVar(nowpos, (char *)code.c_str(), varname) != NULL)
			{
				output += "V";
				output += varname;
				output += " ";
				nowpos += strlen(varname) - 1;
			}
		}
	}
	return output;
}

void setLabel( map<string, int> &label, char *code)
{
	int pos;
	size_t codeSz = strlen(code);
	char labelname[0xFF] = { 0 };

	for( pos = 0; pos < codeSz; pos++ )
	{
		if(code[pos] == 'L' && code[pos-6] != 'W')
		{
			checkVar(pos+1, code, labelname);
			label[labelname] = pos-2;
		}
	}
}

char *replace(char *str)
{
	char *pos;
	char escape[6][3] = {
		"\\n","\n",
		"\\t","\t",
		"\\b","\b"
	};
	int i;
	for(i = 0; i < 6; i += 2)
	{
		while( (pos = strstr( str, escape[i] )) != NULL)
		{
			pos[0] = escape[i+1][0];
			memmove(pos + 1, pos + 2, 
				strlen(str) - 2 + 1);
		}
	}
	return str;
}

int main(int argc, char *argv[])
{
	if(argc < 2) return -1;

	map<string, double> var;
	map<string, int> label;
	stack<int> fors, forEnds;
	ifstream Source(argv[1]);
	Calculator calc;

	string code((istreambuf_iterator<char>(Source)), istreambuf_iterator<char>());
	string objcode;

	char funcname[0xFF]  = { 0 }, 
		varname[0xFF] = { 0 }, 
		number[0xFF] = { 0 },
		wordname[0xFF] = { 0 },
		stringname[0xFF] = { 0 },
		labelname[0xFF] = { 0 }, 
		assigVarName[0xFF] = { 0 };
	int nowpos;
	bool assigFlag = false;
	bool useIf = false, useFor = false, useGoto = false, useElse = false;
	int ifCmp = 0, forNumber = 0, forNumber2 = 0;
	double printDouble = 0, ifLeft = 0, ifRight = 0;
	size_t objcode_size;
	char *objcode_c;

	{// パース後のコードを Char にセット
		objcode = Token(code);
		objcode_size = objcode.size();
		objcode_c = new char[objcode_size+2]();
		strcpy(objcode_c, objcode.c_str());
	}

	cout << "After Parse:" << endl << objcode_c << endl << endl;
	cout << "Output:" << endl;

	setLabel(label, objcode_c);

	for( nowpos = 0; nowpos < objcode_size; nowpos++ )
	{
		switch(objcode_c[nowpos])
		{
		case '\"': nowpos++;
			checkString(nowpos, objcode_c, calc.str);
			nowpos += strlen(calc.str);
			break;
		case 'V': nowpos++;
			checkVar(nowpos, (char *)objcode_c, varname);
			sprintf(calc.str, "%s%.20lf", calc.str, var[varname]);
			nowpos++;
			break;
		case 'W': nowpos++;
			checkWord(nowpos, (char *)objcode_c, wordname);
			nowpos++;
			
			if(strcmp(wordname, "if") == 0) 
				useIf = true;
			else if(strcmp(wordname, "goto") == 0) 
				useGoto = true;
			else if(strcmp(wordname, "else") == 0) 
			{
				if( ifCmp == IF_TRUE )
				{
					int ifCount = 1;
					while(nowpos < objcode_size && ifCount > 0)
					{
						nowpos++;
						if(objcode_c[nowpos] == 'W' )
						{
							checkWord(nowpos+1, objcode_c, wordname);
							if(strcmp(wordname, "if") == 0)
								ifCount++;
							if(strcmp(wordname, "end") == 0)
								ifCount--;
							if(strcmp(wordname, "else") == 0)
								ifCount--;
						}
					}
				}
			}
			else if(strcmp(wordname, "end") == 0)
				useElse = useIf = false;
			else if( strcmp(wordname, "==") == 0 )
			{
				ifLeft = calc.calc();
				ifCmp = SAME;
			} 
			else if(strcmp(wordname, "!=" ) == 0 ) {
				ifLeft = calc.calc();
				ifCmp = DIFFER;
			}
			else if(strcmp(wordname, "<") == 0 ) {
				ifLeft = calc.calc();
				ifCmp = BIGRIGHT;
			}
			else if(strcmp(wordname, ">") == 0 ) {
				ifLeft = calc.calc();
				ifCmp = BIGLEFT;
			}
			else if(strcmp(wordname, ">=") == 0 ) {
				ifLeft = calc.calc();
				ifCmp = SAME_BIGLEFT;
			}
			else if(strcmp(wordname, "<=") == 0 ) {
				ifLeft = calc.calc();
				ifCmp = SAME_BIGRIGHT;
			}
			break;
		case 'L': nowpos++;
			checkVar(nowpos, (char *)objcode_c, labelname);
			break;
		case 'S': nowpos++;
			switch(objcode_c[nowpos])
			{
			case '+':
			case '-':
			case '*':
			case '/':
			case '%':
			case '(':
			case ')':
				sprintf(calc.str, "%s%c", calc.str, objcode_c[nowpos]);
				break;
			case '=':
				assigFlag = true;
				strcpy(assigVarName, varname);
				memset(calc.str, 0, strlen(calc.str));
				break;
			case ',':
				break;
			case '\n':
			case ';':
				if(assigFlag == true)
				{
					var[assigVarName] = calc.calc();
					assigFlag = false;
				}
				if( useGoto )	
				{	
					nowpos = label[labelname];
					useIf = useGoto = false;
					memset(calc.str, 0, 0xFFFF);
				}
				if( useIf )
				{
					ifRight = calc.calc();
					switch(ifCmp)
					{
					case SAME:
						if(ifRight == ifLeft)
						ifCmp = IF_TRUE;
						else ifCmp = IF_FALSE;
						break;
					case DIFFER:
						if(ifRight != ifLeft)
						ifCmp = IF_TRUE;
						else ifCmp = IF_FALSE;
						break;
					case BIGLEFT:
						if(ifLeft > ifRight)
						ifCmp = IF_TRUE;
						else ifCmp = IF_FALSE;
						break;
					case BIGRIGHT:
						if(ifLeft < ifRight)
						ifCmp = IF_TRUE;
						else ifCmp = IF_FALSE;
						break;
					case SAME_BIGLEFT:
						if(ifLeft >= ifRight)
						ifCmp = IF_TRUE;
						else ifCmp = IF_FALSE;
						break;
					case SAME_BIGRIGHT:
						if(ifLeft <= ifRight)
						ifCmp = IF_TRUE;
						else ifCmp = IF_FALSE;
						break;
					}
					if( ifCmp == IF_FALSE )
					{
						int ifCount = 1;
						useElse = false;
						while(nowpos < objcode_size && ifCount > 0)
						{
							nowpos++;
							if(objcode_c[nowpos] == 'W' )
							{
								checkWord(nowpos+1, objcode_c, wordname);
								if(strcmp(wordname, "if") == 0)
									ifCount++;
								if(strcmp(wordname, "end") == 0)
								{
									if( useElse ) { ifCount++; useElse = false; }
									ifCount--;
								}
								if(strcmp(wordname, "else") == 0)
								{ 
									useElse = true; 
									ifCount--; 
								}
							}
						}
						nowpos += 6;
					}
					useIf = false;
					memset(calc.str, 0, 0xFFFF);
				}// IF
				if(funcname != NULL)
				{
					if(strcmp(funcname, "print") == 0)
					{
						if(
							( calc.str[0] >= 48 && 
							calc.str[0] <= 59 ) || 
							( calc.str[0] >= 40 && 
							calc.str[0] <= 43 ) ||
							calc.str[0] == 45 ||
							calc.str[0] == 47
						)
						{
							printDouble = calc.calc();
							cout << setprecision(16) << printDouble;
						}
						else
						{
							replace(calc.str);
							calc.str[strlen(calc.str)-1] = 0;
							cout << calc.str;
						}
					}
					else if( strcmp(funcname, "input") == 0)
					{
						cin >> var[varname];
					}				
					memset(funcname, 0, sizeof(funcname));
					memset(calc.str, 0, 0xFFFF);
				}
				break;
			}
			break;
		case 'F': nowpos++;
			checkFunc(nowpos, (char *)objcode_c, funcname);
			nowpos++;
			break;
		case 'I': nowpos++;
			checkNumber(nowpos, (char *)objcode_c, number);
			sprintf(calc.str, "%s%.20lf",  calc.str, atof(number));
			break;
		}
	}
}