2015-03-05 01:16:40 +01:00
|
|
|
/*
|
|
|
|
* Monicelli: an esoteric language compiler
|
|
|
|
*
|
|
|
|
* Copyright (C) 2014 Stefano Sanfilippo
|
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify
|
|
|
|
* it under the terms of the GNU General Public License as published by
|
|
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
|
|
* (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
* GNU General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License
|
|
|
|
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <string>
|
|
|
|
|
|
|
|
#include "Nodes.hpp"
|
|
|
|
#include "CppEmitter.hpp"
|
|
|
|
#include "Pointers.hpp"
|
|
|
|
|
|
|
|
using namespace monicelli;
|
|
|
|
|
2015-03-06 14:29:52 +01:00
|
|
|
// Yes, that's right, no ending ;
|
|
|
|
#define GUARDED(call) if (!(call)) return false
|
2015-03-05 01:16:40 +01:00
|
|
|
|
|
|
|
static const std::string STATEMENT_TERMINATOR = ";\n";
|
|
|
|
static const std::string BLOCK = " ";
|
|
|
|
|
|
|
|
|
|
|
|
void CppEmitter::indent() {
|
2015-03-05 13:55:34 +01:00
|
|
|
indent_chars += 1;
|
2015-03-05 01:16:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void CppEmitter::dedent() {
|
2015-03-05 13:55:34 +01:00
|
|
|
indent_chars -= 1;
|
2015-03-05 01:16:40 +01:00
|
|
|
}
|
|
|
|
|
2015-03-06 14:29:52 +01:00
|
|
|
bool CppEmitter::emitIndent() {
|
2015-03-05 01:16:40 +01:00
|
|
|
for (int i = 0; i < indent_chars; ++i) {
|
|
|
|
stream << BLOCK;
|
|
|
|
}
|
2015-03-06 14:29:52 +01:00
|
|
|
|
|
|
|
return stream;
|
2015-03-05 01:16:40 +01:00
|
|
|
}
|
|
|
|
|
2015-03-06 14:29:52 +01:00
|
|
|
bool CppEmitter::emit(Program const& program) {
|
2015-03-05 01:16:40 +01:00
|
|
|
for (Module m: program.getModules()) {
|
2015-03-06 14:29:52 +01:00
|
|
|
GUARDED(m.emit(this));
|
2015-03-05 01:16:40 +01:00
|
|
|
stream << "\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!program.getModules().empty()) {
|
|
|
|
stream << "\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
for (Function *function: program.getFunctions()) {
|
2015-03-08 11:25:41 +01:00
|
|
|
emit(function->getPrototype());
|
2015-03-05 01:16:40 +01:00
|
|
|
stream << ";\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!program.getFunctions().empty()) {
|
|
|
|
stream << "\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
for (Function *function: program.getFunctions()) {
|
2015-03-06 14:29:52 +01:00
|
|
|
GUARDED(function->emit(this));
|
2015-03-05 01:16:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
if (program.getMain()) {
|
2015-03-06 14:29:52 +01:00
|
|
|
GUARDED(program.getMain()->emit(this));
|
2015-03-05 01:16:40 +01:00
|
|
|
}
|
2015-03-06 14:29:52 +01:00
|
|
|
|
|
|
|
return stream;
|
2015-03-05 01:16:40 +01:00
|
|
|
}
|
|
|
|
|
2015-03-06 14:29:52 +01:00
|
|
|
bool CppEmitter::emitStatements(PointerList<Statement> const& node) {
|
2015-03-05 01:16:40 +01:00
|
|
|
for (Statement *s: node) {
|
2015-03-05 13:55:34 +01:00
|
|
|
emitIndent();
|
2015-03-06 14:29:52 +01:00
|
|
|
GUARDED(s->emit(this));
|
2015-03-05 01:16:40 +01:00
|
|
|
stream << STATEMENT_TERMINATOR;
|
|
|
|
}
|
2015-03-06 14:29:52 +01:00
|
|
|
return stream;
|
2015-03-05 01:16:40 +01:00
|
|
|
}
|
|
|
|
|
2015-03-06 14:29:52 +01:00
|
|
|
bool CppEmitter::emitMain(Function const& main) {
|
2015-03-05 01:16:40 +01:00
|
|
|
stream << "int main() {\n";
|
2015-03-05 13:55:34 +01:00
|
|
|
indent();
|
|
|
|
emitStatements(main.getBody());
|
|
|
|
dedent();
|
2015-03-05 01:16:40 +01:00
|
|
|
stream << "}\n";
|
2015-03-06 14:29:52 +01:00
|
|
|
return stream;
|
2015-03-05 01:16:40 +01:00
|
|
|
}
|
|
|
|
|
2015-03-06 14:29:52 +01:00
|
|
|
bool CppEmitter::emit(Id const& id) {
|
2015-03-05 01:16:40 +01:00
|
|
|
stream << id.getValue();
|
2015-03-06 14:29:52 +01:00
|
|
|
return stream;
|
2015-03-05 01:16:40 +01:00
|
|
|
}
|
|
|
|
|
2015-03-06 14:29:52 +01:00
|
|
|
bool CppEmitter::emit(Integer const& num) {
|
2015-03-05 01:16:40 +01:00
|
|
|
stream << num.getValue();
|
2015-03-06 14:29:52 +01:00
|
|
|
return stream;
|
2015-03-05 01:16:40 +01:00
|
|
|
}
|
|
|
|
|
2015-03-06 14:29:52 +01:00
|
|
|
bool CppEmitter::emit(Float const& num) {
|
2015-03-05 01:16:40 +01:00
|
|
|
stream << num.getValue();
|
2015-03-06 14:29:52 +01:00
|
|
|
return stream;
|
2015-03-05 01:16:40 +01:00
|
|
|
}
|
|
|
|
|
2015-03-06 14:29:52 +01:00
|
|
|
bool CppEmitter::emit(Return const& node) {
|
2015-03-05 01:16:40 +01:00
|
|
|
stream << "return";
|
|
|
|
|
|
|
|
if (node.getExpression()) {
|
|
|
|
stream << ' ';
|
2015-03-06 14:29:52 +01:00
|
|
|
GUARDED(node.getExpression()->emit(this));
|
2015-03-05 01:16:40 +01:00
|
|
|
}
|
2015-03-06 14:29:52 +01:00
|
|
|
|
|
|
|
return stream;
|
2015-03-05 01:16:40 +01:00
|
|
|
}
|
|
|
|
|
2015-03-06 14:29:52 +01:00
|
|
|
bool CppEmitter::emit(Print const& node) {
|
2015-03-05 01:16:40 +01:00
|
|
|
bool needsBraces =
|
|
|
|
(dynamic_cast<SimpleExpression const*>(&node.getExpression()) == nullptr)
|
|
|
|
&&
|
|
|
|
(dynamic_cast<FunctionCall const*>(&node.getExpression()) == nullptr)
|
|
|
|
;
|
|
|
|
|
|
|
|
stream << "std::cout << ";
|
|
|
|
if (needsBraces) {
|
|
|
|
stream << '(';
|
|
|
|
}
|
|
|
|
|
2015-03-06 14:29:52 +01:00
|
|
|
GUARDED(node.getExpression().emit(this));
|
2015-03-05 01:16:40 +01:00
|
|
|
|
|
|
|
if (needsBraces) {
|
|
|
|
stream << ')';
|
|
|
|
}
|
|
|
|
stream << " << std::endl";
|
2015-03-06 14:29:52 +01:00
|
|
|
|
|
|
|
return stream;
|
2015-03-05 01:16:40 +01:00
|
|
|
}
|
|
|
|
|
2015-03-06 14:29:52 +01:00
|
|
|
bool CppEmitter::emit(Input const& node) {
|
2015-03-05 01:16:40 +01:00
|
|
|
stream << "std::cout << \"";
|
2015-03-06 14:29:52 +01:00
|
|
|
GUARDED(node.getVariable().emit(this));
|
2015-03-05 01:16:40 +01:00
|
|
|
stream << "? \";\n";
|
2015-03-05 13:55:34 +01:00
|
|
|
emitIndent();
|
2015-03-05 01:16:40 +01:00
|
|
|
stream << "std::cin >> ";
|
2015-03-06 14:29:52 +01:00
|
|
|
GUARDED(node.getVariable().emit(this));
|
|
|
|
|
|
|
|
return stream;
|
2015-03-05 01:16:40 +01:00
|
|
|
}
|
|
|
|
|
2015-03-06 14:29:52 +01:00
|
|
|
bool CppEmitter::emit(Abort const&) {
|
2015-03-05 01:16:40 +01:00
|
|
|
stream << "std::exit(1)";
|
2015-03-06 14:29:52 +01:00
|
|
|
|
|
|
|
return stream;
|
2015-03-05 01:16:40 +01:00
|
|
|
}
|
|
|
|
|
2015-03-06 14:29:52 +01:00
|
|
|
bool CppEmitter::emit(Assert const& node) {
|
2015-03-05 01:16:40 +01:00
|
|
|
stream << "assert(";
|
2015-03-06 14:29:52 +01:00
|
|
|
GUARDED(node.getExpression().emit(this));
|
2015-03-05 01:16:40 +01:00
|
|
|
stream << ")";
|
2015-03-06 14:29:52 +01:00
|
|
|
|
|
|
|
return stream;
|
2015-03-05 01:16:40 +01:00
|
|
|
}
|
|
|
|
|
2015-03-06 14:29:52 +01:00
|
|
|
bool CppEmitter::emit(Loop const& loop) {
|
2015-03-05 01:16:40 +01:00
|
|
|
stream << "do {\n";
|
2015-03-05 13:55:34 +01:00
|
|
|
indent();
|
|
|
|
emitStatements(loop.getBody());
|
|
|
|
dedent();
|
|
|
|
emitIndent();
|
2015-03-05 01:16:40 +01:00
|
|
|
stream << "} while (";
|
2015-03-06 14:29:52 +01:00
|
|
|
GUARDED(loop.getCondition().emit(this));
|
2015-03-05 01:16:40 +01:00
|
|
|
stream << ")";
|
2015-03-06 14:29:52 +01:00
|
|
|
|
|
|
|
return stream;
|
2015-03-05 01:16:40 +01:00
|
|
|
}
|
|
|
|
|
2015-03-06 14:29:52 +01:00
|
|
|
bool CppEmitter::emitBranchCase(BranchCase const& node) {
|
2015-03-05 22:28:45 +01:00
|
|
|
emitBranchCondition(node.getCondition());
|
2015-03-05 01:16:40 +01:00
|
|
|
stream << ") {\n";
|
2015-03-05 13:55:34 +01:00
|
|
|
indent();
|
|
|
|
emitStatements(node.getBody());
|
|
|
|
dedent();
|
|
|
|
emitIndent();
|
2015-03-05 01:16:40 +01:00
|
|
|
stream << "}";
|
2015-03-06 14:29:52 +01:00
|
|
|
|
|
|
|
return stream;
|
2015-03-05 01:16:40 +01:00
|
|
|
}
|
|
|
|
|
2015-03-06 14:29:52 +01:00
|
|
|
bool CppEmitter::emit(Branch const& branch) {
|
2015-03-05 01:16:40 +01:00
|
|
|
auto &body = branch.getBody();
|
|
|
|
auto &var = branch.getVar();
|
|
|
|
|
|
|
|
stream << "if (";
|
2015-03-06 14:29:52 +01:00
|
|
|
GUARDED(var.emit(this));
|
2015-03-05 01:16:40 +01:00
|
|
|
|
|
|
|
if (body.getCases().size() > 0) {
|
|
|
|
BranchCase *last = body.getCases().back();
|
|
|
|
for (BranchCase *cas: body.getCases()) {
|
2015-03-05 22:28:45 +01:00
|
|
|
emitBranchCase(*cas);
|
2015-03-05 01:16:40 +01:00
|
|
|
if (cas != last) {
|
|
|
|
stream << " else if (";
|
2015-03-06 14:29:52 +01:00
|
|
|
GUARDED(var.emit(this));
|
2015-03-05 01:16:40 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!body.getElse()) {
|
2015-03-06 14:29:52 +01:00
|
|
|
return stream;
|
2015-03-05 01:16:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
stream << " else {\n";
|
2015-03-05 13:55:34 +01:00
|
|
|
indent();
|
|
|
|
emitStatements(*body.getElse());
|
|
|
|
dedent();
|
|
|
|
emitIndent();
|
2015-03-05 01:16:40 +01:00
|
|
|
stream << "}";
|
2015-03-06 14:29:52 +01:00
|
|
|
|
|
|
|
return stream;
|
2015-03-05 01:16:40 +01:00
|
|
|
}
|
|
|
|
|
2015-03-06 14:29:52 +01:00
|
|
|
bool CppEmitter::emit(Assignment const& assignment) {
|
|
|
|
GUARDED(assignment.getName().emit(this));
|
2015-03-05 01:16:40 +01:00
|
|
|
stream << " = ";
|
2015-03-06 14:29:52 +01:00
|
|
|
GUARDED(assignment.getValue().emit(this));
|
|
|
|
|
|
|
|
return stream;
|
2015-03-05 01:16:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-03-06 14:29:52 +01:00
|
|
|
bool CppEmitter::emitFunctionArglist(PointerList<Expression> const& args) {
|
2015-03-05 01:16:40 +01:00
|
|
|
Expression *last = args.back();
|
|
|
|
for (Expression const* arg: args) {
|
2015-03-06 14:29:52 +01:00
|
|
|
GUARDED(arg->emit(this));
|
2015-03-05 01:16:40 +01:00
|
|
|
if (arg != last) {
|
|
|
|
stream << ", ";
|
|
|
|
}
|
|
|
|
}
|
2015-03-06 14:29:52 +01:00
|
|
|
|
|
|
|
return stream;
|
2015-03-05 01:16:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2015-03-06 14:29:52 +01:00
|
|
|
bool CppEmitter::emit(FunctionCall const& funcall) {
|
|
|
|
GUARDED(funcall.getName().emit(this));
|
2015-03-05 01:16:40 +01:00
|
|
|
stream << "(";
|
|
|
|
emitFunctionArglist(funcall.getArgs());
|
|
|
|
stream << ")";
|
2015-03-06 14:29:52 +01:00
|
|
|
|
|
|
|
return stream;
|
2015-03-05 01:16:40 +01:00
|
|
|
}
|
|
|
|
|
2015-03-06 14:29:52 +01:00
|
|
|
bool CppEmitter::emit(Function const& function) {
|
2015-03-08 11:25:41 +01:00
|
|
|
emit(function.getPrototype());
|
2015-03-05 01:16:40 +01:00
|
|
|
stream << " {\n";
|
2015-03-05 13:55:34 +01:00
|
|
|
indent();
|
|
|
|
emitStatements(function.getBody());
|
|
|
|
dedent();
|
2015-03-05 01:16:40 +01:00
|
|
|
stream << "}\n\n";
|
2015-03-06 14:29:52 +01:00
|
|
|
|
|
|
|
return stream;
|
2015-03-05 01:16:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
std::ostream& operator<<(std::ostream &stream, Type const& type) {
|
|
|
|
switch (type) {
|
|
|
|
case Type::INT:
|
|
|
|
stream << "int";
|
|
|
|
break;
|
|
|
|
case Type::CHAR:
|
|
|
|
stream << "char";
|
|
|
|
break;
|
|
|
|
case Type::FLOAT:
|
|
|
|
stream << "float";
|
|
|
|
break;
|
|
|
|
case Type::BOOL:
|
|
|
|
stream << "bool";
|
|
|
|
break;
|
|
|
|
case Type::DOUBLE:
|
|
|
|
stream << "double";
|
|
|
|
break;
|
|
|
|
case Type::VOID:
|
|
|
|
stream << "void";
|
|
|
|
break;
|
2015-03-07 14:03:07 +01:00
|
|
|
case Type::UNKNOWN:
|
|
|
|
stream << "???????????";
|
|
|
|
break;
|
2015-03-05 01:16:40 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
return stream;
|
|
|
|
}
|
|
|
|
|
2015-03-06 14:29:52 +01:00
|
|
|
bool CppEmitter::emitFunctionParams(PointerList<FunArg> const& funargs) {
|
2015-03-05 01:16:40 +01:00
|
|
|
FunArg *last = funargs.back();
|
|
|
|
|
|
|
|
for (FunArg const* funarg: funargs) {
|
|
|
|
stream << funarg->getType() << (funarg->isPointer()? "* ": " ");
|
2015-03-06 14:29:52 +01:00
|
|
|
GUARDED(funarg->getName().emit(this));
|
2015-03-05 01:16:40 +01:00
|
|
|
if (funarg != last) {
|
|
|
|
stream << ", ";
|
|
|
|
}
|
|
|
|
}
|
2015-03-06 14:29:52 +01:00
|
|
|
|
|
|
|
return stream;
|
2015-03-05 01:16:40 +01:00
|
|
|
}
|
|
|
|
|
2015-03-06 14:29:52 +01:00
|
|
|
bool CppEmitter::emit(Module const& module) {
|
2015-03-05 01:16:40 +01:00
|
|
|
bool system = (module.getType() == Module::SYSTEM);
|
|
|
|
stream << "#include " << (system? '<': '"') << module.getName() << (system? '>': '"');
|
2015-03-06 14:29:52 +01:00
|
|
|
|
|
|
|
return stream;
|
2015-03-05 01:16:40 +01:00
|
|
|
}
|
|
|
|
|
2015-03-08 11:25:41 +01:00
|
|
|
bool CppEmitter::emit(FunctionPrototype const& proto) {
|
|
|
|
stream << proto.getType() << ' ';
|
|
|
|
GUARDED(proto.getName().emit(this));
|
2015-03-05 01:16:40 +01:00
|
|
|
stream << "(";
|
2015-03-08 11:25:41 +01:00
|
|
|
emitFunctionParams(proto.getArgs());
|
2015-03-05 01:16:40 +01:00
|
|
|
stream << ")";
|
2015-03-06 14:29:52 +01:00
|
|
|
|
|
|
|
return stream;
|
2015-03-05 01:16:40 +01:00
|
|
|
}
|
|
|
|
|
2015-03-06 14:29:52 +01:00
|
|
|
bool CppEmitter::emit(VarDeclaration const& decl) {
|
2015-03-05 01:16:40 +01:00
|
|
|
stream << decl.getType() << ' ';
|
|
|
|
if (decl.isPointer()) stream << '*';
|
2015-03-06 14:29:52 +01:00
|
|
|
GUARDED(decl.getId().emit(this));
|
2015-03-05 01:16:40 +01:00
|
|
|
|
|
|
|
if (decl.getInitializer()) {
|
|
|
|
stream << " = ";
|
2015-03-06 14:29:52 +01:00
|
|
|
GUARDED(decl.getInitializer()->emit(this));
|
2015-03-05 01:16:40 +01:00
|
|
|
}
|
2015-03-06 14:29:52 +01:00
|
|
|
|
|
|
|
return stream;
|
2015-03-05 01:16:40 +01:00
|
|
|
}
|
|
|
|
|
2015-03-05 17:25:02 +01:00
|
|
|
std::ostream& operator<<(std::ostream &stream, Operator op) {
|
|
|
|
switch (op) {
|
|
|
|
case Operator::PLUS:
|
|
|
|
stream << '+';
|
|
|
|
break;
|
|
|
|
case Operator::MINUS:
|
|
|
|
stream << '-';
|
|
|
|
break;
|
|
|
|
case Operator::TIMES:
|
|
|
|
stream << '*';
|
|
|
|
break;
|
|
|
|
case Operator::DIV:
|
|
|
|
stream << '/';
|
|
|
|
break;
|
|
|
|
case Operator::SHL:
|
|
|
|
stream << "<<";
|
|
|
|
break;
|
|
|
|
case Operator::SHR:
|
|
|
|
stream << ">>";
|
|
|
|
break;
|
|
|
|
case Operator::LT:
|
|
|
|
stream << '<';
|
|
|
|
break;
|
|
|
|
case Operator::GT:
|
|
|
|
stream << '>';
|
|
|
|
break;
|
|
|
|
case Operator::GTE:
|
|
|
|
stream << ">=";
|
|
|
|
break;
|
|
|
|
case Operator::LTE:
|
|
|
|
stream << "<=";
|
|
|
|
break;
|
|
|
|
case Operator::EQ:
|
|
|
|
stream << "==";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return stream;
|
|
|
|
}
|
|
|
|
|
2015-03-06 14:29:52 +01:00
|
|
|
bool CppEmitter::emit(BinaryExpression const& node) {
|
|
|
|
GUARDED(node.getLeft().emit(this));
|
2015-03-05 17:25:02 +01:00
|
|
|
stream << ' ' << node.getOperator() << ' ';
|
2015-03-06 14:29:52 +01:00
|
|
|
GUARDED(node.getRight().emit(this));
|
|
|
|
|
|
|
|
return stream;
|
2015-03-05 01:16:40 +01:00
|
|
|
}
|
|
|
|
|
2015-03-06 14:29:52 +01:00
|
|
|
bool CppEmitter::emitBranchCondition(SemiExpression const& node) {
|
2015-03-05 01:16:40 +01:00
|
|
|
bool braces = (dynamic_cast<SimpleExpression const*>(&node.getLeft()) == nullptr);
|
|
|
|
|
2015-03-05 17:25:02 +01:00
|
|
|
stream << ' ' << node.getOperator() << ' ';
|
2015-03-05 01:16:40 +01:00
|
|
|
if (braces) stream << "(";
|
2015-03-06 14:29:52 +01:00
|
|
|
GUARDED(node.getLeft().emit(this));
|
2015-03-05 01:16:40 +01:00
|
|
|
if (braces) stream << ")";
|
2015-03-06 14:29:52 +01:00
|
|
|
|
|
|
|
return stream;
|
2015-03-05 01:16:40 +01:00
|
|
|
}
|
|
|
|
|