mirror of
https://github.com/mozilla/gecko-dev.git
synced 2025-02-03 12:35:58 +00:00
Added do & switch statements, more hacking at the code state thing.
This commit is contained in:
parent
b7d91147d9
commit
f4b33493b8
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user