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;
}
}
}