Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

6495 lines (5953 sloc) 170.941 kB
// winxedst0.cpp
// Revision 25-jun-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 REGstring = 'S';
const char REGvar = 'P';
// Pseudotypes for builtins
const char REGany = '?';
const char REGnone = '\0'; // void return
static const char * nameoftype(char ctype)
{
switch (ctype)
{
case REGint: return "int";
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("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 BuiltinFunction
{
public:
static const int VarArgs = -1;
BuiltinFunction(const std::string &name, char typeresult, int nargs) :
pname(name),
tresult(typeresult),
n(nargs)
{
}
BuiltinFunction(const std::string &name, char typeresult) :
pname(name),
tresult(typeresult),
n(VarArgs)
{
}
static const BuiltinFunction *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 BuiltinFunction *builtins[];
static const size_t numbuiltins;
const std::string pname;
char tresult;
unsigned int n;
};
class BuiltinFunctionFixargs : public BuiltinFunction
{
public:
BuiltinFunctionFixargs(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 BuiltinFunctionVarargs : public BuiltinFunction
{
protected:
BuiltinFunctionVarargs(const std::string &name,
char typeresult) :
BuiltinFunction(name, typeresult)
{ }
char paramtype(size_t /*unused*/) const
{
return REGany;
}
};
class Builtin_print : public BuiltinFunctionVarargs
{
public:
Builtin_print() : BuiltinFunctionVarargs("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 Builtin_say : public BuiltinFunctionVarargs
{
public:
Builtin_say() : BuiltinFunctionVarargs("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 Builtin_cry : public BuiltinFunctionVarargs
{
public:
Builtin_cry() : BuiltinFunctionVarargs("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 Builtin_ASSERT : public BuiltinFunction
{
public:
Builtin_ASSERT() : BuiltinFunction("__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 BuiltinFunction *BuiltinFunction::builtins[]= {
new Builtin_ASSERT(),
new Builtin_print(),
new Builtin_say(),
new Builtin_cry(),
new BuiltinFunctionFixargs("int",
"{res} = {arg0}",
REGint, REGany),
new BuiltinFunctionFixargs("string",
"{res} = {arg0}",
REGstring, REGany),
new BuiltinFunctionFixargs("exit",
"exit {arg0}",
REGnone, REGint),
new BuiltinFunctionFixargs("spawnw",
"spawnw {res}, {arg0}",
REGint, REGvar),
new BuiltinFunctionFixargs("getstdin",
"getstdin {res}",
REGvar),
new BuiltinFunctionFixargs("getstdout",
"getstdout {res}",
REGvar),
new BuiltinFunctionFixargs("getstderr",
"getstderr {res}",
REGvar),
new BuiltinFunctionFixargs("open",
"root_new {res}, ['parrot';'FileHandle']\n"
"{res}.'open'({arg0})",
REGvar, REGstring),
new BuiltinFunctionFixargs("open",
"root_new {res}, ['parrot';'FileHandle']\n"
"{res}.'open'({arg0},{arg1})",
REGvar, REGstring, REGstring),
new BuiltinFunctionFixargs("Error",
"root_new {res}, ['parrot';'Exception']\n"
"{res}['message'] = {arg0}\n"
, REGvar, REGstring),
new BuiltinFunctionFixargs("Error",
"root_new {res}, ['parrot';'Exception']\n"
"{res}['message'] = {arg0}\n"
"{res}['severity'] = {arg1}\n"
, REGvar, REGstring, REGint),
new BuiltinFunctionFixargs("Error",
"root_new {res}, ['parrot';'Exception']\n"
"{res}['message'] = {arg0}\n"
"{res}['severity'] = {arg1}\n"
"{res}['type'] = {arg2}\n"
, REGvar, REGstring, REGint, REGint),
new BuiltinFunctionFixargs("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 BuiltinFunctionFixargs("elements",
"elements {res}, {arg0}",
REGint, REGvar),
new BuiltinFunctionFixargs("length",
"length {res}, {arg0}",
REGint, REGstring),
new BuiltinFunctionFixargs("bytelength",
"bytelength {res}, {arg0}",
REGint, REGstring),
new BuiltinFunctionFixargs("chr",
"chr $S0, {arg0}\n"
"find_encoding $I0, 'utf8'\n"
"trans_encoding {res}, $S0, $I0\n",
REGstring, REGint),
new BuiltinFunctionFixargs("ord",
"ord {res}, {arg0}",
REGint, REGstring),
new BuiltinFunctionFixargs("ord",
"ord {res}, {arg0}, {arg1}",
REGint, REGstring, REGint),
new BuiltinFunctionFixargs("substr",
"substr {res}, {arg0}, {arg1}",
REGstring, REGstring, REGint),
new BuiltinFunctionFixargs("substr",
"substr {res}, {arg0}, {arg1}, {arg2}",
REGstring, REGstring, REGint, REGint),
new BuiltinFunctionFixargs("replace",
"replace {res}, {arg0}, {arg1}, {arg2}, {arg3}",
REGstring, REGstring, REGint, REGint, REGstring),
new BuiltinFunctionFixargs("indexof",
"index {res}, {arg0}, {arg1}",
REGint, REGstring, REGstring),
new BuiltinFunctionFixargs("indexof",
"index {res}, {arg0}, {arg1}, {arg2}",
REGint, REGstring, REGstring, REGint),
new BuiltinFunctionFixargs("escape",
"escape {res}, {arg0}",
REGstring, REGstring),
new BuiltinFunctionFixargs("unescape",
"$P0 = new ['String']\n"
"$P0 = {arg0}\n"
"{res} = $P0.'unescape'('utf8')\n",
REGstring, REGstring),
new BuiltinFunctionFixargs("unescape",
"$P0 = new ['String']\n"
"$P0 = {arg0}\n"
"{res} = $P0.'unescape'({arg1})\n",
REGstring, REGstring, REGstring),
new BuiltinFunctionFixargs("upcase",
"upcase {res}, {arg0}",
REGstring, REGstring),
new BuiltinFunctionFixargs("downcase",
"downcase {res}, {arg0}",
REGstring, REGstring),
new BuiltinFunctionFixargs("titlecase",
"titlecase {res}, {arg0}",
REGstring, REGstring),
new BuiltinFunctionFixargs("join",
"join {res}, {arg0}, {arg1}",
REGstring, REGstring, REGvar),
new BuiltinFunctionFixargs("split",
"split {res}, {arg0}, {arg1}",
REGvar, REGstring, REGstring),
new BuiltinFunctionFixargs("push",
"push {arg0}, {arg1}",
REGnone, REGvar, REGany),
new BuiltinFunctionFixargs("getinterp",
"getinterp {res}",
REGvar),
new BuiltinFunctionFixargs("get_class",
"get_class {res}, {arg0}",
REGvar, REGstring),
new BuiltinFunctionFixargs("typeof",
"typeof {res}, {arg0}",
REGvar, REGvar),
new BuiltinFunctionFixargs("clone",
"clone {res}, {arg0}",
REGvar, REGvar),
new BuiltinFunctionFixargs("compreg",
"compreg {res}, {arg0}",
REGvar, REGstring),
new BuiltinFunctionFixargs("compreg",
"compreg {arg0}, {arg1}",
REGnone, REGstring, REGvar),
new BuiltinFunctionFixargs("load_language",
"load_language {arg0}\n"
"compreg {res}, {arg0}",
REGvar, REGstring),
new BuiltinFunctionFixargs("load_language",
"load_language {arg0}\n"
"compreg {res}, {arg1}",
REGvar, REGstring, REGstring),
new BuiltinFunctionFixargs("loadlib",
"loadlib {res}, {arg0}",
REGvar, REGstring),
new BuiltinFunctionFixargs("load_bytecode",
"load_bytecode {arg0}",
REGvar, REGstring),
new BuiltinFunctionFixargs("sprintf",
"sprintf {res}, {arg0}, {arg1}",
REGstring, REGstring, REGvar)
};
const size_t BuiltinFunction::numbuiltins =
sizeof(BuiltinFunction::builtins) / sizeof(BuiltinFunction::builtins[0]);
const BuiltinFunction *BuiltinFunction::find(const std::string &name,
size_t numargs)
{
for (size_t i= 0; i < numbuiltins; ++i) {
int n = builtins[i]->n;
if ((n == BuiltinFunction::VarArgs || n == int(numargs)) &&
builtins[i]->name_is(name) )
return builtins[i];
}
return 0;
}
BuiltinFunctionFixargs::BuiltinFunctionFixargs(const std::string &name,
const std::string &body,
char typeresult,
char type0, char type1, char type2, char type3) :
BuiltinFunction(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 BuiltinFunctionFixargs::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 builtin");
}
}
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 Annotated
{
protected:
Annotated(const Token & tstart) : start(tstart)
{ }
public:
void annotate(Emit &e)
{
e.annotate(start);
}
const Token & getstart() const
{
return start;
}
private:
const Token start;
};
//**********************************************************************
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
{
char c= Block::checkconstant(name);
if (c == '\0')
c= parent.checkconstant(name);
return c;
}
ConstantValue SubBlock::getconstant(const std::string &name) const
{
if (Block::checkconstant(name))
return Block::getconstant(name);
else
return parent.getconstant(name);
}
std::string SubBlock::genlocallabel()
{
std::ostringstream l;
l << "__label_" << id << '_' << ++nlabel;
return l.str();
}
//**********************************************************************
class NamespaceKey
{
typedef std::vector <std::string> key_t;
public:
NamespaceKey() { }
NamespaceKey(const std::string &name) :
key(1, name)
{
}
NamespaceKey(const key_t &newkey) :
key(newkey)
{
}
bool isroot() const
{
return key.empty();
}
NamespaceKey parent() const
{
key_t newkey = key;
newkey.pop_back();
return NamespaceKey(newkey);
}
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;
};
//**********************************************************************
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)
{
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 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_parrotkey,
CLASSSPECIFIER_id
};
class ClassSpecifier : public Annotated
{
protected:
ClassSpecifier(const Token &t) : Annotated(t)
{ }
public:
virtual ClassSpecifierType reftype() const
{ return CLASSSPECIFIER_invalid; }
virtual ~ClassSpecifier() {}
virtual std::string basename() const = 0;
virtual void emit(Emit &e) = 0;
};
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 Expr : public InBlock, public Annotated
{
public:
Expr(BlockBase &block, const Token & tstart) :
InBlock(block),
Annotated(tstart)
{
}
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)
{
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 Annotated
{
public:
ValueStatement(Block & block, const Token & tstart);
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;
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 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, 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 Annotated
{
public:
ReturnStatement(Block & block, const Token & tstart, 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 TryStatement : public BlockStatement, public Annotated
{
public:
TryStatement(Block &block, const Token &st, Tokenizer &tk);
private:
BaseStatement *optimize();
void emit (Emit &e);
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:
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 Annotated
{
public:
FunctionStatement(Tokenizer &tk, const Token & tstart,
Block &parent,
const std::string &funcname);
virtual std::string getsubid() const;
std::string getname() const { return name; }
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 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);
const std::string &getname() const { return name; }
void emit (Emit &e);
std::vector <Token> attributes() const { return attrs; }
void optimize();
const NamespaceKey &getkey() const;
void emitkey (Emit &e) 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)
{
Token t = tk.get();
type= nativetype(t);
if (type == '\0')
throw Expected("parameter type", t);
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 *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);
switch(nativetype(t))
{
case REGint:
return parseDeclare<IntStatement>(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, t, 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() )
{
arg.annotate(e);
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, const Token & token) :
Expr(block, token),
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 & tstart) :
Expr(block, tstart)
{ }
};
//**********************************************************************
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, const Token & tstart, Expr *subexpr) :
OpUnaryBaseExpr(block, tstart, 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, getstart(), -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, const Token & tstart, Expr *subexpr) :
OpUnaryBaseExpr(block, tstart, subexpr)
{
}
private:
bool isinteger () const { return true; }
Expr *optimize()
{
optimize_branch(expr);
if (expr->isnull() )
return new IntegerExpr(*this, getstart(), 1);
if (expr->isliteralinteger() )
{
const int n= expr->getintegervalue();
return new IntegerExpr(*this, getstart(), !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 BinOpExpr : public OpBaseExpr
{
protected:
BinOpExpr(BlockBase &block, const Token & tstart, Expr *first, Expr *second) :
OpBaseExpr(block, tstart),
lexpr(first),
rexpr(second)
{
}
void optimize_operands()
{
optimize_branch(lexpr);
optimize_branch(rexpr);
}
Expr *lexpr;
Expr *rexpr;
private:
Expr *optimize()
{
optimize_operands();
return this;
}
};
//**********************************************************************
class CommonBinOpExpr : public BinOpExpr
{
public:
CommonBinOpExpr(BlockBase &block,
const Token & tstart, Expr *first, Expr *second) :
BinOpExpr(block, tstart, first, second)
{
}
protected:
bool isstring() const
{
return lexpr->isstring() && rexpr->isstring();
}
bool isinteger() const
{
return lexpr->isinteger() && rexpr->isinteger();
}
};
//**********************************************************************
class CompareOpExpr : public BinOpExpr
{
public:
CompareOpExpr(BlockBase &block,
const Token & tstart, Expr *first, Expr *second) :
BinOpExpr(block, tstart, first, second)
{
}
protected:
bool isinteger() const { return true; }
};
//**********************************************************************
class OpEqualExpr : public CompareOpExpr
{
public:
OpEqualExpr(BlockBase &block,
const Token & tstart, Expr *first, Expr *second) :
CompareOpExpr(block, tstart, 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->isnull() && rexpr->isnull())
{
return new IntegerExpr(*this, getstart(), 1);
}
if (lexpr->isliteralinteger() && rexpr->isliteralinteger())
{
return new IntegerExpr(*this, getstart(),
lexpr->getintegervalue() == rexpr->getintegervalue());
}
if (lexpr->isliteralstring() && rexpr->isliteralstring())
{
std::string s1= lexpr->getstringvalue();
std::string s2= rexpr->getstringvalue();
return new IntegerExpr(*this, getstart(), 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,
const Token & tstart, Expr *first, Expr *second) :
CompareOpExpr(block, tstart, first, second)
{ }
private:
Expr *optimize();
void emit(Emit &e, const std::string &result);
};
Expr *OpNotEqualExpr::optimize()
{
optimize_operands();
if (lexpr->isnull() && rexpr->isnull())
return new IntegerExpr(*this, getstart(), 0);
if (lexpr->isliteralinteger() && rexpr->isliteralinteger())
return new IntegerExpr(*this, getstart(),
lexpr->getintegervalue() != rexpr->getintegervalue());
if (lexpr->isliteralstring() && rexpr->isliteralstring())
return new IntegerExpr(*this, getstart(),
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,
const Token & tstart, Expr *first, Expr *second) :
CompareOpExpr(block, tstart, first, second),
positive(positiveform)
{ }
private:
bool isinteger() const { return true; }
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", getstart());
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,
const Token & tstart, Expr *first, Expr *second) :
CompareOpExpr(block, tstart, 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,
const Token & tstart, Expr *first, Expr *second) :
ComparatorBaseExpr(block, tstart, 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,
const Token & tstart, Expr *first, Expr *second) :
ComparatorBaseExpr(block, tstart, 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,
const Token & tstart, Expr *first, Expr *second) :
ComparatorBaseExpr(block, tstart, 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,
const Token & tstart, Expr *first, Expr *second) :
ComparatorBaseExpr(block, tstart, 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,
const Token & tstart, Expr *first, Expr *second) :
BinOpExpr(block, tstart, 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);
annotate(e);
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);
annotate(e);
e << INDENT << varname << " = " << r << '\n';
e << INDENT << result << " = " << r << '\n';
}
}
break;
case REGstring:
if (rexpr->isnull())
{
annotate(e);
e << op_null(varname) << '\n';
}
else if (!(rexpr->isinteger() || rexpr->isstring()))
{
std::string r= gentemp(REGstring);
rexpr->emit(e, r);
annotate(e);
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);
annotate(e);
e << INDENT << varname << " = " << r << '\n';
e << INDENT << result << " = " << r << '\n';
}
}
break;
default:
if (rexpr->isnull())
{
annotate(e);
e << op_null(varname) << '\n';
}
else if (rexpr->isinteger() || rexpr->isstring() )
{
annotate(e);
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 '='", getstart());
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,
const Token & tstart, Expr *first, Expr *second) :
CommonBinOpExpr(block, tstart, 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()
{
optimize_operands();
if (lexpr->isliteralinteger() && rexpr->isliteralinteger())
{
return new IntegerExpr(*this, getstart(),
lexpr->getintegervalue() + rexpr->getintegervalue());
}
if (lexpr->isliteralstring() && rexpr->isliteralstring())
{
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,
const Token & tstart, Expr *first, Expr *second) :
CommonBinOpExpr(block, tstart, first, second)
{
}
private:
Expr *optimize()
{
optimize_operands();
if (lexpr->isliteralinteger() && rexpr->isliteralinteger())
{
int n1= lexpr->getintegervalue();
int n2= rexpr->getintegervalue();
return new IntegerExpr(*this, getstart(), n1 - n2);
}
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 << op_sub(res, op1, op2);
if (!result.empty())
e << '\n';
}
};
//**********************************************************************
class OpBoolOrExpr : public BinOpExpr
{
public:
OpBoolOrExpr(BlockBase &block,
const Token & tstart, Expr *first, Expr *second) :
BinOpExpr(block, tstart, 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);
annotate(e);
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,
const Token & tstart, Expr *first, Expr *second) :
CommonBinOpExpr(block, tstart, 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,
const Token & tstart, Expr *first, Expr *second) :
CommonBinOpExpr(block, tstart, 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,
const Token & tstart, Expr *first, Expr *second) :
OpBaseExpr(block, tstart),
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);
annotate(e);
e << INDENT << res << " = and " << op1 << ", " << op2;
}
else
{
std::string l = genlocallabel();
lexpr->emit(e, res);
annotate(e);
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,
const Token & tstart, Expr *first, Expr *second) :
CommonBinOpExpr(block, tstart, first, second)
{ }
private:
bool isinteger() const
{
return lexpr->isinteger() && rexpr->isinteger();
}
Expr *optimize()
{
optimize_operands();
if (lexpr->isliteralinteger() && rexpr->isliteralinteger())
{
return new IntegerExpr(*this, getstart(),
lexpr->getintegervalue() * rexpr->getintegervalue());
}
return this;
}
void emit(Emit &e, const std::string &result)
{
char type= 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,
const Token & tstart, Expr *first, Expr *second) :
CommonBinOpExpr(block, tstart, 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 ArrayExpr : public Expr
{
public:
ArrayExpr(BlockBase &block, Tokenizer &tk, const Token & tstart) :
Expr(block, tstart)
{
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 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, const Token & tstart);
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, const Token & tstart) :
Expr(block, tstart)
{
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, const Token & tstart,
Expr *leftexpr) :
Expr(block, tstart),
left(leftexpr),
right(tk.get())
{
if (!right.isidentifier())
throw Expected("identifier", right);
}
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);
annotate(e);
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)
{
annotate(e);
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;
if (typevalue == REGvar)
regattrval= regval;
else
{
regattrval= gentemp(REGvar);
e << op_box(regattrval, regval) << '\n';
}
e << INDENT "setattribute " << reg << ", '" << right.identifier() <<
"', " << regattrval << '\n';
if (! to.empty())
e << INDENT "set " << to << ", " << regattrval << '\n';
}
private:
Expr *left;
Token right;
};
//**********************************************************************
class CallExpr : public Expr
{
public:
CallExpr(BlockBase &block, Tokenizer &tk, const Token & tstart,
Expr *function) :
Expr(block, tstart),
called(function),
args(0)
{
Token t= tk.get();
if (! t.isop (')') )
{
tk.unget(t);
args= new ArgumentList(block, tk, ')');
}
}
Expr * optimize()
{
if (args)
args->optimize();
return this;
}
bool isinteger() const;
bool isstring() const;
private:
void emit(Emit &e, const std::string &result);
Expr *called;
ArgumentList *args;
};
bool CallExpr::isinteger() const
{
if (called->isidentifier())
{
std::string name= called->getidentifier();
int numargs = args ? args->numargs() : 0;
if (const BuiltinFunction *builtin=
BuiltinFunction::find(name, numargs))
{
return builtin->resulttype() == REGint;
}
}
return false;
}
bool CallExpr::isstring() const
{
if (called->isidentifier())
{
std::string name= called->getidentifier();
int numargs = args ? args->numargs() : 0;
if (const BuiltinFunction *builtin=
BuiltinFunction::find(name, numargs))
{
return builtin->resulttype() == REGstring;
}
}
return false;
}
void CallExpr::emit(Emit &e, const std::string &result)
{
const int numargs = args ? args->numargs() : 0;
if (called->isidentifier())
{
annotate(e);
std::string name= called->getidentifier();
if (const BuiltinFunction *builtin=
BuiltinFunction::find(name, numargs))
{
std::vector<std::string> argregs;
for (int i= 0; i < numargs; ++i)
{
Expr &arg= * (args->getfreearg(i));
char paramtype= builtin->paramtype(i);
switch (paramtype)
{
case REGint:
if (arg.isliteralinteger())
argregs.push_back(arg.gettoken().str());
else if (arg.isinteger() && arg.isidentifier())
argregs.push_back(arg.getidentifier());
else
{
std::string reg= gentemp(REGint);
arg.emit(e, reg);
argregs.push_back(reg);
}
break;
case REGstring:
if (arg.isliteralstring())
argregs.push_back(arg.gettoken().pirliteralstring());
else if (arg.isstring() && arg.isidentifier())
argregs.push_back(arg.getidentifier());
else
{
std::string reg= gentemp(REGstring);
arg.emit(e, reg);
argregs.push_back(reg);
}
break;
case REGany:
argregs.push_back(arg.emit_get(e));
break;
default:
{
std::string reg= gentemp(REGvar);
char type= arg.checkresult();
switch(type)
{
case REGint:
case REGstring:
{
std::string reg2= gentemp(type);
arg.emit(e, reg2);
e << op_box(reg, reg2) << '\n';
}
break;
default:
arg.emit(e, reg);
}
argregs.push_back(reg);
}
}
}
if (builtin->resulttype())
{
std::string r;
if (result.empty())
r= gentemp(builtin->resulttype());
else
r= result;
builtin->emit(e, r, argregs);
}
else
builtin->emit(e, std::string(), argregs);
return;
}
}
if (args)
args->prepare(e);
std::string reg;
if (called->isidentifier())
{
std::string name= called->getidentifier();
bool is_local = islocal(name);
if (! is_local) {
FunctionStatement *fun = getfunction(name);
if (fun) {
name = fun->getsubid();
e << INDENT ".const 'Sub' " << name << " = '" << name << "'\n";
is_local = true;
}
}
std::string quote(is_local ? "" : "'");
name = quote + name + quote;
annotate(e);
e << INDENT;
if (!result.empty() )
e << result << " = ";
e << name << '(';
}
else
{
reg= gentemp(REGvar);
if (MemberExpr *me= dynamic_cast<MemberExpr*>(called))
{
std::string mefun= gentemp(REGvar);
me->emitleft(e, mefun);
annotate(e);
e << INDENT << reg << " = " << mefun << ".'" << me->getmember() << "'(";
}
else
{
called->emit(e, reg);
annotate(e);
e << INDENT << reg << '(';
}
}
// Arguments
if (args)
args->emit(e);
e << ')';
if (! reg.empty() )
{
e << '\n';
if (!result.empty() )
e << INDENT << result << " = " << reg << '\n';
}
else
{
if (!result.empty() )
e << '\n';
}
}
//**********************************************************************
class OpInstanceOf : public Expr
{
public:
OpInstanceOf(BlockBase &block, const Token & tstart,
Expr *subexpr, Tokenizer &tk) :
Expr(block, tstart),
obj(subexpr),
checked(tk.get())
{
}
private:
bool isinteger() const { return true; }
Expr *optimize()
{
optimize_branch(obj);
return this;
}
void emit(Emit &e, const std::string &result)
{
std::string checkedval;
if (checked.isliteralstring())
checkedval= checked.pirliteralstring();
else if (checked.isidentifier())
{
ClassKey key;
key.push_back(checked.identifier());
ClassStatement *cl = findclass(key);
if (cl)
checkedval = cl->getkey().get_key();
else
checkedval= "'" + checked.identifier() + "'";
}
else
throw CompileError("Unimplemented", checked);
std::string reg= gentemp(REGvar);
obj->emit(e, reg);
annotate(e);
if (result.empty() ) {
std::string regcheck = gentemp(REGint);
e << op_isa(regcheck, reg, checkedval) << '\n';
}
else
{
e << op_isa(result, reg, checkedval) << '\n';
}
}
Expr *obj;
Token checked;
};
//**********************************************************************
class NewExpr : public Expr
{
public:
NewExpr(BlockBase &block, Tokenizer &tk, const Token & tstart);
private:
Expr *optimize();
void emit(Emit &e, const std::string &result);
unsigned int ln;
ClassSpecifier *claspec;
ArgumentList *init;
};
NewExpr::NewExpr(BlockBase &block, Tokenizer &tk, const Token & tstart) :
Expr(block, tstart),
ln(tstart.linenum()),
init(0)
{
Token t= tk.get();
claspec = parseClassSpecifier(t, tk, block);
t= tk.get();
if (t.isop('('))
init = new ArgumentList(block, tk, ')');
else
tk.unget(t);
}
Expr *NewExpr::optimize()
{
if (init)
init->optimize();
return this;
</