Skip to content

Instantly share code, notes, and snippets.

@bencz
Created November 20, 2012 05:40
Show Gist options
  • Save bencz/4116247 to your computer and use it in GitHub Desktop.
Save bencz/4116247 to your computer and use it in GitHub Desktop.
Basic compiler, generate IL CODE
/*
INPUT SAMPLE:
VAR NUMBER = 25
VAR STRING = "ALEX"
VAR ERRO = "THAT's NOT CAUSE AN ERROR :)"
PRINT ERRO
PRINT "ALEXANDRE"
PRINT NUMBER
GETLINE
*/
#include <stdio.h>
#include <string>
#include <vector>
#include <map>
#include <Windows.h>
using namespace std;
bool compile(FILE *fp);
bool CodeGen(std::vector<string> tokens);
void GenPrint(std::vector<string> tokens, int _pos, bool IsVar, bool _type);
void GenVar(std::vector<string> tokens, std::map<string, string> _varInfo, int _pos, bool _varType);
void GenGet();
//Assembly code global
string AssemblyCode = "";
// Il infs
void GenIlHeader(string IlName, FILE* fp);
// variable system
string VariableNames = "";
string VariableAssembly = "";
int VarNumbersArray = 0;
std::string _itoa_(int value, unsigned int base);
int main()
{
char *filename = "test.in";
FILE *fp = fopen(filename, "rb");
if(!fp)
{
return 1;
}
if(!compile(fp))
{
printf("ERROR...\n");
}
fclose(fp);
FILE* fpw = fopen("test.il", "wb");
if(!fpw)
return 1;
GenIlHeader("test", fpw);
// Write the variable declarations
fprintf(fpw, "\t.locals init (\n");
VariableNames[VariableNames.length()-2] = ')'; // remove the last comma
fwrite(VariableNames.c_str(), VariableNames.length(), 1, fpw);
// Write the code
fwrite(VariableAssembly.c_str(), VariableAssembly.length(), 1, fpw); // write variables
fwrite(AssemblyCode.c_str(), AssemblyCode.length(), 1, fpw); // write code
fprintf(fpw, "\tret\n");
fprintf(fpw, "}");
fclose(fpw);
}
bool compile(FILE *fp)
{
char c;
string token;
std::vector<string> tokens;
bool _return = true;
bool InQuote = false;
while ((c = getc(fp)) != EOF)
{
if(InQuote)
{
token += c;
if(c == '"')
InQuote = false;
}
else if(isalpha(c) || isalnum(c) || c == '"' || c == '=')
{
if(c == '"')
InQuote = true;
token += c;
}
else if(c == ' ' || c == '\0' || c == '\n')
{
tokens.push_back(token);
token = "";
}
}
tokens.push_back(token);
if(!CodeGen(tokens))
_return = false;
return _return;
}
bool CodeGen(std::vector<string> tokens)
{
int i;
bool _IsVar = false;
bool _varType = false; // false -> INT && true -> string
bool _type = false; // false -> INT && true -> string
bool _return = true;
map<string, string> _varInfo;
for(i=0;i<tokens.size();i++)
{
if(tokens[i] == "PRINT")
{
if(tokens[i+1][0] == '"')
{
_IsVar = false;
_type = true; // string
}
else
{
// get the variable type
map<string, string>::iterator it = _varInfo.find(tokens[i+1]);
if(it != _varInfo.end())
{
if(it->second[0] == '"')
{
_IsVar = true;
_type = true;
}
else
{
_IsVar = true;
_type = false; // int
}
}
}
GenPrint(tokens, i, _IsVar, _type);
}
else if(tokens[i] == "VAR")
{
if(tokens[i+2] != "=")
{
printf("Error... faltou o = \n");
_return = false;
}
else
{
// get var type ( int or string )
if(isalnum(tokens[i+3][0])) // int
{
_varInfo.insert(make_pair(tokens[i+1], tokens[i+3]));
_varType = false;
}
else if(tokens[i+3][0] == '"') // string
{
_varInfo.insert(make_pair(tokens[i+1], tokens[i+3]));
_varType = true;
}
}
GenVar(tokens, _varInfo, i, _varType);
}
else if(tokens[i] == "GETLINE")
{
GenGet();
}
}
return _return;
}
// ++++++++++++++++++++ //
// The code gen section //
// ++++++++++++++++++++ //
void GenPrint(std::vector<string> tokens, int _pos, bool IsVar, bool _type)
{
if(IsVar)
{
if(_type) // string
{
AssemblyCode += "\tldloc ";
AssemblyCode += tokens[_pos+1].c_str();
AssemblyCode += "\n\tcall void [mscorlib]System.Console::WriteLine(string)\n";
}
else // int
{
AssemblyCode += "\tldloca.s ";
AssemblyCode += tokens[_pos+1].c_str();
AssemblyCode += "\n\tcall instance string [mscorlib]System.Int32::ToString()\n";
AssemblyCode += "\tcall void [mscorlib]System.Console::WriteLine(string)\n";
}
}
else
{
AssemblyCode += "\tldstr ";
AssemblyCode += tokens[_pos+1].c_str();
AssemblyCode += "\n";
AssemblyCode += "\tcall void [mscorlib]System.Console::WriteLine(string)\n";
}
}
void GenVar(std::vector<string> tokens, std::map<string, string> _varInfo, int _pos, bool _varType)
{
string buildBase = "";
map<string, string>::iterator it = _varInfo.find(tokens[_pos+1]);
if(it != _varInfo.end())
{
if(_varType == true) // string
{
string number = _itoa_(VarNumbersArray, 10);
string declaration = "\t\t[" + number + "] string " + it->first.c_str() + ",\n";
VariableNames += declaration;
buildBase += "\tldstr ";
buildBase += it->second.c_str();
buildBase += "\n";
VariableAssembly += buildBase;
// Clear buildbase
buildBase = "";
buildBase += "\tstloc ";
buildBase += it->first.c_str();
buildBase += "\n";
VariableAssembly += buildBase;
VarNumbersArray++;
}
else // int
{
string number = _itoa_(VarNumbersArray, 10);
string declaration = "\t\t[" + number + "] int32 " + it->first.c_str() + ",\n";
VariableNames += declaration;
buildBase += "\tldc.i4.s ";
buildBase += it->second.c_str();
buildBase += "\n";
VariableAssembly += buildBase;
// clear buildBase
buildBase = "";
buildBase += "\tstloc ";
buildBase += it->first.c_str();
buildBase += "\n";
VariableAssembly += buildBase;
VarNumbersArray++;
}
}
}
void GenGet()
{
AssemblyCode += "\tnop\n";
AssemblyCode += "\tcall string [mscorlib]System.Console::ReadLine()\n";
AssemblyCode += "\tpop\n";
}
// ++++++++++++++++++ //
// Il basic generator //
// ++++++++++++++++++ //
void GenIlHeader(string IlName, FILE* fp)
{
fprintf(fp, ".assembly %s {}\n", IlName.c_str());
fprintf(fp, ".assembly extern mscorlib {}\n");
fprintf(fp, ".method static void Main()\n");
fprintf(fp, "{\n");
fprintf(fp, "\t.entrypoint\n");
fprintf(fp, "\t.maxstack 1\n\n");
}
// ************ //
// Special Test //
// ************ //
std::string _itoa_(int value, unsigned int base)
{
const char digitMap[] = "0123456789abcdef";
std::string buf;
if (base == 0 || base > 16)
{
return buf;
}
std::string sign;
int _value = value;
if (_value == 0)
return "0";
if (value < 0)
{
_value = -value;
sign = "-";
}
for (int i = 30; _value && i ; --i)
{
buf = digitMap[ _value % base ] + buf;
_value /= base;
}
return sign.append(buf);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment