Created
June 4, 2016 19:58
-
-
Save Mtgxyz/d177c0d3c37778b3ea6d5beda9de12c5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#include <string> | |
#include <iostream> | |
#include <algorithm> | |
#include <vector> | |
#include <cstdio> | |
using namespace std; | |
vector<string> nameTable; | |
int getVarID(string name) { | |
auto it=nameTable.end(); | |
for(auto it=nameTable.begin(); it!=nameTable.end(); it++) { | |
if(nameTable[it-nameTable.begin()]==name) | |
return it-nameTable.begin()+1; | |
} | |
nameTable.push_back(name); | |
return nameTable.size(); | |
} | |
int labelGen() { | |
static int labelNum=0; | |
return labelNum++; | |
} | |
//This is a conversion of Crenshaw's "Let's Build a Compiler" series. | |
char look; | |
void GetChar() { | |
look=getchar(); | |
if(cin.eof()) | |
look='\0'; | |
} | |
void error(string s) { | |
cerr << "\n\aError: " << s << ".\n"; | |
} | |
void abort(string s) { | |
error(s); | |
exit(-1); | |
} | |
void expected(string s) { | |
abort(s + " Expected"); | |
} | |
bool isAlpha(char c) { | |
return (c<='Z')?((c<='Z')&&(c>='A')):((c<='z')&&(c>='a')); | |
} | |
bool isDigit(char c) { | |
return (c<='9')&&(c>='0'); | |
} | |
bool isAddop(char c) { | |
return (c=='+')||(c=='-'); | |
} | |
bool isMulop(char c) { | |
return (c=='*')||(c=='/'); | |
} | |
bool isAlNum(char c) { | |
return isAlpha(c) || isDigit(c); | |
} | |
bool isWhite(char c) { | |
return (c==' ')||(c=='\t')||(c=='\n'); | |
} | |
void skipWhite() { | |
while(isWhite(look)) | |
GetChar(); | |
} | |
void match(char x) { | |
if(look==x) { | |
GetChar(); | |
skipWhite(); | |
} else | |
expected(""s+x); | |
} | |
void match(string x) { | |
for(int i=0;i<x.length();i++) { | |
match(x[i]); | |
} | |
} | |
string getName() { | |
string token=""; | |
if(!isAlpha(look)) | |
expected("Name"); | |
while(isAlNum(look)) { | |
token+=look; | |
GetChar(); | |
} | |
skipWhite(); | |
return token; | |
} | |
string getNum() { | |
string value; | |
if(!isDigit(look)) | |
expected("Integer"); | |
while(isDigit(look)) { | |
value+=look; | |
GetChar(); | |
} | |
skipWhite(); | |
return value; | |
} | |
void emit(string s) { | |
cout << "\t" << s; | |
} | |
void emitLn(string s) { | |
emit(s); | |
cout << "\n"; | |
} | |
void expression(); | |
void ident() { | |
string name=getName(); | |
if(look=='(') { | |
match('('); | |
match(')'); | |
emitLn("cpget"); | |
emitLn("jmp @"s+name); | |
emitLn("load "s + to_string(getVarID(name))); | |
} else if(look=='=') { | |
match('='); | |
expression(); | |
emitLn("store "+to_string(getVarID(name))); | |
} else { | |
emitLn("load "s + to_string(getVarID(name))); | |
} | |
} | |
void factor() { | |
if(look=='(') { | |
match('('); | |
expression(); | |
match(')'); | |
} else if(isAlpha(look)) { | |
ident(); | |
} else { | |
emitLn("push "s + getNum()); | |
} | |
} | |
void multiply() { | |
match('*'); | |
factor(); | |
emitLn("mul"); | |
} | |
void divide() { | |
match('/'); | |
emitLn("store 0"); | |
factor(); | |
emitLn("load 0"); | |
emitLn("div"); | |
} | |
void term() { | |
factor(); | |
while(isMulop(look)) { | |
switch(look) { | |
case '*': | |
multiply(); | |
break; | |
case '/': | |
divide(); | |
break; | |
default: | |
expected("Mulop"); | |
} | |
} | |
} | |
void add() { | |
match('+'); | |
term(); | |
emitLn("add"); | |
} | |
void subtract() { | |
match('-'); | |
term(); | |
emitLn("sub"); | |
emitLn("not"); | |
emitLn("[i0:arg] add 1"); | |
} | |
void expression() { | |
if(isAddop(look)) { | |
emitLn("push 0"); | |
} else | |
term(); | |
while(isAddop(look)) { | |
switch(look) { | |
case '+': | |
add(); | |
break; | |
case '-': | |
subtract(); | |
break; | |
default: | |
expected("Addop"); | |
} | |
} | |
} | |
void assignment() { | |
if(isAlpha(look)) { | |
ident(); | |
} else { | |
expression(); | |
emitLn("drop"); | |
} | |
} | |
void block(int label); | |
int condition(int blk) { | |
expression(); //First part of expression | |
string comparision=getName(); //Middle part of expression | |
expression(); //Last part of expression | |
match(':'); | |
emitLn("sub [r:discard] [f:yes] "); | |
int after=labelGen(); | |
int label=(block<0)?after:blk; | |
if(comparision=="eq") { | |
emitLn("[ex(z)=0] jmp @_L"s + to_string(after)); | |
block(label); | |
} else if(comparision=="ne") { | |
emitLn("[ex(z)=1] jmp @_L"s + to_string(after)); | |
block(label); | |
} else if(comparision=="gt") { | |
emitLn("[ex(n)=1] jmp @_L"s + to_string(after)); | |
emitLn("[ex(z)=1] jmp @_L"s + to_string(after)); | |
block(label); | |
} else if(comparision=="lt") { | |
emitLn("[ex(n)=0] jmp @_L"s + to_string(after)); | |
block(label); | |
} else { | |
expected("Comparision"); | |
} | |
return after; | |
} | |
void doIf(int blk) { | |
int after=condition(blk); | |
if(look=='!') { | |
match("!ELSE:"); | |
int afterElse=labelGen(); | |
emitLn("jmp @_L"+to_string(afterElse)); | |
cout << "_L" << after << ":\n"; | |
block(blk); | |
cout << "_L" << afterElse << ":\n"; | |
} else { | |
cout << "_L" << after << ":\n"; | |
} | |
} | |
void doWhile() { | |
int before=labelGen(); | |
cout << "_L" << before << ":\n"; | |
int after=condition(-1); | |
emitLn("jmp @_L"s+to_string(before)); | |
cout << "_L" << after << ":\n"; | |
} | |
void doLoop() { | |
int before=labelGen(); | |
int after=labelGen(); | |
cout << "_L" << before << ":\n"; | |
block(after); | |
emitLn("jmp @_L"s+to_string(before)); | |
cout << "_L" << after << ":\n"; | |
} | |
void doFor() { | |
string varname = getName(); | |
int varID = getVarID(varname); | |
int varCheck = labelGen(); | |
int after = labelGen(); | |
match('='); | |
expression(); | |
emitLn("store "s+to_string(varID)); | |
cout << "_L" << varCheck << ":\n"; | |
emitLn("load "s+to_string(varID)); | |
match("TO"); | |
expression(); | |
match(':'); | |
emitLn("[i0:arg] add 1"); | |
emitLn("sub [r:discard] [f:yes]"); | |
emitLn("[ex(n)=0] jmp @_L"s + to_string(after)); | |
block(after); | |
emitLn("load "s+to_string(varID)); | |
emitLn("[i0:arg] add 1"); | |
emitLn("store "s+to_string(varID)); | |
emitLn("jmp @_L"s+to_string(varCheck)); | |
cout << "_L" << after << ":\n"; | |
} | |
void doBreak(int lbl) { | |
if(lbl<0) | |
abort("No loop to break from"); | |
emitLn("jmp @_L"s + to_string(lbl)); | |
} | |
bool other(int block) { | |
string token=getName(); | |
if(token=="END") | |
return true; | |
if(token=="IF") | |
doIf(block); | |
if(token=="WHILE") | |
doWhile(); | |
if(token=="LOOP") | |
doLoop(); | |
if(token=="FOR") | |
doFor(); | |
if(token=="BREAK") | |
doBreak(block); | |
return false; | |
} | |
void block(int block) { | |
while(true) { | |
if(look=='%') { | |
match('%'); | |
if(other(block)) | |
return; | |
} else if (!look) | |
return; | |
else if (look=='!') | |
return; | |
else | |
assignment(); | |
} | |
} | |
bool function() { | |
match("%FUNCTION"); | |
cout << getName() << ":\n"; //Start function | |
match(':'); | |
block(-1); | |
emitLn("ret"); | |
} | |
void init() { | |
//Output standard library | |
cout << "_start:\n"; | |
emitLn("cpget"); | |
emitLn("jmp @main"); | |
emitLn("[i0:zero] syscall [ci:0]"); | |
cout << "putc:\n"; | |
emitLn("load "s+to_string(getVarID("putChar"))); | |
emitLn("[i0:pop] syscall [ci:1]"); | |
emitLn("ret"); | |
cout << "puti:\n"; | |
emitLn("load "s+to_string(getVarID("putNumber"))); | |
emitLn("[i0:pop] syscall [ci:2]"); | |
emitLn("ret"); | |
GetChar(); | |
skipWhite(); | |
} | |
int main() { | |
init(); | |
bool fin=false; | |
while(look=='%') | |
function(); | |
cout << ";Name table:\n"; | |
for(int i=0;i<nameTable.size();i++) { | |
cout << ";"<<i<<": "<<nameTable[i]<<"\n"; | |
} | |
return 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment