ForInStatement ParseForInStatement() { var statement = new ForInStatement(_current.m_line); statement.name_list = ParseNameList(); if (NextToken().m_type != (int)TokenType.IN) { throw NewParserException("expect 'in' in for-in-statement", _current); } // 这个结构特殊,返回的是迭代器, statement.exp_list = ParseExpList(); if (NextToken().m_type != (int)TokenType.DO) { throw NewParserException("expect 'do' to start for-in-body", _current); } statement.block = ParseBlock(); if (NextToken().m_type != (int)TokenType.END) { throw NewParserException("expect 'end' to complete for-in-body", _current); } return(statement); }
void HandleForInStatement(ForInStatement tree) { EnterBlock(); var f = GetCurrentFunction(); Instruction code; // init iterator function HandleExpList(tree.exp_list, 3); var func_register = GenerateRegisterId(); var table_register = GenerateRegisterId(); var index_register = GenerateRegisterId(); EnterLoop(); { EnterBlock(); // alloca registers for names int name_start = GetNextRegisterId(); HandleNameList(tree.name_list); int name_end = GetNextRegisterId(); // allocate temp registers for call iterator function int temp_func = name_start; int temp_table = name_start + 1; int temp_index = name_start + 2; // call iterate function Action <int, int> move = (int dst, int src) => { var l_code = Instruction.AB(OpType.OpType_Move, dst, src); f.AddInstruction(l_code, tree.name_list.line); }; move(temp_func, func_register); move(temp_table, table_register); move(temp_index, index_register); code = Instruction.ABC(OpType.OpType_Call, temp_func, 2, 0); f.AddInstruction(code, tree.exp_list.line); code = Instruction.A(OpType.OpType_FillNilFromTopToA, name_end); f.AddInstruction(code, tree.exp_list.line); // jump to loop tail when the first name value is nil code = Instruction.ABx(OpType.OpType_JmpNil, name_start, 0); int index = f.AddInstruction(code, tree.exp_list.line); AddLoopJumpInfo(JumpType.JumpTail, index); // index = name1 move(index_register, name_start); HandleBlock(tree.block); LeaveBlock(); // jump to loop head code = Instruction.Bx(OpType.OpType_Jmp, 0); index = f.AddInstruction(code, -1); AddLoopJumpInfo(JumpType.JumpHead, index); } LeaveLoop(); LeaveBlock(); }