/// <summary> /// Seeks the <see cref="SourceLine"/> containing the /// first instance one of the directives in the block. /// </summary> /// <param name="iterator">The source line iterator.</param> /// <param name="directives">An array of directives, one of which to seek in the block.</param> protected void SeekBlockDirectives(RandomAccessIterator <SourceLine> iterator, StringView[] directives) { var line = iterator.Current; if (!line.Instruction.Name.Equals(BlockClosure, Services.StringComparison)) { var blockClose = BlockClosure; var keywordsNotToSkip = new List <StringView>(directives) { blockClose }; keywordsNotToSkip.AddRange(BlockOpens.Select(bo => new StringView(bo))); var opens = 1; while (opens != 0) { line = iterator.FirstOrDefault(l => l.Instruction != null && keywordsNotToSkip.Contains(l.Instruction.Name, Services.StringViewComparer)); if (line == null) { throw new BlockClosureException(BlockOpens.First()); } if (BlockOpens.Contains(line.Instruction.Name.ToString(), Services.StringComparer)) { opens++; } if (opens < 2 && directives.Contains(line.Instruction.Name, Services.StringViewComparer)) { break; } if (line.Instruction.Name.Equals(blockClose, Services.StringComparison)) { opens--; } } } }
string DoGoto(RandomAccessIterator <SourceLine> lines) { var line = lines.Current; if (line.Operands.Count == 0) { throw new SyntaxException(line.Instruction.Position, "Destination not specified for \".goto\" directive."); } var gotoExp = line.Operands[0].Name; if ((!char.IsLetter(gotoExp[0]) && gotoExp[0] != '_') || line.Operands.Count > 1) { Services.Log.LogEntry(line.Operands[0], "\".goto\" operand must be a label."); } else if (line.Label != null && gotoExp.Equals(line.Label.Name, Services.StringViewComparer)) { Services.Log.LogEntry(line.Instruction, "Destination cannot be the same line as \".goto\" directive."); } else { var iterCopy = new RandomAccessIterator <SourceLine>(lines, true); SourceLine currLine; if ((currLine = iterCopy.FirstOrDefault(l => { if (l.Instruction != null && _openClosures.ContainsKey(l.Instruction.Name)) { if (l.Instruction.Name.Equals(".function", Services.StringComparison)) { throw new SyntaxException(l.Instruction, "Function block cannot be inside another block."); } // leap over any blocks we find along the way we are not currently in. if (!_blocks.Any(b => b.Index == iterCopy.Index)) { GetProcessor(l, iterCopy.Index).SeekBlockEnd(iterCopy); } return(false); } return(l.Label != null && l.Label.Name.Equals(gotoExp, Services.StringViewComparer)); })) != null) { if (currLine.Instruction != null && (currLine.Instruction.Name.Contains('=') || currLine.Instruction.Name.Equals(".equ", Services.StringComparison) || currLine.Instruction.Name.Equals(".global", Services.StringComparison) ) ) { Services.Log.LogEntry(line.Instruction, $"\"{gotoExp}\" is not a valid destination."); } else { while (_currentBlock != null) { // if where we landed lies outside of the current block scope // we need to pop out of that scope. _currentBlock.SeekBlockEnd(lines); if (iterCopy.Index > _currentBlock.Index) { // did we land in a place still within the block scope? if (iterCopy.Index > lines.Index) { // no, pop out DoPop(lines); } else { // we're still within the current block, don't pop it break; } } else { // we went backwards, pop out of current scope DoPop(lines); } } if (iterCopy.Index >= lines.Index) { lines.FastForward(iterCopy.Index); } else if (iterCopy.Index == 0) { lines.Reset(); } else { lines.Rewind(iterCopy.Index - 1); } } } else { Services.Log.LogEntry(line.Instruction, $"Could not find destination \"{gotoExp}\"."); } } return(string.Empty); }