protected void ParseStatement(bool allowEmpty = false) { FilePosition statementStart = _lexer.TokenStartPosition; MethodGenerator.BeginSourceLine(statementStart); if (Accept(Token.KwFor)) { Symbol iterator; FilePosition fp = _lexer.TokenStartPosition; if (!Accept(Token.Identifier)) { AddError(fp, "Expecting integer identifier."); SkipStatement(); return; } // Initial assignment iterator = LookupSymbol(fp, _lexeme); VerifyExpressionType(fp, DerefType(iterator.Type), IrisType.Integer); bool byRef = iterator.Type.IsByRef; if (byRef) { EmitLoadSymbol(iterator, SymbolLoadMode.Raw); } Expect(Token.ChrAssign); fp = _lexer.TokenStartPosition; IrisType rhs = ParseExpression(); VerifyExpressionType(fp, rhs, IrisType.Integer); if (byRef) { MethodGenerator.Store(rhs); } else { EmitStoreSymbol(iterator); } Expect(Token.KwTo); // Loop start and condition int loopLabel = GetNextLabel(); MethodGenerator.Label(loopLabel); EmitLoadSymbol(iterator, SymbolLoadMode.Dereference); fp = _lexer.TokenStartPosition; rhs = ParseExpression(); VerifyExpressionType(fp, rhs, IrisType.Integer); int exitLabel = GetNextLabel(); MethodGenerator.BranchCondition(Operator.GreaterThan, exitLabel); // Loop body Expect(Token.KwDo); FilePosition forEndPosition = _lastParsedPosition; MethodGenerator.EndSourceLine(forEndPosition); ParseStatement(); // Loop end MethodGenerator.BeginSourceLine(statementStart); // Source position is the same as the loop start. Increment(iterator); MethodGenerator.Goto(loopLabel); MethodGenerator.Label(exitLabel); MethodGenerator.EndSourceLine(forEndPosition); } else if (Accept(Token.KwWhile)) { int loopLabel = GetNextLabel(); MethodGenerator.Label(loopLabel); FilePosition fp = _lexer.TokenStartPosition; IrisType type = ParseExpression(); VerifyExpressionType(fp, type, IrisType.Boolean); int exitLabel = GetNextLabel(); MethodGenerator.BranchFalse(exitLabel); Expect(Token.KwDo); MethodGenerator.EndSourceLine(_lastParsedPosition); ParseStatement(); MethodGenerator.Goto(loopLabel); MethodGenerator.Label(exitLabel); } else if (Accept(Token.KwRepeat)) { int loopLabel = GetNextLabel(); MethodGenerator.Label(loopLabel); MethodGenerator.EmitNonCodeLineInfo(new SourceRange(statementStart, _lastParsedPosition)); ParseStatements(Token.KwUntil); FilePosition fp = _lexer.TokenStartPosition; IrisType type = ParseExpression(); VerifyExpressionType(fp, type, IrisType.Boolean); MethodGenerator.BranchFalse(loopLabel); MethodGenerator.EndSourceLine(_lastParsedPosition); } else if (Accept(Token.KwIf)) { ParseIf(); } else if (Accept(Token.KwBegin)) { MethodGenerator.EmitNonCodeLineInfo(new SourceRange(statementStart, _lastParsedPosition)); ParseStatements(Token.KwEnd); } else if (Accept(Token.Identifier)) { FilePosition fp = _lexer.TokenStartPosition; string symbolName = _lexeme; Symbol symbol = LookupSymbol(fp, symbolName); IrisType lhs = symbol.Type; bool assign = false; bool isArray = false; if (Accept(Token.ChrOpenBracket)) { // Assignment to an array element. isArray = true; lhs = ProcessArrayAccess(fp, symbol, SymbolLoadMode.Raw); } if (Accept(Token.ChrAssign)) { assign = true; bool indirectAssign = false; if (lhs.IsByRef) { lhs = lhs.GetElementType(); EmitLoadSymbol(symbol, SymbolLoadMode.Raw); indirectAssign = true; } FilePosition exprPosition = _lexer.TokenStartPosition; IrisType rhs = ParseExpression(); if (lhs.IsMethod) { AddError(fp, "Cannot assign to result of function or procedure call."); } else if (lhs != IrisType.Invalid) { if (rhs == IrisType.Void) { AddError(fp, "Cannot use procedure in assignment statement."); } else if (rhs != IrisType.Invalid && rhs != lhs) { AddError(exprPosition, string.Format("Cannot assign to '{0}' (type mismatch error).", symbolName)); } if (isArray) { MethodGenerator.StoreElement(lhs); } else if (indirectAssign) { MethodGenerator.Store(lhs); } else { EmitStoreSymbol(symbol); } } } else if (isArray) { // This is an array subscript. Assignment is the only kind of statement that // starts with an array subscript. AddErrorAtTokenStart("Expecting ':='."); SkipStatement(); } if (!assign && !isArray) { bool skipArgList = !Accept(Token.ChrOpenParen); ProcessCall(fp, symbol, skipArgList); if (symbol.Type.IsFunction) { MethodGenerator.Pop(); } } MethodGenerator.EndSourceLine(_lastParsedPosition); } else if (Accept(Token.KwElse)) { AddErrorAtTokenStart("Cannot start statement with 'else' or unexpected ';' after if statement."); SkipStatement(); } else if (!allowEmpty && !Accept(Token.ChrSemicolon)) { AddErrorAtLastParsedPosition("Expecting statement."); SkipStatement(); } }