void HandleForEachStatement(ForEachStatement tree) { EnterBlock(); var f = GetCurrentFunction(); Instruction code; // get table iter HandleExpRead(tree.exp); var table_register = GenerateRegisterId(); var iter_register = table_register; code = Instruction.AB(OpType.OpType_TableIter, iter_register, table_register); f.AddInstruction(code, tree.k.m_line); EnterLoop(); { EnterBlock(); var k_register = GenerateRegisterId(); if (tree.k != null) { InsertName(tree.k.m_string, k_register); } var v_register = GenerateRegisterId(); InsertName(tree.v.m_string, v_register); code = Instruction.ABC(OpType.OpType_TableIterNext, iter_register, k_register, v_register); f.AddInstruction(code, tree.k.m_line); // jump to loop tail when the first name value is nil code = Instruction.ABx(OpType.OpType_JmpNil, k_register, 0); int index = f.AddInstruction(code, tree.k.m_line); AddLoopJumpInfo(JumpType.JumpTail, index); 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(); }
ForEachStatement ParseForEachStatement() { NextToken();// skip 'foreach' var statement = new ForEachStatement(_current.m_line); if (NextToken().m_type != (int)TokenType.NAME) { throw NewParserException("expect 'id' in foreach-statement", _current); } if (LookAhead().m_type == (int)',') { statement.k = _current; NextToken(); if (NextToken().m_type != (int)TokenType.NAME) { throw NewParserException("expect 'id' in foreach-statement after ','", _current); } statement.v = _current; } else { statement.v = _current; } if (NextToken().m_type != (int)TokenType.IN) { throw NewParserException("expect 'in' in foreach-statement", _current); } statement.exp = ParseExp(); if (NextToken().m_type != (int)TokenType.DO) { throw NewParserException("expect 'do' to start foreach-body", _current); } statement.block = ParseBlock(); if (NextToken().m_type != (int)TokenType.END) { throw NewParserException("expect 'end' to complete foreach-body", _current); } return(statement); }