Added do & switch statements, more hacking at the code state thing.

This commit is contained in:
rogerl%netscape.com 2000-04-01 01:30:32 +00:00
Родитель b7d91147d9
Коммит f4b33493b8
6 изменённых файлов: 590 добавлений и 120 удалений

Просмотреть файл

@ -144,24 +144,37 @@ void ICodeGenerator::setLabel(int32 label)
l->itsOffset = iCode->size();
}
void ICodeGenerator::setLabel(InstructionStream *stream, int32 label)
{
Label* l;
#ifdef __GNUC__
// libg++'s vector class doesn't have at():
if (label >= labels.size())
throw std::out_of_range("label out of range");
l = labels[label];
#else
l = labels.at(label);
#endif
l->itsBase = stream;
l->itsOffset = stream->size();
}
/***********************************************************************************************/
void MultiPathICodeState::mergeStream(InstructionStream *mainStream, LabelList &labels)
{
if (itsTopLabel < labels.size()) {
// labels (might) have been allocated in this stream
// we need to adjust their position relative to the
// size of the stream we're joining
for (LabelList::iterator i = labels.begin() + itsTopLabel; i != labels.end(); i++) {
if ((*i)->itsBase == its_iCode) {
(*i)->itsBase = mainStream;
(*i)->itsOffset += mainStream->size();
}
// change InstructionStream to be a class that also remembers
// if it contains any labels (maybe even remembers the labels
// themselves?) in order to avoid running this loop unnecessarily.
for (LabelList::iterator i = labels.begin(); i != labels.end(); i++) {
if ((*i)->itsBase == its_iCode) {
(*i)->itsBase = mainStream;
(*i)->itsOffset += mainStream->size();
}
}
for (InstructionIterator i = its_iCode->begin(); i != its_iCode->end(); i++)
mainStream->push_back(*i);
for (InstructionIterator ii = its_iCode->begin(); ii != its_iCode->end(); ii++)
mainStream->push_back(*ii);
}
@ -178,43 +191,176 @@ void ICodeGenerator::beginWhileStatement(const SourcePosition &pos)
branch(whileConditionTop);
// save off the current stream while we gen code for the condition
stitcher.push(new WhileCodeState(iCode, labels.size(), whileConditionTop, whileBlockStart));
stitcher.push_back(new WhileCodeState(whileConditionTop, whileBlockStart, this));
iCode = new InstructionStream();
}
void ICodeGenerator::endWhileExpression(Register condition)
{
WhileCodeState *ics = static_cast<WhileCodeState *>(stitcher.top());
ASSERT(ics->stateKind == While_State);
WhileCodeState *ics = static_cast<WhileCodeState *>(stitcher.back());
ASSERT(ics->stateKind == While_state);
branchConditional(ics->whileBodyLabel, condition);
branchConditional(ics->whileBody, condition);
resetTopRegister();
// stash away the condition expression and switch
// back to the main stream
iCode = ics->swapStream(iCode);
setLabel(ics->whileBodyLabel); // mark the start of the while block
setLabel(ics->whileBody); // mark the start of the while block
}
void ICodeGenerator::endWhileStatement()
{
// recover the while stream
WhileCodeState *ics = static_cast<WhileCodeState *>(stitcher.top());
ASSERT(ics->stateKind == While_State);
stitcher.pop();
WhileCodeState *ics = static_cast<WhileCodeState *>(stitcher.back());
ASSERT(ics->stateKind == While_state);
stitcher.pop_back();
// mark the start of the condition code
// and re-attach it to the main stream
setLabel(ics->whileConditionLabel);
setLabel(ics->whileCondition);
ics->mergeStream(iCode, labels);
if (ics->breakLabel != -1)
setLabel(ics->breakLabel);
delete ics->its_iCode;
delete ics;
resetTopRegister();
}
/***********************************************************************************************/
void ICodeGenerator::beginDoStatement(const SourcePosition &pos)
{
resetTopRegister();
// mark the top of the loop body
// and reserve a label for the condition
int32 doBlock = getLabel();
int32 doCondition = getLabel();
setLabel(doBlock);
stitcher.push_back(new DoCodeState(doBlock, doCondition, this));
iCode = new InstructionStream();
}
void ICodeGenerator::endDoStatement()
{
DoCodeState *ics = static_cast<DoCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Do_state);
// mark the start of the do conditional
setLabel(ics->doCondition);
resetTopRegister();
}
void ICodeGenerator::endDoExpression(Register condition)
{
DoCodeState *ics = static_cast<DoCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Do_state);
stitcher.pop_back();
// add branch to top of do block
branchConditional(ics->doBody, condition);
if (ics->breakLabel != -1)
setLabel(ics->breakLabel);
delete ics;
resetTopRegister();
}
/***********************************************************************************************/
void ICodeGenerator::beginSwitchStatement(const SourcePosition &pos, Register expression)
{
// stash the control expression value
resetTopRegister();
op(MOVE_TO, getRegister(), expression);
// build an instruction stream for the case statements, the case
// expressions are generated into the main stream directly, the
// case statements are then added back in afterwards.
InstructionStream *x = new InstructionStream();
SwitchCodeState *ics = new SwitchCodeState(expression, this);
ics->swapStream(x);
stitcher.push_back(ics);
}
void ICodeGenerator::endCaseCondition(Register expression)
{
SwitchCodeState *ics = static_cast<SwitchCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Switch_state);
int32 caseLabel = getLabel();
Register r = op(COMPARE, expression, ics->controlExpression);
branchConditional(caseLabel, r);
setLabel(ics->its_iCode, caseLabel); // mark the case in the Case Statement stream
resetTopRegister();
}
void ICodeGenerator::beginCaseStatement()
{
SwitchCodeState *ics = static_cast<SwitchCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Switch_state);
iCode = ics->swapStream(iCode); // switch to Case Statement stream
}
void ICodeGenerator::endCaseStatement()
{
SwitchCodeState *ics = static_cast<SwitchCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Switch_state); // do more to guarantee correct blocking?
iCode = ics->swapStream(iCode); // switch back to Case Conditional stream
resetTopRegister();
}
void ICodeGenerator::beginDefaultStatement()
{
SwitchCodeState *ics = static_cast<SwitchCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Switch_state);
ASSERT(ics->defaultLabel == -1);
ics->defaultLabel = getLabel();
setLabel(ics->its_iCode, ics->defaultLabel);
iCode = ics->swapStream(iCode); // switch to Case Statement stream
}
void ICodeGenerator::endDefaultStatement()
{
SwitchCodeState *ics = static_cast<SwitchCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Switch_state);
ASSERT(ics->defaultLabel != -1); // do more to guarantee correct blocking?
iCode = ics->swapStream(iCode); // switch to Case Statement stream
resetTopRegister();
}
void ICodeGenerator::endSwitchStatement()
{
SwitchCodeState *ics = static_cast<SwitchCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Switch_state);
stitcher.pop_back();
// ground out the case chain at the default block or fall thru
// to the break label
if (ics->defaultLabel != -1)
branch(ics->defaultLabel);
else {
if (ics->breakLabel == -1)
ics->breakLabel = getLabel();
branch(ics->breakLabel);
}
// dump all the case statements into the main stream
ics->mergeStream(iCode, labels);
if (ics->breakLabel != -1)
setLabel(ics->breakLabel);
delete ics;
}
/***********************************************************************************************/
@ -222,7 +368,7 @@ void ICodeGenerator::beginIfStatement(const SourcePosition &pos, Register condit
{
int32 elseLabel = getLabel();
stitcher.push(new IfCodeState(elseLabel, -1));
stitcher.push_back(new IfCodeState(elseLabel, -1, this));
Register notCond = op(NOT, condition);
branchConditional(elseLabel, notCond);
@ -232,8 +378,8 @@ void ICodeGenerator::beginIfStatement(const SourcePosition &pos, Register condit
void ICodeGenerator::beginElseStatement(bool hasElse)
{
IfCodeState *ics = static_cast<IfCodeState *>(stitcher.top());
ASSERT(ics->stateKind == If_State);
IfCodeState *ics = static_cast<IfCodeState *>(stitcher.back());
ASSERT(ics->stateKind == If_state);
if (hasElse) {
int32 beyondElse = getLabel();
@ -246,35 +392,54 @@ void ICodeGenerator::beginElseStatement(bool hasElse)
void ICodeGenerator::endIfStatement()
{
IfCodeState *ics = static_cast<IfCodeState *>(stitcher.top());
ASSERT(ics->stateKind == If_State);
IfCodeState *ics = static_cast<IfCodeState *>(stitcher.back());
ASSERT(ics->stateKind == If_state);
stitcher.pop_back();
if (ics->beyondElse != -1) { // had an else
setLabel(ics->beyondElse); // the beyond else label
}
stitcher.pop();
delete ics;
resetTopRegister();
}
/***********************************************************************************************/
void ICodeGenerator::breakStatement()
{
for (std::vector<ICodeState *>::reverse_iterator p = stitcher.rbegin(); p != stitcher.rend(); p++) {
// this is NOT going to stay this way
if (((*p)->stateKind == While_state)
|| ((*p)->stateKind == Do_state)
|| ((*p)->stateKind == For_state)
|| ((*p)->stateKind == Switch_state)) {
if ((*p)->breakLabel == -1)
(*p)->breakLabel = getLabel();
branch((*p)->breakLabel);
return;
}
}
NOT_REACHED("no break target available");
}
/***********************************************************************************************/
char *opcodeName[] = {
"move_to",
"load_var",
"save_var",
"load_imm",
"load_name",
"save_name",
"get_prop",
"set_prop",
"add",
"compare",
"not",
"branch",
"branch_cond",
};
@ -330,11 +495,13 @@ ostream &ICodeGenerator::print(ostream &s)
}
break;
case ADD :
case COMPARE :
{
Instruction_3<Register, Register, Register> *t = static_cast<Instruction_3<Register, Register, Register> * >(instr);
s << "R" << t->itsOperand1 << ", R" << t->itsOperand2 << ", R" << t->itsOperand3;
}
break;
case MOVE_TO :
case NOT :
{
Instruction_3<Register, Register, Register> *t = static_cast<Instruction_3<Register, Register, Register> * >(instr);

Просмотреть файл

@ -34,6 +34,8 @@ namespace JavaScript {
enum ICodeOp {
// Operand1 Operand2 Operand3
MOVE_TO, // Source Register Destination Register
LOAD_VAR, // index of frame slot Destination Register
SAVE_VAR, // index of frame slot Source Register
@ -46,6 +48,7 @@ namespace JavaScript {
SET_PROP, // StringAtom & Base Register Source Register
ADD, // Source Register 1 Source Register 2 Destination Register
COMPARE, // Source Register 1 Source Register 2 Destination Register
NOT, // Source Register Destination Register
BRANCH, // Target label
@ -104,46 +107,66 @@ namespace JavaScript {
/****************************************************************/
/****************************************************************/
enum StateKind { While_State, If_State };
class ICodeGenerator; // forward declaration
class ICodeState {
enum StateKind { While_state, If_state, Do_state, Switch_state, For_state };
class ICodeState {
public :
ICodeState(StateKind kind) : stateKind(kind) { }
ICodeState(StateKind kind, ICodeGenerator *icg); // inline below
StateKind stateKind;
int32 breakLabel;
int32 continueLabel;
int32 registerBase;
};
// an ICodeState that handles switching to a new InstructionStream
// and then re-combining the streams later
class MultiPathICodeState : public ICodeState {
public:
MultiPathICodeState(StateKind kind,InstructionStream *iCode, int32 topLabel)
: ICodeState(kind), its_iCode(iCode), itsTopLabel(topLabel) {}
MultiPathICodeState(StateKind kind, ICodeGenerator *icg); // inline below
virtual ~MultiPathICodeState() { delete its_iCode; }
InstructionStream *swapStream(InstructionStream *iCode) { InstructionStream *t = its_iCode; its_iCode = iCode; return t; }
InstructionStream *its_iCode;
int32 itsTopLabel; // set to the highest label allocated when this stream
// was created. If that value changes, this stream may
// contain labels that will need to be adjusted when
// the streams are merged.
void mergeStream(InstructionStream *mainStream, LabelList &labels);
};
class WhileCodeState : public MultiPathICodeState {
public:
WhileCodeState(InstructionStream *iCode, int32 topLabel, int32 a, int32 b)
: MultiPathICodeState(While_State, iCode, topLabel), whileConditionLabel(a), whileBodyLabel(b) { }
int32 whileConditionLabel;
int32 whileBodyLabel;
WhileCodeState(int32 conditionLabel, int32 bodyLabel, ICodeGenerator *icg)
: MultiPathICodeState(While_state, icg), whileCondition(conditionLabel), whileBody(bodyLabel) { }
int32 whileCondition;
int32 whileBody;
};
class IfCodeState : public ICodeState {
public:
IfCodeState(int32 a, int32 b) : ICodeState(If_State), elseLabel(a), beyondElse(b) { }
IfCodeState(int32 a, int32 b, ICodeGenerator *icg)
: ICodeState(If_state, icg), elseLabel(a), beyondElse(b) { }
int32 elseLabel;
int32 beyondElse;
};
class DoCodeState : public ICodeState {
public:
DoCodeState(int32 bodyLabel, int32 conditionLabel, ICodeGenerator *icg)
: ICodeState(Do_state, icg), doBody(bodyLabel), doCondition(conditionLabel) { }
int32 doBody;
int32 doCondition;
};
class SwitchCodeState : public MultiPathICodeState {
public:
SwitchCodeState(Register control, ICodeGenerator *icg)
: MultiPathICodeState(Switch_state, icg), controlExpression(control), defaultLabel(-1) { }
Register controlExpression;
int32 defaultLabel;
};
/****************************************************************/
// An ICodeGenerator provides the interface between the parser and the interpreter.
@ -157,20 +180,21 @@ namespace JavaScript {
LabelList labels;
std::stack<ICodeState *> stitcher;
std::vector<ICodeState *> stitcher;
Register topRegister;
Register getRegister() { return topRegister++; }
void resetTopRegister() { topRegister = 0; }
void resetTopRegister() { topRegister = stitcher.empty() ? 0 : stitcher.back()->registerBase; }
int32 getLabel();
void setLabel(int32 label);
void setLabel(InstructionStream *stream, int32 label);
void branch(int32 label);
void branchConditional(int32 label, Register condition);
public:
ICodeGenerator() { iCode = new InstructionStream(); }
ICodeGenerator() : topRegister(0) { iCode = new InstructionStream(); }
InstructionStream *complete();
@ -187,8 +211,8 @@ namespace JavaScript {
Register loadName(StringAtom &name);
Register getProperty(StringAtom &name, Register base);
void beginStatement(const SourcePosition &pos) { resetTopRegister(); }
Register getRegisterBase() { return topRegister; }
InstructionStream *get_iCode() { return iCode; }
// Rather than have the ICG client maniplate labels and branches, it
@ -197,13 +221,16 @@ namespace JavaScript {
// in the order listed for each construct, (internal error otherwise).
// The ICG will enforce correct nesting and closing.
// expression statements
void beginStatement(const SourcePosition &pos) { resetTopRegister(); }
void beginWhileStatement(const SourcePosition &pos);
void endWhileExpression(Register condition);
void endWhileStatement();
void beginDoStatement();
void beginDoStatement(const SourcePosition &pos);
void endDoStatement();
void endDoExpression(Register condition);
@ -220,23 +247,27 @@ namespace JavaScript {
void endForStatement();
void beginSwitchStatement(Register expression);
void beginSwitchStatement(const SourcePosition &pos, Register expression);
// sequences of the next three follow for each case clause
void beginCaseStatement();
void endCaseCondition(Register expression);
void endCaseStatement(); // corresponds to a break and may be omitted
void beginCaseStatement();
void endCaseStatement();
// optionally
void beginDefaultStatement();
void endDefaultStatement(); // the break for the default clause, may be omitted
void endDefaultStatement();
void endSwitchStatement();
void labelStatement(const StringAtom &label); // adds to label set for next statement,
// removed when that statement is finished
void labelStatement(const StringAtom &label); // adds to label set for next statement,
// removed when that statement is finished
void continueStatement();
void breakStatement();
void continueStatement(const StringAtom &label);
void breakStatement(const StringAtom &label);
void throwStatement(Register expression);
@ -253,5 +284,11 @@ namespace JavaScript {
ostream &operator<<(ostream &s, ICodeGenerator &i);
ostream &operator<<(ostream &s, StringAtom &str);
inline ICodeState::ICodeState(StateKind kind, ICodeGenerator *icg)
: stateKind(kind), breakLabel(-1), continueLabel(-1), registerBase(icg->getRegisterBase()) { }
inline MultiPathICodeState::MultiPathICodeState(StateKind kind, ICodeGenerator *icg)
: ICodeState(kind, icg), its_iCode(icg->get_iCode()) {}
}
#endif

Просмотреть файл

@ -371,6 +371,37 @@ void testICG(World &world)
icg.beginElseStatement(false);
icg.endIfStatement();
// switch (i) { case 3: case 4: j = 4; break; case 5: j = 5; break; default : j = 6; }
r1 = icg.loadVariable(0);
icg.beginSwitchStatement(pos, r1);
// case 3, note empty case statement (?necessary???)
icg.endCaseCondition(icg.loadImmediate(3));
icg.beginCaseStatement();
icg.endCaseStatement();
// case 4
icg.endCaseCondition(icg.loadImmediate(4));
icg.beginCaseStatement();
icg.beginStatement(pos);
icg.saveVariable(1, icg.loadImmediate(4));
icg.breakStatement();
icg.endCaseStatement();
// case 5
icg.endCaseCondition(icg.loadImmediate(5));
icg.beginCaseStatement();
icg.beginStatement(pos);
icg.saveVariable(1, icg.loadImmediate(5));
icg.breakStatement();
icg.endCaseStatement();
// default
icg.beginDefaultStatement();
icg.beginStatement(pos);
icg.saveVariable(1, icg.loadImmediate(6));
icg.endDefaultStatement();
icg.endSwitchStatement();
InstructionStream *iCode = icg.complete();
std::cout << icg;
}
@ -380,7 +411,7 @@ int main(int argc, char **argv)
initConsole("\pJavaScript Shell", "Welcome to the js2 shell.\n", argc, argv);
#endif
World world;
#if 0
#if 1
testICG(world);
#else
readEvalPrint(std::cin, world);

Просмотреть файл

@ -144,24 +144,37 @@ void ICodeGenerator::setLabel(int32 label)
l->itsOffset = iCode->size();
}
void ICodeGenerator::setLabel(InstructionStream *stream, int32 label)
{
Label* l;
#ifdef __GNUC__
// libg++'s vector class doesn't have at():
if (label >= labels.size())
throw std::out_of_range("label out of range");
l = labels[label];
#else
l = labels.at(label);
#endif
l->itsBase = stream;
l->itsOffset = stream->size();
}
/***********************************************************************************************/
void MultiPathICodeState::mergeStream(InstructionStream *mainStream, LabelList &labels)
{
if (itsTopLabel < labels.size()) {
// labels (might) have been allocated in this stream
// we need to adjust their position relative to the
// size of the stream we're joining
for (LabelList::iterator i = labels.begin() + itsTopLabel; i != labels.end(); i++) {
if ((*i)->itsBase == its_iCode) {
(*i)->itsBase = mainStream;
(*i)->itsOffset += mainStream->size();
}
// change InstructionStream to be a class that also remembers
// if it contains any labels (maybe even remembers the labels
// themselves?) in order to avoid running this loop unnecessarily.
for (LabelList::iterator i = labels.begin(); i != labels.end(); i++) {
if ((*i)->itsBase == its_iCode) {
(*i)->itsBase = mainStream;
(*i)->itsOffset += mainStream->size();
}
}
for (InstructionIterator i = its_iCode->begin(); i != its_iCode->end(); i++)
mainStream->push_back(*i);
for (InstructionIterator ii = its_iCode->begin(); ii != its_iCode->end(); ii++)
mainStream->push_back(*ii);
}
@ -178,43 +191,176 @@ void ICodeGenerator::beginWhileStatement(const SourcePosition &pos)
branch(whileConditionTop);
// save off the current stream while we gen code for the condition
stitcher.push(new WhileCodeState(iCode, labels.size(), whileConditionTop, whileBlockStart));
stitcher.push_back(new WhileCodeState(whileConditionTop, whileBlockStart, this));
iCode = new InstructionStream();
}
void ICodeGenerator::endWhileExpression(Register condition)
{
WhileCodeState *ics = static_cast<WhileCodeState *>(stitcher.top());
ASSERT(ics->stateKind == While_State);
WhileCodeState *ics = static_cast<WhileCodeState *>(stitcher.back());
ASSERT(ics->stateKind == While_state);
branchConditional(ics->whileBodyLabel, condition);
branchConditional(ics->whileBody, condition);
resetTopRegister();
// stash away the condition expression and switch
// back to the main stream
iCode = ics->swapStream(iCode);
setLabel(ics->whileBodyLabel); // mark the start of the while block
setLabel(ics->whileBody); // mark the start of the while block
}
void ICodeGenerator::endWhileStatement()
{
// recover the while stream
WhileCodeState *ics = static_cast<WhileCodeState *>(stitcher.top());
ASSERT(ics->stateKind == While_State);
stitcher.pop();
WhileCodeState *ics = static_cast<WhileCodeState *>(stitcher.back());
ASSERT(ics->stateKind == While_state);
stitcher.pop_back();
// mark the start of the condition code
// and re-attach it to the main stream
setLabel(ics->whileConditionLabel);
setLabel(ics->whileCondition);
ics->mergeStream(iCode, labels);
if (ics->breakLabel != -1)
setLabel(ics->breakLabel);
delete ics->its_iCode;
delete ics;
resetTopRegister();
}
/***********************************************************************************************/
void ICodeGenerator::beginDoStatement(const SourcePosition &pos)
{
resetTopRegister();
// mark the top of the loop body
// and reserve a label for the condition
int32 doBlock = getLabel();
int32 doCondition = getLabel();
setLabel(doBlock);
stitcher.push_back(new DoCodeState(doBlock, doCondition, this));
iCode = new InstructionStream();
}
void ICodeGenerator::endDoStatement()
{
DoCodeState *ics = static_cast<DoCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Do_state);
// mark the start of the do conditional
setLabel(ics->doCondition);
resetTopRegister();
}
void ICodeGenerator::endDoExpression(Register condition)
{
DoCodeState *ics = static_cast<DoCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Do_state);
stitcher.pop_back();
// add branch to top of do block
branchConditional(ics->doBody, condition);
if (ics->breakLabel != -1)
setLabel(ics->breakLabel);
delete ics;
resetTopRegister();
}
/***********************************************************************************************/
void ICodeGenerator::beginSwitchStatement(const SourcePosition &pos, Register expression)
{
// stash the control expression value
resetTopRegister();
op(MOVE_TO, getRegister(), expression);
// build an instruction stream for the case statements, the case
// expressions are generated into the main stream directly, the
// case statements are then added back in afterwards.
InstructionStream *x = new InstructionStream();
SwitchCodeState *ics = new SwitchCodeState(expression, this);
ics->swapStream(x);
stitcher.push_back(ics);
}
void ICodeGenerator::endCaseCondition(Register expression)
{
SwitchCodeState *ics = static_cast<SwitchCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Switch_state);
int32 caseLabel = getLabel();
Register r = op(COMPARE, expression, ics->controlExpression);
branchConditional(caseLabel, r);
setLabel(ics->its_iCode, caseLabel); // mark the case in the Case Statement stream
resetTopRegister();
}
void ICodeGenerator::beginCaseStatement()
{
SwitchCodeState *ics = static_cast<SwitchCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Switch_state);
iCode = ics->swapStream(iCode); // switch to Case Statement stream
}
void ICodeGenerator::endCaseStatement()
{
SwitchCodeState *ics = static_cast<SwitchCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Switch_state); // do more to guarantee correct blocking?
iCode = ics->swapStream(iCode); // switch back to Case Conditional stream
resetTopRegister();
}
void ICodeGenerator::beginDefaultStatement()
{
SwitchCodeState *ics = static_cast<SwitchCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Switch_state);
ASSERT(ics->defaultLabel == -1);
ics->defaultLabel = getLabel();
setLabel(ics->its_iCode, ics->defaultLabel);
iCode = ics->swapStream(iCode); // switch to Case Statement stream
}
void ICodeGenerator::endDefaultStatement()
{
SwitchCodeState *ics = static_cast<SwitchCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Switch_state);
ASSERT(ics->defaultLabel != -1); // do more to guarantee correct blocking?
iCode = ics->swapStream(iCode); // switch to Case Statement stream
resetTopRegister();
}
void ICodeGenerator::endSwitchStatement()
{
SwitchCodeState *ics = static_cast<SwitchCodeState *>(stitcher.back());
ASSERT(ics->stateKind == Switch_state);
stitcher.pop_back();
// ground out the case chain at the default block or fall thru
// to the break label
if (ics->defaultLabel != -1)
branch(ics->defaultLabel);
else {
if (ics->breakLabel == -1)
ics->breakLabel = getLabel();
branch(ics->breakLabel);
}
// dump all the case statements into the main stream
ics->mergeStream(iCode, labels);
if (ics->breakLabel != -1)
setLabel(ics->breakLabel);
delete ics;
}
/***********************************************************************************************/
@ -222,7 +368,7 @@ void ICodeGenerator::beginIfStatement(const SourcePosition &pos, Register condit
{
int32 elseLabel = getLabel();
stitcher.push(new IfCodeState(elseLabel, -1));
stitcher.push_back(new IfCodeState(elseLabel, -1, this));
Register notCond = op(NOT, condition);
branchConditional(elseLabel, notCond);
@ -232,8 +378,8 @@ void ICodeGenerator::beginIfStatement(const SourcePosition &pos, Register condit
void ICodeGenerator::beginElseStatement(bool hasElse)
{
IfCodeState *ics = static_cast<IfCodeState *>(stitcher.top());
ASSERT(ics->stateKind == If_State);
IfCodeState *ics = static_cast<IfCodeState *>(stitcher.back());
ASSERT(ics->stateKind == If_state);
if (hasElse) {
int32 beyondElse = getLabel();
@ -246,35 +392,54 @@ void ICodeGenerator::beginElseStatement(bool hasElse)
void ICodeGenerator::endIfStatement()
{
IfCodeState *ics = static_cast<IfCodeState *>(stitcher.top());
ASSERT(ics->stateKind == If_State);
IfCodeState *ics = static_cast<IfCodeState *>(stitcher.back());
ASSERT(ics->stateKind == If_state);
stitcher.pop_back();
if (ics->beyondElse != -1) { // had an else
setLabel(ics->beyondElse); // the beyond else label
}
stitcher.pop();
delete ics;
resetTopRegister();
}
/***********************************************************************************************/
void ICodeGenerator::breakStatement()
{
for (std::vector<ICodeState *>::reverse_iterator p = stitcher.rbegin(); p != stitcher.rend(); p++) {
// this is NOT going to stay this way
if (((*p)->stateKind == While_state)
|| ((*p)->stateKind == Do_state)
|| ((*p)->stateKind == For_state)
|| ((*p)->stateKind == Switch_state)) {
if ((*p)->breakLabel == -1)
(*p)->breakLabel = getLabel();
branch((*p)->breakLabel);
return;
}
}
NOT_REACHED("no break target available");
}
/***********************************************************************************************/
char *opcodeName[] = {
"move_to",
"load_var",
"save_var",
"load_imm",
"load_name",
"save_name",
"get_prop",
"set_prop",
"add",
"compare",
"not",
"branch",
"branch_cond",
};
@ -330,11 +495,13 @@ ostream &ICodeGenerator::print(ostream &s)
}
break;
case ADD :
case COMPARE :
{
Instruction_3<Register, Register, Register> *t = static_cast<Instruction_3<Register, Register, Register> * >(instr);
s << "R" << t->itsOperand1 << ", R" << t->itsOperand2 << ", R" << t->itsOperand3;
}
break;
case MOVE_TO :
case NOT :
{
Instruction_3<Register, Register, Register> *t = static_cast<Instruction_3<Register, Register, Register> * >(instr);

Просмотреть файл

@ -34,6 +34,8 @@ namespace JavaScript {
enum ICodeOp {
// Operand1 Operand2 Operand3
MOVE_TO, // Source Register Destination Register
LOAD_VAR, // index of frame slot Destination Register
SAVE_VAR, // index of frame slot Source Register
@ -46,6 +48,7 @@ namespace JavaScript {
SET_PROP, // StringAtom & Base Register Source Register
ADD, // Source Register 1 Source Register 2 Destination Register
COMPARE, // Source Register 1 Source Register 2 Destination Register
NOT, // Source Register Destination Register
BRANCH, // Target label
@ -104,46 +107,66 @@ namespace JavaScript {
/****************************************************************/
/****************************************************************/
enum StateKind { While_State, If_State };
class ICodeGenerator; // forward declaration
class ICodeState {
enum StateKind { While_state, If_state, Do_state, Switch_state, For_state };
class ICodeState {
public :
ICodeState(StateKind kind) : stateKind(kind) { }
ICodeState(StateKind kind, ICodeGenerator *icg); // inline below
StateKind stateKind;
int32 breakLabel;
int32 continueLabel;
int32 registerBase;
};
// an ICodeState that handles switching to a new InstructionStream
// and then re-combining the streams later
class MultiPathICodeState : public ICodeState {
public:
MultiPathICodeState(StateKind kind,InstructionStream *iCode, int32 topLabel)
: ICodeState(kind), its_iCode(iCode), itsTopLabel(topLabel) {}
MultiPathICodeState(StateKind kind, ICodeGenerator *icg); // inline below
virtual ~MultiPathICodeState() { delete its_iCode; }
InstructionStream *swapStream(InstructionStream *iCode) { InstructionStream *t = its_iCode; its_iCode = iCode; return t; }
InstructionStream *its_iCode;
int32 itsTopLabel; // set to the highest label allocated when this stream
// was created. If that value changes, this stream may
// contain labels that will need to be adjusted when
// the streams are merged.
void mergeStream(InstructionStream *mainStream, LabelList &labels);
};
class WhileCodeState : public MultiPathICodeState {
public:
WhileCodeState(InstructionStream *iCode, int32 topLabel, int32 a, int32 b)
: MultiPathICodeState(While_State, iCode, topLabel), whileConditionLabel(a), whileBodyLabel(b) { }
int32 whileConditionLabel;
int32 whileBodyLabel;
WhileCodeState(int32 conditionLabel, int32 bodyLabel, ICodeGenerator *icg)
: MultiPathICodeState(While_state, icg), whileCondition(conditionLabel), whileBody(bodyLabel) { }
int32 whileCondition;
int32 whileBody;
};
class IfCodeState : public ICodeState {
public:
IfCodeState(int32 a, int32 b) : ICodeState(If_State), elseLabel(a), beyondElse(b) { }
IfCodeState(int32 a, int32 b, ICodeGenerator *icg)
: ICodeState(If_state, icg), elseLabel(a), beyondElse(b) { }
int32 elseLabel;
int32 beyondElse;
};
class DoCodeState : public ICodeState {
public:
DoCodeState(int32 bodyLabel, int32 conditionLabel, ICodeGenerator *icg)
: ICodeState(Do_state, icg), doBody(bodyLabel), doCondition(conditionLabel) { }
int32 doBody;
int32 doCondition;
};
class SwitchCodeState : public MultiPathICodeState {
public:
SwitchCodeState(Register control, ICodeGenerator *icg)
: MultiPathICodeState(Switch_state, icg), controlExpression(control), defaultLabel(-1) { }
Register controlExpression;
int32 defaultLabel;
};
/****************************************************************/
// An ICodeGenerator provides the interface between the parser and the interpreter.
@ -157,20 +180,21 @@ namespace JavaScript {
LabelList labels;
std::stack<ICodeState *> stitcher;
std::vector<ICodeState *> stitcher;
Register topRegister;
Register getRegister() { return topRegister++; }
void resetTopRegister() { topRegister = 0; }
void resetTopRegister() { topRegister = stitcher.empty() ? 0 : stitcher.back()->registerBase; }
int32 getLabel();
void setLabel(int32 label);
void setLabel(InstructionStream *stream, int32 label);
void branch(int32 label);
void branchConditional(int32 label, Register condition);
public:
ICodeGenerator() { iCode = new InstructionStream(); }
ICodeGenerator() : topRegister(0) { iCode = new InstructionStream(); }
InstructionStream *complete();
@ -187,8 +211,8 @@ namespace JavaScript {
Register loadName(StringAtom &name);
Register getProperty(StringAtom &name, Register base);
void beginStatement(const SourcePosition &pos) { resetTopRegister(); }
Register getRegisterBase() { return topRegister; }
InstructionStream *get_iCode() { return iCode; }
// Rather than have the ICG client maniplate labels and branches, it
@ -197,13 +221,16 @@ namespace JavaScript {
// in the order listed for each construct, (internal error otherwise).
// The ICG will enforce correct nesting and closing.
// expression statements
void beginStatement(const SourcePosition &pos) { resetTopRegister(); }
void beginWhileStatement(const SourcePosition &pos);
void endWhileExpression(Register condition);
void endWhileStatement();
void beginDoStatement();
void beginDoStatement(const SourcePosition &pos);
void endDoStatement();
void endDoExpression(Register condition);
@ -220,23 +247,27 @@ namespace JavaScript {
void endForStatement();
void beginSwitchStatement(Register expression);
void beginSwitchStatement(const SourcePosition &pos, Register expression);
// sequences of the next three follow for each case clause
void beginCaseStatement();
void endCaseCondition(Register expression);
void endCaseStatement(); // corresponds to a break and may be omitted
void beginCaseStatement();
void endCaseStatement();
// optionally
void beginDefaultStatement();
void endDefaultStatement(); // the break for the default clause, may be omitted
void endDefaultStatement();
void endSwitchStatement();
void labelStatement(const StringAtom &label); // adds to label set for next statement,
// removed when that statement is finished
void labelStatement(const StringAtom &label); // adds to label set for next statement,
// removed when that statement is finished
void continueStatement();
void breakStatement();
void continueStatement(const StringAtom &label);
void breakStatement(const StringAtom &label);
void throwStatement(Register expression);
@ -253,5 +284,11 @@ namespace JavaScript {
ostream &operator<<(ostream &s, ICodeGenerator &i);
ostream &operator<<(ostream &s, StringAtom &str);
inline ICodeState::ICodeState(StateKind kind, ICodeGenerator *icg)
: stateKind(kind), breakLabel(-1), continueLabel(-1), registerBase(icg->getRegisterBase()) { }
inline MultiPathICodeState::MultiPathICodeState(StateKind kind, ICodeGenerator *icg)
: ICodeState(kind, icg), its_iCode(icg->get_iCode()) {}
}
#endif

Просмотреть файл

@ -371,6 +371,37 @@ void testICG(World &world)
icg.beginElseStatement(false);
icg.endIfStatement();
// switch (i) { case 3: case 4: j = 4; break; case 5: j = 5; break; default : j = 6; }
r1 = icg.loadVariable(0);
icg.beginSwitchStatement(pos, r1);
// case 3, note empty case statement (?necessary???)
icg.endCaseCondition(icg.loadImmediate(3));
icg.beginCaseStatement();
icg.endCaseStatement();
// case 4
icg.endCaseCondition(icg.loadImmediate(4));
icg.beginCaseStatement();
icg.beginStatement(pos);
icg.saveVariable(1, icg.loadImmediate(4));
icg.breakStatement();
icg.endCaseStatement();
// case 5
icg.endCaseCondition(icg.loadImmediate(5));
icg.beginCaseStatement();
icg.beginStatement(pos);
icg.saveVariable(1, icg.loadImmediate(5));
icg.breakStatement();
icg.endCaseStatement();
// default
icg.beginDefaultStatement();
icg.beginStatement(pos);
icg.saveVariable(1, icg.loadImmediate(6));
icg.endDefaultStatement();
icg.endSwitchStatement();
InstructionStream *iCode = icg.complete();
std::cout << icg;
}
@ -380,7 +411,7 @@ int main(int argc, char **argv)
initConsole("\pJavaScript Shell", "Welcome to the js2 shell.\n", argc, argv);
#endif
World world;
#if 0
#if 1
testICG(world);
#else
readEvalPrint(std::cin, world);