Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

7160 lines (6552 sloc) 188.551 kb
// winxedst0.cpp
// Revision 29-apr-2012
// Winxed compiler stage 0.
#include "token.h"
#include "errors.h"
#include "emit.h"
#include <string>
#include <iostream>
#include <istream>
#include <fstream>
#include <sstream>
#include <cctype>
#include <vector>
#include <map>
#include <algorithm>
#include <stdexcept>
#include <string.h>
#include <errno.h>
#include <typeinfo>
//**********************************************************************
// Register types
const char REGint = 'I';
const char REGfloat = 'N';
const char REGstring = 'S';
const char REGvar = 'P';
// Pseudotypes for predefined functions
const char REGany = '?';
const char REGnone = '\0'; // void return
static const char * nameoftype(char ctype)
{
switch (ctype)
{
case REGint: return "int";
case REGfloat: return "num";
case REGstring: return "string";
case REGvar: return "pmc";
default:
throw CompileError("Invalid type");
}
}
char nativetype(const Token &name)
{
if (name.iskeyword("int")) return REGint;
else if (name.iskeyword("float")) return REGfloat;
else if (name.iskeyword("string")) return REGstring;
else if (name.iskeyword("var")) return REGvar;
else return '\0';
}
//**********************************************************************
#define INDENT " "
#define INDENTLABEL " "
inline
std::string op(const char *name, const std::string &op1)
{
return INDENT + std::string(name) + ' ' + op1;
}
inline
std::string op(const char *name,
const std::string &op1, const std::string &op2)
{
return INDENT + std::string(name) + ' ' + op1 + ", " + op2;
}
inline
std::string op(const char *name,
const std::string &op1,
const std::string &op2, const std::string &op3)
{
return INDENT + std::string(name) + ' ' + op1 + ", " + op2 + ", " + op3;
}
inline
std::string op_inc(const std::string &op1)
{
return op("inc", op1);
}
inline
std::string op_dec(const std::string &op1)
{
return op("dec", op1);
}
inline
std::string op_set(const std::string &res, const std::string &op1)
{
return op("set", res, op1);
}
inline
std::string op_assign(const std::string &res, const std::string &op1)
{
return op("assign", res, op1);
}
inline
std::string op_box(const std::string &res, const std::string &op1)
{
return op("box", res, op1);
}
inline
std::string op_add(const std::string &res,
const std::string &op1, const std::string &op2)
{
return op("add", res, op1, op2);
}
inline
std::string op_sub(const std::string &res,
const std::string &op1, const std::string &op2)
{
return op("sub", res, op1, op2);
}
inline
std::string op_mul(const std::string &res,
const std::string &op1, const std::string &op2)
{
return op("mul", res, op1, op2);
}
inline
std::string op_div(const std::string &res,
const std::string &op1, const std::string &op2)
{
return op("div", res, op1, op2);
}
inline
std::string op_mod(const std::string &res,
const std::string &op1, const std::string &op2)
{
return op("mod", res, op1, op2);
}
inline
std::string op_cmod(const std::string &res,
const std::string &op1, const std::string &op2)
{
return op("cmod", res, op1, op2);
}
inline
std::string op_null(const std::string &res)
{
return op("null", res);
}
inline
std::string op_isnull(const std::string &res, const std::string &op1)
{
return op("isnull", res, op1);
}
inline
std::string op_iseq(const std::string &res,
const std::string &op1, const std::string &op2)
{
return op("iseq", res, op1, op2);
}
inline
std::string op_isne(const std::string &res,
const std::string &op1, const std::string &op2)
{
return op("isne", res, op1, op2);
}
inline
std::string op_islt(const std::string &res,
const std::string &op1, const std::string &op2)
{
return op("islt", res, op1, op2);
}
inline
std::string op_isgt(const std::string &res,
const std::string &op1, const std::string &op2)
{
return op("isgt", res, op1, op2);
}
inline
std::string op_isle(const std::string &res,
const std::string &op1, const std::string &op2)
{
return op("isle", res, op1, op2);
}
inline
std::string op_isge(const std::string &res,
const std::string &op1, const std::string &op2)
{
return op("isge", res, op1, op2);
}
inline
std::string op_isa(const std::string &res,
const std::string &op1, const std::string &op2)
{
return op("isa", res, op1, op2);
}
//**********************************************************************
inline void RequireOp(char name, const Token &t)
{
if (! t.isop(name) )
throw Expected (name, t);
}
inline void ExpectOp(char name, Tokenizer &tk)
{
Token t= tk.get();
RequireOp(name, t);
}
//**********************************************************************
template <typename T>
void emit_group(const std::vector<T *> &group, Emit &e)
{
for (size_t i= 0; i < group.size(); ++i)
group[i]->emit(e);
}
//**********************************************************************
class PredefFunction
{
public:
static const int VarArgs = -1;
PredefFunction(const std::string &name, char typeresult, int nargs) :
pname(name),
tresult(typeresult),
n(nargs)
{
}
PredefFunction(const std::string &name, char typeresult) :
pname(name),
tresult(typeresult),
n(VarArgs)
{
}
static const PredefFunction *find(const std::string &name,
size_t numargs);
bool name_is(const std::string &name) const
{ return pname == name; }
size_t numargs() const { return n; }
char resulttype() const { return tresult; }
virtual char paramtype(size_t n) const = 0;
virtual void emit(Emit &e, const std::string &result,
const std::vector<std::string> args) const = 0;
private:
static const PredefFunction *predefs[];
static const size_t numpredefs;
const std::string pname;
char tresult;
unsigned int n;
};
class PredefFunctionFixargs : public PredefFunction
{
public:
PredefFunctionFixargs(const std::string &name,
const std::string &body,
char typeresult,
char type0= '\0',
char type1= '\0',
char type2= '\0',
char type3= '\0');
private:
void emit(Emit &e, const std::string &result,
const std::vector<std::string> args) const;
char paramtype(size_t n) const
{
switch(n)
{
case 0: return t0;
case 1: return t1;
case 2: return t2;
case 3: return t3;
default: return '\0';
}
}
char t0, t1, t2, t3;
std::vector<std::string> chunks;
std::vector<int> marks;
};
class PredefFunctionVarargs : public PredefFunction
{
protected:
PredefFunctionVarargs(const std::string &name,
char typeresult) :
PredefFunction(name, typeresult)
{ }
char paramtype(size_t /*unused*/) const
{
return REGany;
}
};
class Predef_print : public PredefFunctionVarargs
{
public:
Predef_print() : PredefFunctionVarargs("print", REGnone)
{ }
private:
void emit(Emit &e, const std::string &,
const std::vector<std::string> args) const
{
const size_t n = args.size();
for (size_t i= 0; i < n; ++i)
e << INDENT "print " << args[i] << '\n';
}
};
class Predef_say : public PredefFunctionVarargs
{
public:
Predef_say() : PredefFunctionVarargs("say", REGnone)
{ }
private:
void emit(Emit &e, const std::string &,
const std::vector<std::string> args) const
{
const size_t n = args.size();
if (n > 0) {
for (size_t i= 0; i < n - 1; ++i)
e << INDENT "print " << args[i] << '\n';
e << INDENT "say " << args[n-1] << '\n';
}
else
e << INDENT "say ''\n";
}
};
class Predef_cry : public PredefFunctionVarargs
{
public:
Predef_cry() : PredefFunctionVarargs("cry", REGnone)
{ }
private:
void emit(Emit &e, const std::string &,
const std::vector<std::string> args) const
{
e <<
INDENT "getstderr $P0\n";
const size_t n = args.size();
for (size_t i= 0; i < n; ++i)
e << INDENT "$P0.'print'(" << args[i] << ")\n";
e << INDENT "$P0.'print'(\"\\n\")\n";
}
};
class Predef_ASSERT : public PredefFunction
{
public:
Predef_ASSERT() : PredefFunction("__ASSERT__", REGnone, 1)
{ }
char paramtype(size_t n) const { return REGint; }
void emit(Emit &e, const std::string &,
const std::vector<std::string> args) const
{
if (e.getDebug())
{
e <<
INDENT ".const 'Sub' __WINXED_ASSERT_check ='__WINXED_ASSERT_check'\n"
INDENT "__WINXED_ASSERT_check(" << args[0] << ")\n";
}
}
};
const PredefFunction *PredefFunction::predefs[]= {
new Predef_ASSERT(),
new Predef_print(),
new Predef_say(),
new Predef_cry(),
new PredefFunctionFixargs("int",
"{res} = {arg0}",
REGint, REGany),
new PredefFunctionFixargs("string",
"{res} = {arg0}",
REGstring, REGany),
new PredefFunctionFixargs("exit",
"exit {arg0}",
REGnone, REGint),
new PredefFunctionFixargs("spawnw",
"spawnw {res}, {arg0}",
REGint, REGvar),
new PredefFunctionFixargs("getstdin",
"getstdin {res}",
REGvar),
new PredefFunctionFixargs("getstdout",
"getstdout {res}",
REGvar),
new PredefFunctionFixargs("getstderr",
"getstderr {res}",
REGvar),
new PredefFunctionFixargs("open",
"root_new {res}, ['parrot';'FileHandle']\n"
"{res}.'open'({arg0})",
REGvar, REGstring),
new PredefFunctionFixargs("open",
"root_new {res}, ['parrot';'FileHandle']\n"
"{res}.'open'({arg0},{arg1})",
REGvar, REGstring, REGstring),
new PredefFunctionFixargs("Error",
"root_new {res}, ['parrot';'Exception']\n"
"{res}['message'] = {arg0}\n"
, REGvar, REGstring),
new PredefFunctionFixargs("Error",
"root_new {res}, ['parrot';'Exception']\n"
"{res}['message'] = {arg0}\n"
"{res}['severity'] = {arg1}\n"
, REGvar, REGstring, REGint),
new PredefFunctionFixargs("Error",
"root_new {res}, ['parrot';'Exception']\n"
"{res}['message'] = {arg0}\n"
"{res}['severity'] = {arg1}\n"
"{res}['type'] = {arg2}\n"
, REGvar, REGstring, REGint, REGint),
new PredefFunctionFixargs("Error",
"root_new {res}, ['parrot';'Exception']\n"
"{res}['message'] = {arg0}\n"
"{res}['severity'] = {arg1}\n"
"{res}['type'] = {arg2}\n"
"{res}['payload'] = {arg3}\n"
, REGvar, REGstring, REGint, REGint, REGvar),
new PredefFunctionFixargs("elements",
"elements {res}, {arg0}",
REGint, REGvar),
new PredefFunctionFixargs("length",
"length {res}, {arg0}",
REGint, REGstring),
new PredefFunctionFixargs("bytelength",
"bytelength {res}, {arg0}",
REGint, REGstring),
new PredefFunctionFixargs("chr",
"chr $S0, {arg0}\n"
"find_encoding $I0, 'utf8'\n"
"trans_encoding {res}, $S0, $I0\n",
REGstring, REGint),
new PredefFunctionFixargs("ord",
"ord {res}, {arg0}",
REGint, REGstring),
new PredefFunctionFixargs("ord",
"ord {res}, {arg0}, {arg1}",
REGint, REGstring, REGint),
new PredefFunctionFixargs("substr",
"substr {res}, {arg0}, {arg1}",
REGstring, REGstring, REGint),
new PredefFunctionFixargs("substr",
"substr {res}, {arg0}, {arg1}, {arg2}",
REGstring, REGstring, REGint, REGint),
new PredefFunctionFixargs("replace",
"replace {res}, {arg0}, {arg1}, {arg2}, {arg3}",
REGstring, REGstring, REGint, REGint, REGstring),
new PredefFunctionFixargs("indexof",
"index {res}, {arg0}, {arg1}",
REGint, REGstring, REGstring),
new PredefFunctionFixargs("indexof",
"index {res}, {arg0}, {arg1}, {arg2}",
REGint, REGstring, REGstring, REGint),
new PredefFunctionFixargs("escape",
"escape {res}, {arg0}",
REGstring, REGstring),
new PredefFunctionFixargs("unescape",
"$P0 = new ['String']\n"
"$P0 = {arg0}\n"
"{res} = $P0.'unescape'('utf8')\n",
REGstring, REGstring),
new PredefFunctionFixargs("unescape",
"$P0 = new ['String']\n"
"$P0 = {arg0}\n"
"{res} = $P0.'unescape'({arg1})\n",
REGstring, REGstring, REGstring),
new PredefFunctionFixargs("upcase",
"upcase {res}, {arg0}",
REGstring, REGstring),
new PredefFunctionFixargs("downcase",
"downcase {res}, {arg0}",
REGstring, REGstring),
new PredefFunctionFixargs("titlecase",
"titlecase {res}, {arg0}",
REGstring, REGstring),
new PredefFunctionFixargs("join",
"join {res}, {arg0}, {arg1}",
REGstring, REGstring, REGvar),
new PredefFunctionFixargs("split",
"split {res}, {arg0}, {arg1}",
REGvar, REGstring, REGstring),
new PredefFunctionFixargs("push",
"push {arg0}, {arg1}",
REGnone, REGvar, REGany),
new PredefFunctionFixargs("getinterp",
"getinterp {res}",
REGvar),
new PredefFunctionFixargs("get_class",
"get_class {res}, {arg0}",
REGvar, REGstring),
new PredefFunctionFixargs("typeof",
"typeof {res}, {arg0}",
REGvar, REGvar),
new PredefFunctionFixargs("clone",
"clone {res}, {arg0}",
REGvar, REGvar),
new PredefFunctionFixargs("compreg",
"compreg {res}, {arg0}",
REGvar, REGstring),
new PredefFunctionFixargs("compreg",
"compreg {arg0}, {arg1}",
REGnone, REGstring, REGvar),
new PredefFunctionFixargs("load_language",
"load_language {arg0}\n"
"compreg {res}, {arg0}",
REGvar, REGstring),
new PredefFunctionFixargs("load_language",
"load_language {arg0}\n"
"compreg {res}, {arg1}",
REGvar, REGstring, REGstring),
new PredefFunctionFixargs("loadlib",
"loadlib {res}, {arg0}",
REGvar, REGstring),
new PredefFunctionFixargs("load_bytecode",
"load_bytecode {arg0}",
REGvar, REGstring),
new PredefFunctionFixargs("sprintf",
"sprintf {res}, {arg0}, {arg1}",
REGstring, REGstring, REGvar)
};
const size_t PredefFunction::numpredefs =
sizeof(PredefFunction::predefs) / sizeof(PredefFunction::predefs[0]);
const PredefFunction *PredefFunction::find(const std::string &name,
size_t numargs)
{
for (size_t i= 0; i < numpredefs; ++i) {
int n = predefs[i]->n;
if ((n == PredefFunction::VarArgs || n == int(numargs)) &&
predefs[i]->name_is(name) )
return predefs[i];
}
return 0;
}
PredefFunctionFixargs::PredefFunctionFixargs(const std::string &name,
const std::string &body,
char typeresult,
char type0, char type1, char type2, char type3) :
PredefFunction(name, typeresult,
bool(type0) +bool(type1) + bool(type2) + bool(type3) ),
t0(type0), t1(type1), t2(type2), t3(type3)
{
const size_t ntags = 5;
const std::string tags[ntags] =
{ "{res}", "{arg0}", "{arg1}", "{arg2}", "{arg3}" };
std::string::size_type pos[ntags];
std::string aux = body;
for (;;)
{
for (size_t i = 0; i < ntags; ++i)
pos[i] = aux.find(tags[i]);
const std::string::size_type *minp = std::min_element(pos, pos + ntags);
size_t minpos = minp - pos;
std::string::size_type mpos = pos[minpos];
if (mpos == std::string::npos)
break;
chunks.push_back(aux.substr(0, mpos));
marks.push_back(minpos);
aux.erase(0, mpos + tags[minpos].length());
}
if (aux.length() > 0)
{
chunks.push_back(aux);
marks.push_back(-1);
}
}
void PredefFunctionFixargs::emit(Emit &e, const std::string &result,
const std::vector<std::string> args) const
{
std::string body;
size_t n = chunks.size();
for (size_t i = 0; i < n; ++i)
{
body+= chunks[i];
int m = marks[i];
switch (m)
{
case 0:
body+= result;
break;
case 1: case 2: case 3: case 4:
body+= args[m-1];
break;
case -1:
break;
default:
throw InternalError("Unexpected failure in Predef");
}
}
size_t pos = 0;
size_t prev = 0;
while ((pos = body.find("\n", prev)) != std::string::npos)
{
e << INDENT << body.substr(prev, pos - prev + 1);
prev = pos + 1;
}
e << INDENT << body.substr(prev) << '\n';
}
//**********************************************************************
class ConstantValue
{
public:
ConstantValue(char type, const Token &value) :
t(type), v(value)
{
switch(t)
{
case REGint:
if (!v.isinteger())
throw SyntaxError("Invalid const int value", v);
break;
case REGstring:
if (!v.isliteralstring())
throw SyntaxError("Invalid const string value", v);
break;
case 'n':
// Special case
if (!v.isidentifier())
throw SyntaxError("Invalid const string value", v);
break;
default:
throw InternalError("Invalid const type");
}
}
char type() const { return t; }
Token value() const { return v; }
private:
char t;
Token v;
};
//**********************************************************************
class ClassStatement;
typedef std::vector<std::string> ClassKey;
std::string dotted(const ClassKey &ck)
{
size_t l = ck.size();
if (l == 0)
return "(anonimous)";
else
{
std::string r = ck[0];
for (size_t i = 1; i < l; ++i)
{
r+= '.';
r+= ck[i];
}
return r;
}
}
//**********************************************************************
class FunctionStatement;
class BlockBase
{
public:
virtual char checklocal(const std::string &name) const = 0;
virtual char checkconstant(const std::string &name) const = 0;
virtual ConstantValue getconstant(const std::string &name) const = 0;
virtual FunctionStatement *getfunction(const std::string &name) const = 0;
virtual void genconstant(const std::string &name, char type, const Token &value) = 0;
virtual std::string genlocallabel() = 0;
virtual std::string genlocalregister(char type)= 0;
virtual void freelocalregister(const std::string &)= 0;
virtual std::string gentemp(char /*unused*/)
{
throw std::runtime_error("No temp registers here!");
}
virtual void freetempregs()
{
throw std::runtime_error("No temp registers here!");
}
virtual void genlocal(const std::string &name, char type) = 0;
virtual bool islocal(std::string /*name*/) const = 0;
virtual std::string getbreaklabel() const
{
throw std::runtime_error("No break allowed");
}
virtual std::string getcontinuelabel() const
{
throw std::runtime_error("No continue allowed");
}
virtual ClassStatement *findclass(const ClassKey &classkey)
{
std::cerr << "BlockBase::findclass **WRONG CALL**\n";
return 0;
}
virtual ~BlockBase() { }
};
class Block : public BlockBase
{
public:
Block();
virtual unsigned int blockid() = 0;
void genlocal(const std::string &name, char type);
bool islocal(std::string name) const;
void genconstant(const std::string &name, char type, const Token &value);
char checklocal(const std::string &name) const;
char checkconstant(const std::string &name) const;
ConstantValue getconstant(const std::string &name) const;
std::string genlabel();
protected:
typedef std::map<std::string, char> Locals;
Locals locals;
typedef std::map<std::string, ConstantValue> Constants;
Constants constants;
};
class InBlock : public BlockBase
{
protected:
InBlock(BlockBase &block) : bl(block) { };
public:
std::string getbreaklabel() const
{
return bl.getbreaklabel();
}
std::string getcontinuelabel() const
{
return bl.getcontinuelabel();
}
char checklocal(const std::string &name) const
{
return bl.checklocal(name);
}
char checkconstant(const std::string &name) const
{
return bl.checkconstant(name);
}
void genconstant(const std::string &name, char type, const Token &value)
{
bl.genconstant(name, type, value);
}
ConstantValue getconstant(const std::string &name) const
{
return bl.getconstant(name);
}
FunctionStatement *getfunction(const std::string &name) const
{
return bl.getfunction(name);
}
std::string genlocallabel()
{
return bl.genlocallabel();
}
std::string genlocalregister(char type)
{
return bl.genlocalregister(type);
}
void freelocalregister(const std::string &reg)
{
bl.freelocalregister(reg);
}
std::string gentemp(char type)
{
return bl.gentemp(type);
}
void freetempregs()
{
bl.freetempregs();
}
void genlocal(const std::string &name, char type)
{
bl.genlocal(name, type);
}
bool islocal(std::string name) const
{
return bl.islocal(name);
}
ClassStatement *findclass(const ClassKey &classkey)
{
return bl.findclass(classkey);
}
private:
BlockBase &bl;
};
Block::Block()
{ }
void Block::genlocal(const std::string &name, char type)
{
locals[name]= type;
}
bool Block::islocal(std::string name) const
{
return locals.find(name) != locals.end();
}
void Block::genconstant(const std::string &name, char type, const Token &value)
{
constants.insert(std::make_pair(name, ConstantValue(type, value)));
}
char Block::checklocal(const std::string &name) const
{
Locals::const_iterator it= locals.find(name);
if (it != locals.end() )
return it->second;
Constants::const_iterator itc= constants.find(name);
if (itc != constants.end() )
return itc->second.type();
return '\0';
}
char Block::checkconstant(const std::string &name) const
{
Constants::const_iterator itc= constants.find(name);
if (itc != constants.end() )
return itc->second.type();
return '\0';
}
ConstantValue Block::getconstant(const std::string &name) const
{
Constants::const_iterator itc= constants.find(name);
if (itc != constants.end() )
return itc->second;
throw InternalError("No such constant");
}
std::string Block::genlabel()
{
return genlocallabel();
}
//**********************************************************************
class SubBlock : public Block
{
public:
SubBlock(Block &parentblock) :
parent(parentblock),
id(parent.blockid()),
nlabel(0)
{
}
std::string getbreaklabel() const;
std::string getcontinuelabel() const;
bool islocal(std::string name) const;
char checklocal(const std::string &name) const;
char checkconstant(const std::string &name) const;
ConstantValue getconstant(const std::string &name) const;
FunctionStatement *getfunction(const std::string &name) const
{
return parent.getfunction(name);
}
std::string genlocalregister(char type)
{
return parent.genlocalregister(type);
}
void freelocalregister(const std::string &reg)
{
parent.freelocalregister(reg);
}
std::string gentemp(char type)
{
return parent.gentemp(type);
}
void freetempregs()
{
parent.freetempregs();
}
std::string genlocallabel();
ClassStatement *findclass(const ClassKey &classkey)
{
return parent.findclass(classkey);
}
private:
unsigned int blockid();
Block &parent;
unsigned int id;
unsigned int nlabel;
};
unsigned int SubBlock::blockid()
{
return parent.blockid();
}
std::string SubBlock::getbreaklabel() const
{
return parent.getbreaklabel();
}
std::string SubBlock::getcontinuelabel() const
{
return parent.getcontinuelabel();
}
char SubBlock::checklocal(const std::string &name) const
{
if (char c= Block::checklocal(name))
return c;
else
return parent.checklocal(name);
}
bool SubBlock::islocal(std::string name) const
{
return checklocal(name) != '\0';
}
char SubBlock::checkconstant(const std::string &name) const
{
//std::cerr << "SubBlock::checkconstant\n";
char c= Block::checkconstant(name);
if (c == '\0')
c= parent.checkconstant(name);
//std::cerr << "SubBlock::checkconstant end\n";
return c;
}
ConstantValue SubBlock::getconstant(const std::string &name) const
{
//std::cerr << "SubBlock::getconstant\n";
if (Block::checkconstant(name))
return Block::getconstant(name);
else
return parent.getconstant(name);
//std::cerr << "SubBlock::getconstant end\n";
}
std::string SubBlock::genlocallabel()
{
std::ostringstream l;
l << "__label_" << id << '_' << ++nlabel;
return l.str();
}
//**********************************************************************
class NamespaceKey
{
public:
NamespaceKey() { }
NamespaceKey(const NamespaceKey &parent, const std::string &name) :
key(parent.key)
{
key.push_back(name);
}
bool isroot() const
{
return key.empty();
}
NamespaceKey parent() const
{
NamespaceKey newparent(*this);
newparent.key.pop_back();
return newparent;
}
std::string getid() const
{
std::string r= "__Id";
for (size_t i= 0; i < key.size(); ++i)
r+= '_' + key [i];
return r;
}
std::string get_key() const
{
std::string r= "[ ";
for (size_t i= 0; i < key.size(); ++i)
{
if (i > 0)
r+= "; ";
r+= '\'' + key [i] + '\'';
}
r+= " ]";
return r;
}
void emit (Emit &e) const
{
e << ".namespace " << get_key() << '\n';
}
private:
std::vector <std::string> key;
NamespaceKey *parentns;
};
//**********************************************************************
class FunctionBlock : public SubBlock
{
public:
FunctionBlock(Block &parent) :
SubBlock(parent),
subblocks(0),
nreg(0), nlabel(0)
{
}
public:
std::string genlocallabel();
std::string genlocalregister(char type);
std::string gentemp(char type);
std::string genregister(char type);
void freelocalregister(const std::string &reg);
void freeregister(const std::string &reg);
protected:
size_t tempsused() const
{
return tempi.size() + temps.size() + tempp.size() +
+ freetempi.size() + freetemps.size() + freetempp.size();
}
void freetempregs()
{
using std::copy;
using std::back_inserter;
copy(tempi.begin(), tempi.end(), back_inserter(freetempi));
tempi= std::vector<std::string>();
copy(temps.begin(), temps.end(), back_inserter(freetemps));
temps= std::vector<std::string>();
copy(tempp.begin(), tempp.end(), back_inserter(freetempp));
tempp= std::vector<std::string>();
}
private:
unsigned int subblocks;
unsigned int nreg;
unsigned int nlabel;
std::vector <std::string> tempi;
std::vector <std::string> temps;
std::vector <std::string> tempp;
std::vector <std::string> freetempi;
std::vector <std::string> freetemps;
std::vector <std::string> freetempp;
};
std::string FunctionBlock::genlocalregister(char type)
{
if (type != REGint && type != REGstring && type != REGvar)
throw InternalError("invalid register type");
std::ostringstream l;
l << '$' << type << ++nreg;
return l.str();
}
void FunctionBlock::freelocalregister(const std::string &reg)
{
//std::cerr << "Free " << reg << "!\n";
if (reg.at(0) != '$')
throw InternalError("invalid free register");
switch(reg.at(1))
{
case REGint: freetempi.push_back(reg); break;
case REGstring: freetemps.push_back(reg); break;
case REGvar: freetempp.push_back(reg); break;
default: throw InternalError("invalid free register");
}
}
void FunctionBlock::freeregister(const std::string &reg)
{
return freelocalregister(reg);
}
std::string FunctionBlock::genregister(char type)
{
return genlocalregister(type);
}
std::string FunctionBlock::gentemp(char type)
{
std::vector<std::string> &usefree= type == REGint ? freetempi :
type == REGstring ? freetemps : freetempp;
std::string temp;
if (usefree.size() > 0)
{
temp= usefree.back();
usefree.pop_back();
}
else
{
temp= genlocalregister(type);
switch(type)
{
case REGint: tempi.push_back(temp); break;
case REGstring: temps.push_back(temp); break;
default: tempp.push_back(temp); break;
}
}
return temp;
}
std::string FunctionBlock::genlocallabel()
{
std::ostringstream l;
l << "__label_" << ++nlabel;
return l.str();
}
//**********************************************************************
class FunctionStatement;
class NamespaceBlockBase;
class Expr;
//**********************************************************************
class BaseStatement
{
public:
virtual bool isempty() { return false; }
virtual void emit (Emit &e) = 0;
virtual BaseStatement *optimize() { return this; }
void optimize_branch(BaseStatement *&branch);
void optimize_branch(Expr *&branch);
virtual ~BaseStatement() { };
};
//**********************************************************************
class MultiStatement : public BaseStatement
{
public:
MultiStatement(BaseStatement *st1, BaseStatement *st2)
{
subst.push_back(st1);
subst.push_back(st2);
}
void push(BaseStatement *st)
{
subst.push_back(st);
}
private:
std::vector <BaseStatement *> subst;
BaseStatement *optimize()
{
for (size_t i= 0; i < subst.size(); ++i)
subst[i] = subst[i]->optimize();
return this;
}
void emit (Emit &e)
{
for (size_t i= 0; i < subst.size(); ++i)
subst[i]->emit(e);
}
};
BaseStatement *addtomulti(BaseStatement *oldst, BaseStatement *newst)
{
if (! oldst)
return newst;
else if (MultiStatement *multi = dynamic_cast<MultiStatement *>(oldst))
{
multi->push(newst);
return multi;
}
else
return new MultiStatement(oldst, newst);
}
//**********************************************************************
enum ClassSpecifierType
{
CLASSSPECIFIER_invalid,
CLASSSPECIFIER_str,
CLASSSPECIFIER_parrotkey,
CLASSSPECIFIER_id
};
class ClassSpecifier
{
protected:
ClassSpecifier(const Token &t) : start(t)
{ }
public:
virtual ClassSpecifierType reftype() const
{ return CLASSSPECIFIER_invalid; }
virtual ~ClassSpecifier() {}
void annotate(Emit &e)
{
e.annotate(start);
}
virtual std::string basename() const = 0;
virtual void emit(Emit &e) = 0;
private:
const Token start;
};
ClassSpecifier *parseClassSpecifier(const Token &start, Tokenizer &tk,
BlockBase &owner);
//**********************************************************************
class SubStatement : public BaseStatement, public InBlock
{
public:
SubStatement(Block &block);
};
SubStatement::SubStatement(Block &block) :
InBlock(block)
{
}
//**********************************************************************
class EmptyStatement : public BaseStatement
{
private:
bool isempty() { return true; }
void emit (Emit &) { };
};
//**********************************************************************
class BlockStatement : public BaseStatement, public SubBlock
{
public:
BlockStatement (Block &parentblock) :
SubBlock(parentblock)
{
}
};
//**********************************************************************
class UsingStatement : public BaseStatement
{
public:
UsingStatement(Block &bl,
const std::string &name, const NamespaceKey &nspace);
private:
void emit (Emit &e);
std::string n;
NamespaceKey ns;
};
//**********************************************************************
class ExternStatement : public BaseStatement
{
public:
ExternStatement(Tokenizer &tk);
private:
void emit (Emit &e)
{
e << INDENT "load_bytecode '" << n << ".pbc'\n";
}
std::string n;
};
ExternStatement::ExternStatement(Tokenizer &tk)
{
Token t;
do {
t= tk.get();
if (!n.empty() )
n+= '/';
n+= t.identifier();
t= tk.get();
} while (t.isop('.') );
RequireOp(';', t);
}
//**********************************************************************
class Expr : public InBlock
{
public:
Expr(BlockBase &block) : InBlock(block) { }
virtual Expr *optimize()
{
return this;
}
virtual bool isleft() const { return false; }
virtual void emitleft(Emit &)
{
std::cerr << typeid(*this).name() << '\n';
throw InternalError("Not a left-side expression");
}
virtual void emitleft(Emit &, const std::string &)
{
std::cerr << typeid(*this).name() << '\n';
throw InternalError("Not a left-side expression");
}
virtual void emitassign(Emit &, Expr &, const std::string &)
{
std::cerr << typeid(*this).name() << '\n';
throw InternalError("Not an assignable expression");
}
virtual void emit(Emit &e, const std::string &result) = 0;
virtual std::string emit_get(Emit &e);
virtual bool issimple() const { return false; }
virtual const Token &gettoken() const
{
std::cerr << typeid(*this).name() << '\n';
throw InternalError("In gettoken: Not a simple expression");
}
virtual bool isidentifier() const { return false; }
virtual std::string getidentifier() const
{ throw InternalError("Not an identifier"); }
virtual bool isnull() const { return false; }
virtual bool isliteralinteger() const { return false; }
virtual bool isinteger() const { return false; }
virtual int getintegervalue () const
{
std::cerr << typeid(*this).name() << '\n';
throw InternalError("Not an integer");
}
virtual bool isliteralstring() const { return false; }
virtual std::string getstringvalue () const
{ throw InternalError("Not a string"); }
virtual bool isstring() const { return false; }
virtual bool isindex() const { return false; }
char checkresult() const
{
if (isinteger() ) return REGint;
else if (isstring() ) return REGstring;
else return REGvar;
}
void optimize_branch(Expr *&branch)
{ branch= branch->optimize(); }
};
Expr * parseExpr(BlockBase &block, Tokenizer &tk);
//**********************************************************************
class Condition : public InBlock
{
public:
Condition (Block &block, Tokenizer &tk);
Condition (BlockBase &block, Expr *condexpr);
Condition *optimize();
bool issimple() const;
bool isinteger() const { return true; }
//bool isstring() const { return expr->isstring(); }
bool isliteralinteger() const;
std::string value() const;
std::string emit(Emit &e);
void emit_if(Emit &e, const std::string &labeltrue);
void emit_else(Emit &e, const std::string &labelfalse);
enum Value { CVtrue, CVfalse, CVruntime };
Value getvalue() const;
private:
Expr *expr;
};
//**********************************************************************
void BaseStatement::optimize_branch(BaseStatement *&branch)
{
if (branch)
branch= branch->optimize();
}
void BaseStatement::optimize_branch(Expr *&branch)
{
if (branch)
branch= branch->optimize();
}
//**********************************************************************
class Modifier
{
public:
Modifier(BlockBase &block, Tokenizer &tk)
{
Token t= tk.get();
if (!t.isidentifier())
throw Expected("Modifier name", t);
start = t;
name= t.identifier();
t= tk.get();
if (!t.isop('('))
tk.unget(t);
else
{
do
{
args.push_back(parseExpr(block, tk));
} while ((t= tk.get()).isop(','));
RequireOp(')', t);
}
}
std::string getname() const { return name; }
Token getstart() const { return start; }
void optimize()
{
for (size_t i= 0; i < args.size(); ++i)
args[i]= args[i]->optimize();
}
size_t numargs() const { return args.size(); }
Expr *getarg(size_t narg) const
{
return args.at(narg);
}
int getintegervalue(size_t narg) const
{
Expr *arg= args.at(narg);
return arg->getintegervalue();
}
std::string getstringvalue(size_t narg) const
{
Expr *arg= args.at(narg);
return arg->getstringvalue();
}
private:
Token start;
std::string name;
std::vector <Expr *> args;
};
//**********************************************************************
class ModifierList
{
public:
bool has_modifier(const std::string &name) const
{
return modifiers.find(name) != modifiers.end();
}
const Modifier * getmodifier(const std::string &name) const
{
ModList::const_iterator it= modifiers.find(name);
if (it != modifiers.end())
return &it->second;
else
return NULL;
}
void parse(BlockBase &block, Tokenizer &tk)
{
Token t;
do {
Modifier m(block, tk);
std::string name= m.getname();
modifiers.insert(std::make_pair(name, m));
} while ((t= tk.get()).isop(','));
RequireOp(']', t);
}
void optimize()
{
for (ModList::iterator it= modifiers.begin();
it != modifiers.end(); ++it)
it->second.optimize();
}
protected:
typedef std::map<std::string, Modifier> ModList;
ModList modifiers;
};
//**********************************************************************
class FunctionModifiers : public ModifierList
{
public:
FunctionModifiers(BlockBase &block, Tokenizer &tk, const NamespaceKey &)
{
Token t= tk.get();
if (! t.isop('[') )
tk.unget(t);
else
parse(block, tk);
}
};
//**********************************************************************
class ArgumentModifierList : public ModifierList
{
public:
void emitmodifiers(Emit &e)
{
bool isflat = false, isnamed = false;
Expr * setname = 0;
for (ModList::iterator it = modifiers.begin(); it != modifiers.end();
++it)
{
std::string name = it->first;
Modifier &modifier = it->second;
if (name == "flat")
isflat = true;
if (name == "named")
{
isnamed = true;
switch (modifier.numargs())
{
case 0:
break;
case 1:
setname = modifier.getarg(0);
break;
default:
throw SyntaxError("Invalid modifier", modifier.getstart());
}
}
}
if (isflat)
{
if (isnamed)
e << " :flat :named";
else
e << " :flat";
}
else if (isnamed)
{
e << " :named";
if (setname)
e << '(';
setname->emit(e, "");
e << ')';
}
}
};
class Argument
{
public:
Argument(BlockBase &block, Tokenizer &tk) :
modifiers(0)
{
expr = parseExpr(block, tk);
Token t = tk.get();
if (t.isop(':'))
{
t = tk.get();
if (! t.isop('['))
throw Expected("modifier list", t);
modifiers = new ArgumentModifierList();
modifiers->parse(block, tk);
}
else
tk.unget(t);
}
Expr *get()
{
return expr;
}
ArgumentModifierList *getmodifiers()
{
return modifiers;
}
Argument *optimize()
{
expr= expr->optimize();
return this;
}
void emit(Emit &e, const std::string &result)
{
expr->emit(e, result);
}
private:
Expr *expr;
ArgumentModifierList *modifiers;
};
class ArgumentList : public InBlock
{
public:
ArgumentList(BlockBase &block, Tokenizer &tk, char delimiter);
int numargs() const
{
return args ? args->size() : 0;
}
Expr *getfreearg(int i)
{
return args->at(i)->get();
}
void optimize();
void prepare(Emit &e);
void emit(Emit &e);
private:
std::vector <Argument *> *args;
std::vector <std::string> argregs;
};
//**********************************************************************
class ExprStatement : public BaseStatement
{
public:
ExprStatement(Block &parentblock, Tokenizer &tk);
private:
BaseStatement *optimize();
void emit (Emit &e);
Expr *expr;
};
//**********************************************************************
class CompoundStatement : public BlockStatement
{
public:
CompoundStatement(Block &parentblock, Tokenizer &tk);
BaseStatement *optimize();
void emit (Emit &e);
Token getend() const { return tend; }
private:
std::vector <BaseStatement *> subst;
Token tend;
};
//**********************************************************************
class ValueStatement : public SubStatement
{
public:
ValueStatement(Block & block, const Token &st);
protected:
void parseArray(Tokenizer &tk);
void emit (Emit &e, const std::string &name, char type);
enum ValueType { ValueSimple, ValueArray, ValueFixedArray };
ValueType vtype;
Expr *esize;
std::vector<Expr *> value;
const Token start;
private:
BaseStatement *optimize();
};
//**********************************************************************
class IntStatement : public ValueStatement
{
public:
IntStatement(Block & block, const Token &st, Tokenizer &tk);
void emit (Emit &e);
using ValueStatement::emit;
private:
std::string name;
};
//**********************************************************************
class FloatStatement : public ValueStatement
{
public:
FloatStatement(Block & block, const Token &st, Tokenizer &tk);
void emit (Emit &e);
using ValueStatement::emit;
private:
std::string name;
};
//**********************************************************************
class StringStatement : public ValueStatement
{
public:
StringStatement(Block & block, const Token &st, Tokenizer &tk);
void emit (Emit &e);
using ValueStatement::emit;
private:
std::string name;
};
//**********************************************************************
template <class DECST>
BaseStatement *parseDeclare(Block & block, const Token &st, Tokenizer &tk)
{
BaseStatement *multi = 0;
Token t;
do {
BaseStatement *item = new DECST(block, st, tk);
multi = addtomulti(multi, item);
t= tk.get();
} while (t.isop(','));
RequireOp (';', t);
return multi;
}
//**********************************************************************
class VarStatement : public ValueStatement
{
public:
VarStatement(Block & block, const Token &st, Tokenizer &tk);
void emit (Emit &e);
private:
std::string name;
};
//**********************************************************************
class ConstStatement : public ValueStatement
{
public:
ConstStatement(Block & block, const Token &st, Tokenizer &tk);
ConstStatement(Block & block, const Token &st, Tokenizer &tk, char typed);
BaseStatement *optimize();
void emit (Emit &e);
private:
char type;
std::string name;
Expr *value;
};
BaseStatement * parseConst(Block & block, const Token &st, Tokenizer &tk);
//**********************************************************************
class LabelStatement: public SubStatement
{
public:
LabelStatement(Block &block, const std::string &name);
void emit (Emit &e);
private:
std::string labelname;
std::string codename;
};
//**********************************************************************
class ReturnStatement : public SubStatement
{
public:
ReturnStatement(Block & block, Tokenizer &tk);
BaseStatement *optimize();
void emit (Emit &e);
private:
ArgumentList *values;
};
//**********************************************************************
class BreakStatement : public SubStatement
{
public:
BreakStatement(Block &block, Tokenizer &tk) :
SubStatement(block)
{
ExpectOp(';', tk);
}
private:
void emit (Emit &e)
{
e << INDENT "goto " << getbreaklabel() << " # break\n";
}
};
//**********************************************************************
class ContinueStatement : public SubStatement
{
public:
ContinueStatement(Block &block, Tokenizer &tk) :
SubStatement(block)
{
ExpectOp(';', tk);
}
private:
void emit (Emit &e)
{
e << INDENT "goto " << getcontinuelabel() << " # continue\n";
}
};
//**********************************************************************
class BreakableStatement : public BlockStatement
{
protected:
BreakableStatement(Block &block) :
BlockStatement(block)
{ }
std::string getbreaklabel() const
{
if (breaklabel.empty())
throw InternalError("attempt to use break label before creating");
return breaklabel;
}
std::string genbreaklabel()
{
if (! breaklabel.empty())
throw InternalError("attempt to create break label twice");
breaklabel = genlabel();
return breaklabel;
}
private:
std::string breaklabel;
};
class ContinuableStatement : public BreakableStatement
{
protected:
ContinuableStatement(Block &block) :
BreakableStatement(block)
{ }
std::string getcontinuelabel() const
{
if (continuelabel.empty())
throw InternalError("attempt to use continue label before creating");
return continuelabel;
}
std::string gencontinuelabel()
{
if (! continuelabel.empty())
throw InternalError("attempt to create continue label twice");
continuelabel = genlabel();
return continuelabel;
}
private:
std::string continuelabel;
};
//**********************************************************************
class SwitchBaseStatement : public BreakableStatement
{
protected:
SwitchBaseStatement(Block &block);
void parse_cases(Tokenizer &tk);
std::vector<Expr *> casevalue;
std::vector<std::vector<BaseStatement *> > casest;
std::vector<BaseStatement *> defaultst;
BaseStatement *optimize();
};
class SwitchStatement : public SwitchBaseStatement
{
public:
SwitchStatement(Block &block, Tokenizer &tk);
private:
BaseStatement *optimize();
void emit (Emit &e);
Expr *condition;
};
class SwitchCaseStatement : public SwitchBaseStatement
{
public:
SwitchCaseStatement(Block &block, Tokenizer &tk);
private:
void emit (Emit &e);
};
//**********************************************************************
class IfStatement : public BlockStatement
{
public:
IfStatement(Block &block, Tokenizer &tk);
private:
BaseStatement *optimize();
void emit (Emit &e);
Condition *condition;
BaseStatement *st;
BaseStatement *stelse;
};
//**********************************************************************
class WhileStatement : public ContinuableStatement
{
public:
WhileStatement(Block &block, Tokenizer &tk);
private:
BaseStatement *optimize();
void emit (Emit &e);
Condition *condition;
BaseStatement *st;
};
//**********************************************************************
class DoStatement : public ContinuableStatement
{
public:
DoStatement(Block &block, Tokenizer &tk);
private:
BaseStatement *optimize();
void emit (Emit &e);
Condition *condition;
BaseStatement *st;
};
//**********************************************************************
class ForeachStatement : public ContinuableStatement
{
public:
ForeachStatement(Block &block, Tokenizer &tk);
private:
BaseStatement *optimize();
void emit (Emit &e);
Token start;
std::string varname;
char vartype;
Expr * container;
BaseStatement *st;
};
//**********************************************************************
class ForStatement : public ContinuableStatement
{
public:
ForStatement(Block &block, Tokenizer &tk);
private:
BaseStatement *optimize();
void emit (Emit &e);
BaseStatement * initializer;
Expr * condition;
Expr * iteration;
BaseStatement *st;
};
//**********************************************************************
class ThrowStatement : public SubStatement
{
public:
ThrowStatement(Block &block, const Token &st, Tokenizer &tk);
private:
BaseStatement *optimize();
void emit (Emit &e);
Token pos;
Expr * excep;
};
//**********************************************************************
class TryModifierList: public ModifierList
{
public:
void emitmodifiers(Emit &e, const std::string &reghandler);
};
class TryStatement : public BlockStatement
{
public:
TryStatement(Block &block, const Token &st, Tokenizer &tk);
private:
BaseStatement *optimize();
void emit (Emit &e);
Token start;
TryModifierList modifiers;
BaseStatement *stry;
BaseStatement *scatch;
std::string exname;
};
//**********************************************************************
class FunctionParameter
{
public:
FunctionParameter(FunctionStatement *owner, Tokenizer &tk);
char gettype() const { return type; }
std::string getname() const { return name; }
void emit (Emit &e);
private:
//FunctionStatement *fst;
std::string name;
char type;
ModifierList modifiers;
bool has_modifier(const std::string &name) const
{
return modifiers.has_modifier(name);
}
};
//**********************************************************************
class FunctionStatement : protected FunctionModifiers, public FunctionBlock
{
public:
FunctionStatement(Tokenizer &tk, const Token &st,
Block &parent,
const NamespaceKey & ns_a, const std::string &funcname);
std::string getsubid() const;
std::string getname() const { return name; }
NamespaceKey getnamespace() const { return ns; }
void optimize();
virtual void emit (Emit &e);
void local(std::string name);
bool islocal(std::string name) const;
virtual void emitparams (Emit &e);
virtual void emitbody (Emit &e);
virtual ~FunctionStatement() {}
private:
const Token start;
const NamespaceKey ns;
const std::string name;
std::vector <std::string> params;
std::map <std::string, FunctionParameter *> paraminfo;
std::vector <std::string> loc;
BaseStatement *body;
Token tend;
};
//**********************************************************************
class ClassStatement : public SubBlock
{
public:
ClassStatement(NamespaceBlockBase &ns_b, Tokenizer &tk, NamespaceKey &ns_a);
const std::string &getname() const { return name; }
void emit (Emit &e);
std::vector <Token> attributes() const { return attrs; }
void optimize();
const NamespaceKey &getkey() const;
private:
unsigned int subblocks;
unsigned int blockid()
{
return ++subblocks;
}
std::string genlocallabel() { throw InternalError("No Class labels"); }
std::string genlocalregister(char) { throw InternalError("No Class registers"); }
Token start;
std::string name;
NamespaceKey ns;
std::vector <ClassSpecifier *> parents;
std::vector <FunctionStatement *> functions;
std::vector <Token> attrs;
std::vector <BaseStatement *> constants;
};
//**********************************************************************
FunctionParameter::FunctionParameter(FunctionStatement *owner, Tokenizer &tk) //:
//fst(owner)
{
Token t = tk.get();
type= nativetype(t);
if (type == '\0')
type= REGvar;
else
t= tk.get();
name= t.identifier();
t= tk.get();
if (t.isop('['))
modifiers.parse(*owner, tk);
else
tk.unget(t);
}
void FunctionParameter::emit (Emit &e)
{
e << ".param " << nameoftype(type) << ' ' <<
name;
bool isslurpy = has_modifier("slurpy");
bool isnamed = has_modifier("named");
if (isslurpy) {
e << " :slurpy";
// Special case for named slurpy
if (isnamed)
e << " :named";
}
else {
// Unfinished
if (isnamed)
e << " :named";
}
if (has_modifier("optional"))
e << " :optional";
if (has_modifier("opt_flag"))
e << " :opt_flag";
e << '\n';
}
//**********************************************************************
BaseStatement *parseUsing(Block &block, Tokenizer &tk)
{
Token t= tk.get();
if (t.iskeyword("extern"))
{
return new ExternStatement(tk);
}
else
{
NamespaceKey ns;
std::string name= t.identifier();
while((t= tk.get()).isop('.'))
{
ns= NamespaceKey(ns, name);
t= tk.get();
name= t.identifier();
}
RequireOp(';', t);
return new UsingStatement(block, name, ns);
}
}
BaseStatement *parseFor(Block &block, Tokenizer &tk)
{
Token t1= tk.get();
if (t1.isop('(') )
{
Token t2= tk.get();
Token t3= tk.get();
Token t4= tk.get();
if (t2.isidentifier() && (
t3.iskeyword("in") || (t4.iskeyword("in"))))
{
tk.unget(t4);
tk.unget(t3);
tk.unget(t2);
return new ForeachStatement(block, tk);
}
else
{
tk.unget(t4);
tk.unget(t3);
tk.unget(t2);
return new ForStatement(block, tk);
}
}
else
throw Expected("for condition", t1);
}
BaseStatement *parseSwitch(Block &block, Tokenizer &tk)
{
Token t = tk.get();
if (t.isop('('))
return new SwitchStatement(block, tk);
if (t.isop('{'))
return new SwitchCaseStatement(block, tk);
throw Expected("'(' o '{' after switch", t);
}
BaseStatement *parseStatement(Block &block, Tokenizer &tk)
{
Token t= tk.get();
while (t.isspace() )
t= tk.get();
if (t.isop(';'))
return new EmptyStatement();
if (t.isop('{') )
return new CompoundStatement(block, tk);
if (t.iskeyword("using"))
return parseUsing(block, tk);
switch(nativetype(t))
{
case REGint:
return parseDeclare<IntStatement>(block, t, tk);
case REGfloat:
return parseDeclare<FloatStatement>(block, t, tk);
case REGstring:
return parseDeclare<StringStatement>(block, t, tk);
case REGvar:
return new VarStatement(block, t, tk);
default: /* Not a declaration */ ;
}
if (t.iskeyword("const"))
return parseConst(block, t, tk);
if (t.iskeyword("return"))
return new ReturnStatement(block, tk);
if (t.iskeyword("break"))
return new BreakStatement(block, tk);
if (t.iskeyword("continue"))
return new ContinueStatement(block, tk);
if (t.iskeyword("if"))
return new IfStatement(block, tk);
if (t.iskeyword("switch"))
return parseSwitch(block, tk);
if (t.iskeyword("while"))
return new WhileStatement(block, tk);
if (t.iskeyword("do"))
return new DoStatement(block, tk);
if (t.iskeyword("for"))
return parseFor(block, tk);
if (t.iskeyword("throw"))
return new ThrowStatement(block, t, tk);
if (t.iskeyword("try"))
return new TryStatement(block, t, tk);
tk.unget(t);
return new ExprStatement(block, tk);
}
//**********************************************************************
ArgumentList::ArgumentList(BlockBase &block, Tokenizer &tk, char delimiter) :
InBlock(block),
args(0)
{
Token t = tk.get();
if (! t.isop(delimiter))
{
args= new std::vector<Argument *>;
tk.unget(t);
do
{
Argument *arg= new Argument(block, tk);
args->push_back(arg);
t= tk.get();
} while (t.isop(','));
if (! t.isop(delimiter))
throw SyntaxError("Unfinished argument list", t);
}
}
void ArgumentList::optimize()
{
if (args)
for (size_t i= 0; i < args->size(); ++i)
(*args)[i]= (*args)[i]->optimize();
}
void ArgumentList::prepare(Emit &e)
{
std::string nullreg;
if (args)
{
for (size_t i= 0; i < args->size(); ++i)
{
Expr &arg= *((*args)[i]->get());
std::string reg;
if (! arg.issimple() )
reg= arg.emit_get(e);
else
{
if (arg.isnull())
{
if (nullreg.empty())
{
nullreg= gentemp(REGvar);
e << op_null(nullreg) << '\n';
}
reg= nullreg;
}
else if (arg.isidentifier())
{
std::string name = arg.getidentifier();
FunctionStatement *fun = getfunction(name);
if (fun)
{
name = fun->getsubid();
e << ".const 'Sub' " << name << " = '" << name << "'\n";
reg = name;
}
}
}
argregs.push_back(reg);
}
}
}
void ArgumentList::emit(Emit &e)
{
if (args)
{
for (size_t i= 0; i < args->size(); ++i)
{
if (i > 0)
e << ", ";
if (argregs[i].empty() )
(*args)[i]->emit(e, std::string() );
else
e << argregs[i];
if (ArgumentModifierList *modifiers = (*args)[i]->getmodifiers())
{
modifiers->emitmodifiers(e);
}
}
}
}
//**********************************************************************
std::string Expr::emit_get(Emit &e)
{
std::string reg = gentemp(checkresult());
emit(e, reg);
return reg;
}
//**********************************************************************
class SimpleBaseExpr : public Expr
{
public:
SimpleBaseExpr(BlockBase &block, Token token) :
Expr(block),
t(token)
{ }
private:
const Token &gettoken() const { return t; }
bool issimple() const { return true; }
protected:
const Token t;
};
//**********************************************************************
class StringExpr : public SimpleBaseExpr
{
public:
StringExpr(BlockBase &block, Token token) :
SimpleBaseExpr(block, token)
{
if (! t.isliteralstring())
throw InternalError("Invalid literal string");
}
private:
bool isliteralstring() const { return true; }
bool isstring() const { return true; }
bool issinglequoted() const
{
return t.issinglequoted();
}
std::string getstringvalue() const
{
return t.str();
}
void emit(Emit &e, const std::string &result)
{
if (!result.empty() )
e << INDENT << result << " = ";
e << t.pirliteralstring();
if (!result.empty() )
e << '\n';
}
};
//**********************************************************************
class IntegerExpr : public SimpleBaseExpr
{
public:
IntegerExpr(BlockBase &block, Token token) :
SimpleBaseExpr(block, token),
value (t.getinteger())
{
}
IntegerExpr(BlockBase &block, Token token, int n) :
SimpleBaseExpr(block, Token(n, token)),
value (n)
{
}
private:
bool isliteralinteger() const { return true; }
bool isinteger() const { return true; }
int getintegervalue () const { return value; }
void emit(Emit &e, const std::string &result)
{
if (!result.empty() )
e << INDENT << result << " = ";
e << getintegervalue();
if (!result.empty() )
e << '\n';
}
int value;
};
//**********************************************************************
class IdentifierExpr : public SimpleBaseExpr
{
public:
IdentifierExpr(BlockBase &block, Token token) :
SimpleBaseExpr(block, token)
{ }
private:
bool isnull() const
{
return t.iskeyword("null");
}
bool isidentifier() const { return true; }
std::string getidentifier() const
{
if (isnull())
throw SyntaxError("Invalid 'null' usage", t);
return t.identifier();
}
bool isinteger() const
{
return checklocal(t.str()) == REGint;
}
int getintegervalue () const
{
if (checkconstant(t.identifier()) == REGint)
{
ConstantValue cv= getconstant(t.identifier());
if (cv.type () == REGint)
return cv.value().getinteger();
}
throw SyntaxError("Not an integer value", t);
}
bool isstring() const
{
return checklocal(t.str()) == REGstring;
}
std::string getstringvalue() const
{
if (checkconstant(t.identifier()) == REGstring)
{
ConstantValue cv= getconstant(t.identifier());
if (cv.type () == REGstring)
return cv.value().str();
}
throw SyntaxError("Not a string value", t);
}
Expr *optimize();
void emit(Emit &e, const std::string &result);
};
Expr *IdentifierExpr::optimize()
{
char type= checkconstant(t.identifier());
switch (type)
{
case REGint:
{
Token value = getconstant(t.identifier()).value();
return new IntegerExpr(*this, t, value.getinteger());
}
case REGstring:
{
Token value = getconstant(t.identifier()).value();
return new StringExpr(*this, value);
}
default: /* Not a constant */ ;
}
return this;
}
void IdentifierExpr::emit(Emit &e, const std::string &result)
{
if (!result.empty() )
e << INDENT << result << " = ";
e << getidentifier();
if (! result.empty() )
e << '\n';
}
//**********************************************************************
class OpBaseExpr : public Expr
{
public:
OpBaseExpr(BlockBase &block, const Token &t) :
Expr(block),
start(t)
{ }
protected:
void annotate(Emit &e)
{
e.annotate(start);
}
const Token start;
};
//**********************************************************************
class OpUnaryBaseExpr : public OpBaseExpr
{
public:
OpUnaryBaseExpr(BlockBase &block, const Token &t, Expr *subexpr) :
OpBaseExpr(block, t),
expr(subexpr)
{ }
protected:
Expr * expr;
private:
Expr *optimize()
{
optimize_branch(expr);
return this;
}
};
//**********************************************************************
class OpUnaryMinusExpr : public OpUnaryBaseExpr
{
public:
OpUnaryMinusExpr(BlockBase &block, Token t, Expr *subexpr) :
OpUnaryBaseExpr(block, t, subexpr)
{
}
private:
bool isinteger () const { return expr->isinteger(); }
Expr *optimize()
{
optimize_branch(expr);
if (expr->isliteralinteger() )
{
const int n= expr->getintegervalue();
return new IntegerExpr(*this, start, -n);
}
return this;
}
void emit(Emit &e, const std::string &result)
{
std::string arg= gentemp(REGint);
expr->emit(e, arg);
std::string r= result.empty() ? gentemp(REGint) : result;
annotate(e);
e << INDENT << r << " = neg " << arg;
if (! result.empty() )
e << '\n';
}
};
//**********************************************************************
class OpNotExpr : public OpUnaryBaseExpr
{
public:
OpNotExpr(BlockBase &block, Token t, Expr *subexpr) :
OpUnaryBaseExpr(block, t, subexpr)
{
}
private:
bool isinteger () const { return true; }
Expr *optimize()
{
optimize_branch(expr);
if (expr->isnull() )
return new IntegerExpr(*this, start, 1);
if (expr->isliteralinteger() )
{
const int n= expr->getintegervalue();
return new IntegerExpr(*this, start, !n);
}
return this;
}
void emit(Emit &e, const std::string &result)
{
std::string arg= gentemp(expr->isinteger() ? REGint : REGvar);
expr->emit(e, arg);
std::string r= result.empty() ?
gentemp(REGint) :
result;
annotate(e);
e << INDENT;
if (expr->isinteger())
e << "not ";
else
e << "isfalse ";
e << r << ", " << arg;
if (! result.empty() )
e << '\n';
}
};
//**********************************************************************
class OpBinNotExpr : public OpUnaryBaseExpr
{
public:
OpBinNotExpr(BlockBase &block, Token t, Expr *subexpr) :
OpUnaryBaseExpr(block, t, subexpr)
{
}
private:
bool isinteger () const { return true; }
Expr *optimize()
{
optimize_branch(expr);
if (expr->isnull() )
return new IntegerExpr(*this, start, 1);
if (expr->isliteralinteger() )
{
const int n= expr->getintegervalue();
return new IntegerExpr(*this, start, ~n);
}
return this;
}
void emit(Emit &e, const std::string &result)
{
std::string arg= gentemp(expr->isinteger() ? REGint : REGvar);
expr->emit(e, arg);
std::string r= result.empty() ?
gentemp(REGint) :
result;
annotate(e);
std::string aux;
if (expr->isinteger())
aux = arg;
else
{
aux = gentemp(REGint);
e << op_set(aux, arg) << '\n';
}
// bnot is a dynop, use bxor with -1 to avoid load its lib
e << INDENT "bxor " << r << ", " << aux << ", -1";
if (! result.empty() )
e << '\n';
}
};
//**********************************************************************
class BinOpExpr : public OpBaseExpr
{
protected:
BinOpExpr(BlockBase &block, Token t, Expr *first, Expr *second) :
OpBaseExpr(block, t),
lexpr(first),
rexpr(second)
{
}
void optimize_operands();
Expr *lexpr;
Expr *rexpr;
private:
Expr *optimize();
};
void BinOpExpr::optimize_operands()
{
optimize_branch(lexpr);
optimize_branch(rexpr);
}
Expr *BinOpExpr::optimize()
{
optimize_operands();
return this;
}
//**********************************************************************
class CommonBinOpExpr : public BinOpExpr
{
public:
CommonBinOpExpr(BlockBase &block,
Token t, Expr *first, Expr *second) :
BinOpExpr(block, t, first, second)
{
}
protected:
bool isstring() const;
bool isinteger() const;
};
bool CommonBinOpExpr::isstring() const
{
return lexpr->isstring() && rexpr->isstring();
}
bool CommonBinOpExpr::isinteger() const
{
return lexpr->isinteger() && rexpr->isinteger();
}
//**********************************************************************
class CompareOpExpr : public BinOpExpr
{
public:
CompareOpExpr(BlockBase &block,
Token t, Expr *first, Expr *second) :
BinOpExpr(block, t, first, second)
{
}
protected:
bool isinteger() const { return true; }
};
//**********************************************************************
class OpEqualExpr : public CompareOpExpr
{
public:
OpEqualExpr(BlockBase &block,
Token t, Expr *first, Expr *second) :
CompareOpExpr(block, t, first, second)
{ }
private:
bool isinteger() const { return true; }
Expr *optimize();
void emit(Emit &e, const std::string &result);
};
Expr *OpEqualExpr::optimize()
{
optimize_operands();
if (lexpr->issimple() && rexpr->issimple())
{
if (lexpr->isnull() && rexpr->isnull())
{
return new IntegerExpr(*this, start, 1);
}
if (lexpr->isliteralinteger() && rexpr->isliteralinteger())
{
return new IntegerExpr(*this, start,
lexpr->getintegervalue() == rexpr->getintegervalue());
}
if (lexpr->isliteralstring() && rexpr->isliteralstring())
{
std::string s1= lexpr->getstringvalue();
std::string s2= rexpr->getstringvalue();
return new IntegerExpr(*this, start, s1 == s2);
}
}
return this;
}
void OpEqualExpr::emit(Emit &e, const std::string &result)
{
std::string res= gentemp(REGint);
if (lexpr->isnull() || rexpr->isnull())
{
std::string op;
if (lexpr->isnull())
op= rexpr->emit_get(e);
else
op= lexpr->emit_get(e);
e << op_isnull(res, op);
}
else
{
char ltype = lexpr->checkresult();
char rtype = rexpr->checkresult();
if (ltype == rtype)
{
std::string op1= gentemp(ltype);
std::string op2= gentemp(rtype);
lexpr->emit(e, op1);
rexpr->emit(e, op2);
e << op_iseq(res, op1, op2);
}
else if (ltype == REGvar && rtype == REGstring)
{
std::string op1= gentemp(REGstring);
std::string op2= gentemp(REGstring);
std::string aux= gentemp(REGvar);
lexpr->emit(e, aux);
rexpr->emit(e, op2);
e << INDENT << op1 << " = " << aux << '\n';
e << op_iseq(res, op1, op2);
}
else if (ltype == REGstring && rtype == REGvar)
{
std::string op1= gentemp(REGstring);
std::string op2= gentemp(REGstring);
std::string aux= gentemp(REGvar);
lexpr->emit(e, op1);
rexpr->emit(e, aux);
e << INDENT << op2 << " = " << aux << '\n';
e << op_iseq(res, op1, op2);
}
else
{
std::string op1= gentemp(REGvar);
std::string op2= gentemp(REGvar);
if (lexpr->isinteger() )
{
std::string aux= gentemp(REGint);
lexpr->emit(e, aux);
e << op_box(res, aux) << '\n';
}
else if (lexpr->isstring() )
{
std::string aux= gentemp(REGstring);
lexpr->emit(e, aux);
e << op_box(op1, aux) << '\n';
}
else
lexpr->emit(e, op1);
if (rexpr->isinteger() )
{
std::string aux= gentemp(REGint);
rexpr->emit(e, aux);
e << op_box(op2, aux) << '\n';
}
else if (rexpr->isstring() )
{
std::string aux= gentemp(REGstring);
rexpr->emit(e, aux);
e << op_box(op2, aux) << '\n';
}
else
rexpr->emit(e, op2);
e << op_iseq(res, op1, op2);
}
}
if (!result.empty())
e << '\n' << INDENT << result << " = " << res << '\n';
}
//**********************************************************************
class OpNotEqualExpr : public CompareOpExpr
{
public:
OpNotEqualExpr(BlockBase &block,
Token t, Expr *first, Expr *second) :
CompareOpExpr(block, t, first, second)
{ }
private:
Expr *optimize();
void emit(Emit &e, const std::string &result);
};
Expr *OpNotEqualExpr::optimize()
{
optimize_operands();
if (lexpr->issimple() && rexpr->issimple())
{
if (lexpr->isnull() && rexpr->isnull())
return new IntegerExpr(*this, start, 0);
if (lexpr->isliteralinteger() && rexpr->isliteralinteger())
return new IntegerExpr(*this, start,
lexpr->getintegervalue() != rexpr->getintegervalue());
if (lexpr->isliteralstring() && rexpr->isliteralstring())
return new IntegerExpr(*this, start,
lexpr->getstringvalue() != rexpr->getstringvalue());
}
return this;
}
void OpNotEqualExpr::emit(Emit &e, const std::string &result)
{
std::string res= gentemp(REGint);
if (lexpr->isnull() || rexpr->isnull())
{
std::string op;
if (lexpr->isnull())
op= rexpr->emit_get(e);
else
op= lexpr->emit_get(e);
e << op_isnull(res, op) << '\n' <<
INDENT "not " << res;
}
else if (lexpr->isinteger() && rexpr->isinteger())
{
std::string op1= gentemp(REGint);
std::string op2= gentemp(REGint);
lexpr->emit(e, op1);
rexpr->emit(e, op2);
e << op_isne(res, op1, op2);
}
else if (lexpr->isstring() && rexpr->isstring())
{
std::string op1= gentemp(REGstring);
std::string op2= gentemp(REGstring);
lexpr->emit(e, op1);
rexpr->emit(e, op2);
e << op_isne(res, op1, op2);
}
else
{
std::string op1= gentemp(REGvar);
std::string op2= gentemp(REGvar);
if (lexpr->isinteger() )
{
std::string aux= gentemp(REGint);
lexpr->emit(e, aux);
e << op_box(op1, aux) << '\n';
}
else if (lexpr->isstring() )
{
std::string aux= gentemp(REGstring);
lexpr->emit(e, aux);
e << op_box(op1, aux) << '\n';
}
else
lexpr->emit(e, op1);
if (rexpr->isinteger() )
{
std::string aux= gentemp(REGint);
rexpr->emit(e, aux);
e << op_box(op2, aux) << '\n';
}
else if (rexpr->isstring() )
{
std::string aux= gentemp(REGstring);
rexpr->emit(e, aux);
e << op_box(op2, aux) << '\n';
}
else
rexpr->emit(e, op2);
e << INDENT << res << " = isne " << op1 << " , " << op2;
}
if (!result.empty())
e << '\n' << INDENT << result << " = " << res << '\n';
}
//**********************************************************************
class OpSameExpr : public CompareOpExpr
{
public:
OpSameExpr(bool positiveform, BlockBase &block,
Token t, Expr *first, Expr *second) :
CompareOpExpr(block, t, first, second),
positive(positiveform)
{ }
private:
bool isinteger() const { return true; }
Expr *optimize()
{
optimize_operands();
return this;
}
void emit(Emit &e, const std::string &result)
{
char ltype = lexpr->checkresult();
char rtype = rexpr->checkresult();
if (! ((ltype == REGvar && rtype == REGvar) ||
(ltype == REGstring && rtype == REGstring)))
throw SyntaxError(std::string(positive ? "===" : "!==") +
" operator requires val types", start);
std::string op1= gentemp(ltype);
std::string op2= gentemp(rtype);
lexpr->emit(e, op1);
rexpr->emit(e, op2);
std::string res= result.empty() ? gentemp(REGint) : result;
e << INDENT << res << " = " << (positive ? "issame" : "isntsame") <<
' ' << op1 << " , " << op2;
if (!result.empty())
e << '\n' << INDENT << result << " = " << res << '\n';
}
bool positive;
};
//**********************************************************************
class ComparatorBaseExpr : public CompareOpExpr
{
protected:
ComparatorBaseExpr(BlockBase &block,
Token t, Expr *first, Expr *second) :
CompareOpExpr(block, t, first, second)
{
}
virtual void emitop(Emit &e,
const std::string &res,
const std::string &op1, const std::string &op2) = 0;
private:
void emit(Emit &e, const std::string &result);
};
void ComparatorBaseExpr::emit(Emit &e, const std::string &result)
{
std::string res= result.empty() ? gentemp(REGint) : result;
char type1= lexpr->checkresult();
char type2= rexpr->checkresult();
if (type1 == REGint || type2 == REGint)
{
std::string op1= gentemp(REGint);
std::string op2= gentemp(REGint);
if (type1 == REGint)
lexpr->emit(e, op1);
else {
std::string aux= gentemp(REGvar);
lexpr->emit(e, aux);
e << INDENT << op1 << " = " << aux << '\n';
}
if (type2 == REGint)
rexpr->emit(e, op2);
else {
std::string aux= gentemp(REGvar);
rexpr->emit(e, aux);
e << INDENT << op2 << " = " << aux << '\n';
}
emitop(e, res, op1, op2);
if (!result.empty())
e << '\n';
}
else if (type1 == REGstring || type2 == REGstring)
{
std::string op1= gentemp(REGstring);
std::string op2= gentemp(REGstring);
if (type1 == REGstring)
lexpr->emit(e, op1);
else {
std::string aux= gentemp(REGvar);
lexpr->emit(e, aux);
e << INDENT << op1 << " = " << aux << '\n';
}
if (type2 == REGstring)
rexpr->emit(e, op2);
else {
std::string aux= gentemp(REGvar);
rexpr->emit(e, aux);
e << INDENT << op2 << " = " << aux << '\n';
}
emitop(e, res, op1, op2);
if (!result.empty())
e << '\n';
}
else
{
std::string op1= gentemp(REGvar);
std::string op2= gentemp(REGvar);
lexpr->emit(e, op1);
rexpr->emit(e, op2);
emitop(e, res, op1, op2);
if (!result.empty())
e << '\n';
}
}
//**********************************************************************
class OpLessExpr : public ComparatorBaseExpr
{
public:
OpLessExpr(BlockBase &block,
Token t, Expr *first, Expr *second) :
ComparatorBaseExpr(block, t, first, second)
{
}
private:
void emitop(Emit &e,
const std::string &res,
const std::string &op1, const std::string &op2)
{
e << op_islt(res, op1, op2);
}
};
//**********************************************************************
class OpGreaterExpr : public ComparatorBaseExpr
{
public:
OpGreaterExpr(BlockBase &block,
Token t, Expr *first, Expr *second) :
ComparatorBaseExpr(block, t, first, second)
{
}
private:
void emitop(Emit &e,
const std::string &res,
const std::string &op1, const std::string &op2)
{
e << op_isgt(res, op1, op2);
}
};
//**********************************************************************
class OpLessEqualExpr : public ComparatorBaseExpr
{
public:
OpLessEqualExpr(BlockBase &block,
Token t, Expr *first, Expr *second) :
ComparatorBaseExpr(block, t, first, second)
{
}
private:
void emitop(Emit &e,
const std::string &res,
const std::string &op1, const std::string &op2)
{
e << op_isle(res, op1, op2);
}
};
//**********************************************************************
class OpGreaterEqualExpr : public ComparatorBaseExpr
{
public:
OpGreaterEqualExpr(BlockBase &block,
Token t, Expr *first, Expr *second) :
ComparatorBaseExpr(block, t, first, second)
{
}
private:
void emitop(Emit &e,
const std::string &res,
const std::string &op1, const std::string &op2)
{
e << op_isge(res, op1, op2);
}
};
//**********************************************************************
class OpAssignExpr : public BinOpExpr
{
public:
OpAssignExpr(BlockBase &block,
Token t, Expr *first, Expr *second) :
BinOpExpr(block, t, first, second)
{
}
private:
bool isinteger() const { return rexpr->isinteger(); }
bool isstring() const { return rexpr->isstring(); }
void emit(Emit &e, const std::string &result)
{
if (lexpr->isidentifier())
{
std::string varname= lexpr->getidentifier();
char type= checklocal(varname);
if (rexpr->isindex())
{
rexpr->emit(e, varname);
if (! result.empty() )
e << INDENT << result << " = " << varname << '\n';
return;
}
switch (type)
{
case REGint:
if (!(rexpr->isinteger() || rexpr->isstring()))
{
std::string r= gentemp(REGvar);
rexpr->emit(e, r);
e.annotate(start);
e << INDENT << varname << " = " << r << '\n';
if (! result.empty() )
e << INDENT << result << " = " << r << '\n';
}
else {
if (result.empty() )
rexpr->emit(e, varname);
else
{
std::string r= gentemp(REGint);
rexpr->emit(e, r);
e.annotate(start);
e << INDENT << varname << " = " << r << '\n';
e << INDENT << result << " = " << r << '\n';
}
}
break;
case REGstring:
if (rexpr->isnull())
{
e.annotate(start);
e << op_null(varname) << '\n';
}
else if (!(rexpr->isinteger() || rexpr->isstring()))
{
std::string r= gentemp(REGstring);
rexpr->emit(e, r);
e.annotate(start);
e << INDENT << varname << " = " << r << '\n';
if (! result.empty() )
e << INDENT << result << " = " << r << '\n';
}
else {
if (result.empty() )
rexpr->emit(e, varname);
else
{
std::string r= gentemp(REGstring);
rexpr->emit(e, r);
e.annotate(start);
e << INDENT << varname << " = " << r << '\n';
e << INDENT << result << " = " << r << '\n';
}
}
break;
default:
if (rexpr->isnull())
{
e.annotate(start);
e << op_null(varname) << '\n';
}
else if (rexpr->isinteger() || rexpr->isstring() )
{
e.annotate(start);
std::string r= gentemp(rexpr->checkresult());
rexpr->emit(e, r);
e << op_box(varname, r);
e << '\n';
if (! result.empty() )
e << INDENT << result << " = " << varname << '\n';
}
else
{
rexpr->emit(e, varname);
if (! result.empty() )
e << INDENT << result << " = " << varname << '\n';
}
}
}
else
{
if (!lexpr->isleft() )
throw SyntaxError("Not a left-side expression for '='", start);
std::string reg= result.empty() ? std::string() :
gentemp(rexpr->checkresult());
lexpr->emitassign(e, *rexpr, reg);
if (! result.empty() )
e << INDENT << result << " = " << reg << '\n';
}
}
};
//**********************************************************************
class OpAddExpr : public CommonBinOpExpr
{
public:
OpAddExpr(BlockBase &block,
Token t, Expr *first, Expr *second) :
CommonBinOpExpr(block, t, first, second)
{
}
private:
bool isstring () const
{
return (lexpr->isstring() &&
(rexpr->isstring() || rexpr->isinteger()) ) ||
(rexpr->isstring() &&
(lexpr->isstring() || lexpr->isinteger()) );
}
Expr *optimize();
void emit(Emit &e, const std::string &result);
};
Expr *OpAddExpr::optimize()
{
//std::cerr << "OpAddExpr::optimize\n";
optimize_operands();
if (lexpr->issimple() && rexpr->issimple())
{
if (lexpr->isliteralinteger() && rexpr->isliteralinteger())
{
//std::cerr << "OpAddExpr::optimize int\n";
return new IntegerExpr(*this, start,
lexpr->getintegervalue() + rexpr->getintegervalue());
}
if (lexpr->isliteralstring() && rexpr->isliteralstring())
{
//std::cerr << "OpAddExpr::optimize string\n";
Token newt= Token(TokenTQuoted, lexpr->getstringvalue() + rexpr->getstringvalue(), lexpr->gettoken());
return new StringExpr(*this, newt);
}
}
return this;
}
void OpAddExpr::emit(Emit &e, const std::string &result)
{
if (lexpr->isstring() && rexpr->isstring())
{
std::string res= result.empty() ? gentemp(REGstring) : result;
std::string op1= gentemp(REGstring);
std::string op2= gentemp(REGstring);
lexpr->emit(e, op1);
rexpr->emit(e, op2);
e << INDENT << res << " = concat " << op1 << " , " << op2;
}
else if (isinteger())
{
std::string res= result.empty() ? gentemp(REGint) : result;
std::string op1= gentemp(REGint);
std::string op2= gentemp(REGint);
lexpr->emit(e, op1);
rexpr->emit(e, op2);
e << op_add(res, op1, op2);
}
else if (lexpr->isstring() && rexpr->isinteger())
{
std::string res= result.empty() ? gentemp(REGstring) : result;
std::string op1= gentemp(REGstring);
std::string op2= gentemp(REGint);
std::string op2_s= gentemp(REGstring);
lexpr->emit(e, op1);
rexpr->emit(e, op2);
e << op_set(op2_s, op2) << '\n' <<
INDENT << res << " = concat " << op1 << " , " << op2_s;
}
else if (lexpr->isinteger() && rexpr->isstring())
{
std::string res= result.empty() ? gentemp(REGstring) : result;
std::string op1= gentemp(REGint);
std::string op2= gentemp(REGstring);
std::string op1_s= gentemp(REGstring);
lexpr->emit(e, op1);
rexpr->emit(e, op2);
e << op_set(op1_s, op1) << '\n' <<
res << " = concat " << op1_s << " , " << op2;
}
else
{
std::string res= result.empty() ? gentemp(REGvar) : result;
std::string op1= gentemp(REGvar);
std::string op2= gentemp(REGvar);
switch (lexpr->checkresult() )
{
case REGint:
e << INDENT << op1 << " = new 'Integer'\n";
break;
case REGstring:
e << INDENT << op1 << " = new 'String'\n";
break;
default:
e << op_null(op1) << '\n';
}
switch (rexpr->checkresult() )
{
case REGint:
e << INDENT << op2 << " = new 'Integer'\n";
break;
case REGstring:
e << INDENT << op2 << " = new 'String'\n";
break;
default:
e << op_null(op2) << '\n';
}
lexpr->emit(e, op1);
rexpr->emit(e, op2);
e << op_add(res, op1, op2);
}
if (!result.empty())
e << '\n';
}
//**********************************************************************
class OpSubExpr : public CommonBinOpExpr
{
public:
OpSubExpr(BlockBase &block,
Token t, Expr *first, Expr *second) :
CommonBinOpExpr(block, t, first, second)
{
}
private:
Expr *optimize();
void emit(Emit &e, const std::string &result);
};
Expr *OpSubExpr::optimize()
{
//std::cerr << "OpSubExpr::optimize\n";
optimize_operands();
if (lexpr->issimple() && rexpr->issimple())
{
if (lexpr->isliteralinteger() && rexpr->isliteralinteger())
{
//std::cerr << "OpSubExpr::optimize int\n";
int n1= lexpr->getintegervalue();
int n2= rexpr->getintegervalue();
//std::cerr << n1 << " " << n2 << '\n';
return new IntegerExpr(*this, start, n1 - n2);
}
}
return this;
}
void OpSubExpr::emit(Emit &e, const std::string &result)
{
std::string res= result.empty() ? gentemp(REGint) : result;
std::string op1= gentemp(REGint);
std::string op2= gentemp(REGint);
lexpr->emit(e, op1);
rexpr->emit(e, op2);
e << op_sub(res, op1, op2);
if (!result.empty())
e << '\n';
}
//**********************************************************************
class OpBoolOrExpr : public BinOpExpr
{
public:
OpBoolOrExpr(BlockBase &block,
Token t, Expr *first, Expr *second) :
BinOpExpr(block, t, first, second)
{ }
private:
bool isinteger() const { return true; }
void emit(Emit &e, const std::string &result)
{
std::string res= result.empty() ? gentemp(REGint) : result;
std::string op1= gentemp(REGint);
std::string op2= gentemp(REGint);
if (rexpr->issimple())
{
lexpr->emit(e, op1);
rexpr->emit(e, op2);
e << INDENT << res << " = or " << op1 << ", " << op2;
}
else
{
std::string l = genlocallabel();
lexpr->emit(e, res);
e.annotate(start);
e << INDENT "if " << res << " goto " << l << '\n';
rexpr->emit(e, res);
e << INDENTLABEL << l << ":\n";
}
if (!result.empty())
e << '\n';
}
};
//**********************************************************************
class OpBinAndExpr : public CommonBinOpExpr
{
public:
OpBinAndExpr(BlockBase &block,
Token t, Expr *first, Expr *second) :
CommonBinOpExpr(block, t, first, second)
{
}
private:
bool isinteger() const { return true; }
void emit(Emit &e, const std::string &result)
{
std::string res= result.empty() ? gentemp(REGint) : result;
std::string op1= gentemp(REGint);
std::string op2= gentemp(REGint);
lexpr->emit(e, op1);
rexpr->emit(e, op2);
e << INDENT << res << " = band " << op1 << ", " << op2;
if (!result.empty())
e << '\n';
}
};
//**********************************************************************
class OpBinOrExpr : public CommonBinOpExpr
{
public:
OpBinOrExpr(BlockBase &block,
Token t, Expr *first, Expr *second) :
CommonBinOpExpr(block, t, first, second)
{
}
private:
bool isinteger() const { return true; }
void emit(Emit &e, const std::string &result)
{
std::string res= result.empty() ? gentemp(REGint) : result;
std::string op1= gentemp(REGint);
std::string op2= gentemp(REGint);
lexpr->emit(e, op1);
rexpr->emit(e, op2);
e << INDENT << res << " = bor " << op1 << ", " << op2;
if (!result.empty())
e << '\n';
}
};
//**********************************************************************
class OpBoolAndExpr : public OpBaseExpr
{
public:
OpBoolAndExpr(BlockBase &block,
Token t, Expr *first, Expr *second) :
OpBaseExpr(block, t),
lexpr(first),
rexpr(second)
{ }
private:
bool isinteger() const { return true; }
Expr *optimize()
{
optimize_branch(lexpr);
optimize_branch(rexpr);
return this;
}
void emit(Emit &e, const std::string &result)
{
std::string res= result.empty() ? gentemp(REGint) : result;
std::string op1= gentemp(REGint);
std::string op2= gentemp(REGint);
if (rexpr->issimple())
{
lexpr->emit(e, op1);
rexpr->emit(e, op2);
e.annotate(start);
e << INDENT << res << " = and " << op1 << ", " << op2;
}
else
{
std::string l = genlocallabel();
lexpr->emit(e, res);
e.annotate(start);
e << INDENT "unless " << res << " goto " << l << '\n';
rexpr->emit(e, res);
e << INDENTLABEL << l << ":\n";
}
if (!result.empty())
e << '\n';
}
Expr *lexpr;
Expr *rexpr;
};
//**********************************************************************
class OpMulExpr : public CommonBinOpExpr
{
public:
OpMulExpr(BlockBase &block,
Token t, Expr *first, Expr *second) :
CommonBinOpExpr(block, t, first, second)
{ }
private:
bool isinteger() const
{
return lexpr->isinteger() && rexpr->isinteger();
}
bool isstring() const
{
if (lexpr->isstring() && rexpr->isinteger())
return true;
else
return false;
}
Expr *optimize()
{
optimize_operands();
if (lexpr->isliteralinteger() && rexpr->isliteralinteger())
{
return new IntegerExpr(*this, start,
lexpr->getintegervalue() * rexpr->getintegervalue());
}
return this;
}
void emit(Emit &e, const std::string &result)
{
if (isstring())
{
std::string res= result.empty() ? gentemp(REGstring) : result;
std::string op1= gentemp(REGstring);
std::string op2= gentemp(REGint);
lexpr->emit(e, op1);
rexpr->emit(e, op2);
e << INDENT "repeat " << res << ", " << op1 << ", " << op2;
}
else
{
char type= lexpr->isinteger() && rexpr->isinteger() ? REGint : REGvar;
std::string res= result.empty() ? gentemp(type) : result;
std::string op1= gentemp(type);
std::string op2= gentemp(type);
lexpr->emit(e, op1);
rexpr->emit(e, op2);
e << op_mul(res, op1, op2);
}
if (!result.empty())
e << '\n';
}
};
//**********************************************************************
class OpDivExpr : public CommonBinOpExpr
{
public:
OpDivExpr(BlockBase &block,
Token t, Expr *first, Expr *second) :
CommonBinOpExpr(block, t, first, second)
{
}
private:
void emit(Emit &e, const std::string &result)
{
char type= lexpr->isinteger() && rexpr->isinteger() ? REGint : REGvar;
std::string res= result.empty() ? gentemp(type) : result;
std::string op1= gentemp(type);
std::string op2= gentemp(type);
if (lexpr->isinteger() && type != REGint) {
std::string i1= gentemp(REGint);
lexpr->emit(e, i1);
e << op_box(op1, i1);
}
else
lexpr->emit(e, op1);
if (rexpr->isinteger() && type != REGint) {
std::string i2= gentemp(REGint);
rexpr->emit(e, i2);
e << op_box(op2, i2) << '\n';
}
else
rexpr->emit(e, op2);
if (result.empty())
e << INDENT "new " << res << ", 'Integer'" << '\n';
e << op_div(res, op1, op2);
if (!result.empty())
e << '\n';
}
};
//**********************************************************************
class OpModExpr : public CommonBinOpExpr
{
public:
OpModExpr(BlockBase &block,
Token t, Expr *first, Expr *second) :
CommonBinOpExpr(block, t, first, second)
{
}
private:
void emit(Emit &e, const std::string &result)
{
char type= lexpr->isinteger() && rexpr->isinteger() ? REGint : REGvar;
std::string res= result.empty() ? gentemp(type) : result;
std::string op1= gentemp(type);
std::string op2= gentemp(type);
lexpr->emit(e, op1);
rexpr->emit(e, op2);
e << op_mod(res, op1, op2);
if (!result.empty())
e << '\n';
}
};
//**********************************************************************
class OpCModExpr : public CommonBinOpExpr
{
public:
OpCModExpr(BlockBase &block,
Token t, Expr *first, Expr *second) :
CommonBinOpExpr(block, t, first, second)
{
}
private:
void emit(Emit &e, const std::string &result)
{
char type= lexpr->isinteger() && rexpr->isinteger() ? REGint : REGvar;
std::string res= result.empty() ? gentemp(type) : result;
std::string op1= gentemp(type);
std::string op2= gentemp(type);
lexpr->emit(e, op1);
rexpr->emit(e, op2);
e << op_cmod(res, op1, op2);
if (!result.empty())
e << '\n';
}
};
//**********************************************************************
class OpShiftleftExpr : public CommonBinOpExpr
{
public:
OpShiftleftExpr(BlockBase &block,
Token t, Expr *first, Expr *second) :
CommonBinOpExpr(block, t, first, second)
{
}
private:
bool isinteger() const { return true; }
Expr * optimize()
{
optimize_operands();
if (lexpr->isliteralinteger() && rexpr->isliteralinteger())
{
return new IntegerExpr(*this, start,
lexpr->getintegervalue() << rexpr->getintegervalue());
}
return this;
}
void emit(Emit &e, const std::string &result)
{
std::string res= result.empty() ? gentemp(REGint) : result;
std::string op1= gentemp(REGint);
std::string op2= gentemp(REGint);
lexpr->emit(e, op1);
rexpr->emit(e, op2);
e << INDENT << res << " = shl " << op1 << ", " << op2;
if (!result.empty())
e << '\n';
}
};
//**********************************************************************
class OpShiftrightExpr : public CommonBinOpExpr
{
public:
OpShiftrightExpr(BlockBase &block,
Token t, Expr *first, Expr *second) :
CommonBinOpExpr(block, t, first, second)
{
}
private:
bool isinteger() const { return true; }
Expr * optimize()
{
optimize_operands();
if (lexpr->isliteralinteger() && rexpr->isliteralinteger())
{
return new IntegerExpr(*this, start,
lexpr->getintegervalue() >> rexpr->getintegervalue());
}
return this;
}
void emit(Emit &e, const std::string &result)
{
std::string res= result.empty() ? gentemp(REGint) : result;
std::string op1= gentemp(REGint);
std::string op2= gentemp(REGint);
lexpr->emit(e, op1);
rexpr->emit(e, op2);
e << INDENT << res << " = shr " << op1 << ", " << op2;
if (!result.empty())
e << '\n';
}
};
//**********************************************************************
class ArrayExpr : public Expr
{
public:
ArrayExpr(BlockBase &block, Tokenizer &tk) :
Expr(block)
{
Token t = tk.get();
if (! t.isop (']') )
{
tk.unget(t);
do {
elems.push_back(parseExpr(block, tk));
t= tk.get();
} while (t.isop(',') );
RequireOp (']', t);
}
}
private:
Expr *optimize()
{
for (size_t i= 0; i < elems.size(); ++i)
optimize_branch(elems[i]);
return this;
}
void emit(Emit &e, const std::string &result);
std::vector<Expr *> elems;
};
static void emit_maybeboxed(Emit &e, BlockBase &bl,
Expr &elem, const std::string &el)
{
char type = elem.checkresult();
switch (type)
{
case REGint: case REGfloat: case REGstring:
{
std::string aux = bl.gentemp(type);
elem.emit(e, aux);
e << op_box(el, aux) << '\n';
}
break;
default:
elem.emit(e, el);
}
}
void ArrayExpr::emit(Emit &e, const std::string &result)
{
std::string reg = gentemp(REGvar);
e << INDENT << reg << " = root_new ['parrot';'ResizablePMCArray']\n";
for (size_t i= 0; i < elems.size(); ++i)
{
Expr *elem= elems[i];
std::string el = gentemp(REGvar);
if (elem->issimple())
{
if (elem->isidentifier())
{
std::string id= elem->getidentifier();
if (checklocal(id))
emit_maybeboxed(e, *this, *elem, el);
else if (FunctionStatement *fun = getfunction(id))
{
std::string subid = fun->getsubid();
e << INDENT ".const 'Sub' " << subid << " = '" << subid << "'\n";
el = subid;
}
else
emit_maybeboxed(e, *this, *elem, el);
}
else
{
e << INDENT << el << " = box ";
elem->emit(e, std::string());
e << "\n";
}
}
else
emit_maybeboxed(e, *this, *elem, el);
e << INDENT "push " << reg << " , " << el << '\n';
}
if (!result.empty())
e << INDENT << result << " = " << reg << '\n';
}
//**********************************************************************
class HashExpr : public Expr
{
public:
HashExpr(BlockBase &block, Tokenizer &tk);
private:
Expr *optimize()
{
for (std::map<std::string, Expr *>::iterator
it= elems.begin();
it != elems.end();
++it)
{
optimize_branch(it->second);
}
return this;
}
void emit(Emit &e, const std::string &result);
std::map<std::string, Expr *> elems;
};
HashExpr::HashExpr(BlockBase &block, Tokenizer &tk) :
Expr(block)
{
Token t = tk.get();
if (! t.isop ('}') )
{
tk.unget(t);
do {
Token tkey= tk.get();
if (! (tkey.isliteralstring() || tkey.isidentifier() ) )
throw Expected("key", t);
t= tk.get();
RequireOp (':', t);
Expr *value= parseExpr(block, tk);
std::string key;
if (tkey.isidentifier())
key= "'" + tkey.identifier() + "'";
else if (tkey.isliteralstring())
key= tkey.pirliteralstring();
else
throw Expected("Identifier or string", tkey);
elems[key]= value;
t= tk.get();
} while (t.isop(',') );
RequireOp ('}', t);
}
}
class EmitItem
{
public:
EmitItem(Emit &em, HashExpr &block,
const std::string reg) :
e(&em), bl(block), r(reg) { }
void operator() (std::pair<std::string, Expr *> elem)
{
Expr *value= elem.second;
std::string reg;
if (value->isidentifier() )
{
std::string id= value->getidentifier();
if (bl.checklocal(id))
reg= id;
else if (FunctionStatement *fun = bl.getfunction(id))
{
std::string subid = fun->getsubid();
(*e) << INDENT ".const 'Sub' " << subid << " = '" << subid << "'\n";
reg = subid;
}
else
{
reg = bl.gentemp(REGvar);
(*e) << INDENT "get_hll_global " << reg << ", '" <<
id << "'\n";
}
}
else if (value->isinteger())
{
reg = bl.gentemp(REGint);
value->emit(*e, reg);
}
else if (value->isstring())
{
reg = bl.gentemp(REGstring);
value->emit(*e, reg);
}
else
{
reg = bl.gentemp(REGvar);
value->emit(*e, reg);
}
(*e) << INDENT << r << " [" << elem.first << "] = " << reg << '\n';
}
private:
Emit *e;
HashExpr &bl;
std::string r;
};
void HashExpr::emit(Emit &e, const std::string &result)
{
std::string reg = gentemp(REGvar);
e << INDENT << reg << " = root_new ['parrot';'Hash']\n";
std::for_each(elems.begin(), elems.end(), EmitItem(e, *this, reg) );
if (!result.empty())
e << INDENT << result << " = " << reg << '\n';
}
//**********************************************************************
class MemberExpr : public Expr {
public:
MemberExpr(BlockBase &block, Tokenizer &tk, Token t,
Expr *leftexpr) :
Expr(block),
start(t),
left(leftexpr),
right(tk.get())
{
//std::cerr << "MemberExpr::MemberExpr\n";
if (!right.isidentifier())
throw Expected("identifier", right);
//std::cerr << "MemberExpr::MemberExpr\n";
}
void emit(Emit &e, const std::string &result)
{
std::string reg = gentemp(REGvar);
std::string r = (result.empty() ||
(result[0] == '$' && result.substr(0, 2) != "$P") ) ?
gentemp(REGvar) : result;
left->emit(e, reg);
e.annotate(start);
e << INDENT "getattribute " << r << ", " << reg <<
", '" << right.identifier() << "'\n";
if (result != r)
e << op_set(result, r) << '\n';
}
std::string getmember() const { return right.identifier(); }
void emitleft(Emit &e, const std::string &result)
{
char type= left->checkresult();
switch(type)
{
case REGint: case REGstring:
{
std::string aux= gentemp(type);
left->emit(e, aux);
e << op_box(result, aux) << '\n';
}
break;
default:
left->emit(e, result);
}
}
bool isleft() const { return true; }
void emitleft(Emit &)
{
throw InternalError("here");
}
void emitassign(Emit &e, Expr& value, const std::string &to)
{
//std::cerr << typeid(right).name() << '\n';
e.annotate(start);
std::string reg = gentemp(REGvar);
left->emit(e, reg);
char typevalue= value.checkresult();
std::string regval= gentemp(typevalue);
if (value.isnull())
e << op_null(regval) << '\n';
else
value.emit(e, regval);
e << '\n';
std::string regattrval;