Skip to content

Instantly share code, notes, and snippets.

@Mtgxyz
Created June 4, 2016 19:58
Show Gist options
  • Save Mtgxyz/d177c0d3c37778b3ea6d5beda9de12c5 to your computer and use it in GitHub Desktop.
Save Mtgxyz/d177c0d3c37778b3ea6d5beda9de12c5 to your computer and use it in GitHub Desktop.
#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