Statement tstmt() { int l = next.line; int c = next.col; Statement s, s1, s2; Expression e; if (t == TokenKind.OpeningCurlyBrace) { return(block()); } else if (t == TokenKind.If) { move(); e = expr(); if (t == TokenKind.Then) { move(); } s = stmt(); if (t == TokenKind.Else) { move(); return(new If(e, s, stmt(), l, c)); } return(new If(e, s, l, c)); } else if (t == TokenKind.While) { move(); e = expr(); if (t == TokenKind.Do) { move(); } return(new While(e, stmt(), l, c)); } else if (t == TokenKind.Do) { move(); s = stmt(); match(Token.Until, Error.ExpectedUntil); return(new Do(s, expr(), l, c)); } else if (t == TokenKind.For) { // "For" is very weird in GM. Any legal statement including control flow and blocks can be used in for. // example of legal "for" statements: // for (i = 0 i<3; {case 3:exit};;;)func(); move(); match(Token.OpeningParenthesis); s1 = stmt(); //match(Token.Semicolon); // Taken care of by stmt(); e = expr(); match(Token.Semicolon); s2 = stmt(); match(Token.ClosingParenthesis); return(new For(s1, e, s2, stmt(), l, c)); } else if (t == TokenKind.Break) { move(); return(new Break(l, c)); } else if (t == TokenKind.Continue) { move(); return(new Continue(l, c)); } else if (t == TokenKind.Exit) { move(); return(new Exit(l, c)); } else if (t == TokenKind.Return) { move(); return(new Return(expr(), l, c)); } else if (t == TokenKind.Repeat) { move(); return(new Repeat(expr(), stmt(), l, c)); } else if (t == TokenKind.Var) { move(); List <string> strs = new List <string>(); while (t == TokenKind.Identifier) { if (peek().t == TokenKind.OpeningParenthesis) { break; } if (Context.IsBuiltIn(next.lexeme)) { error(Error.BuiltinVariable); } strs.Add(next.lexeme); move(); if (t == TokenKind.Comma) { move(); } } return(new Var(strs.ToArray(), l, c)); } else if (t == TokenKind.Globalvar) { move(); List <string> strs = new List <string>(); while (t == TokenKind.Identifier) { if (peek().t == TokenKind.OpeningParenthesis) { break; } if (Context.IsBuiltIn(next.lexeme)) { error(Error.BuiltinVariable); } strs.Add(next.lexeme); move(); if (t == TokenKind.Comma) { move(); } } return(new Globalvar(strs.ToArray(), l, c)); } else if (t == TokenKind.With) { move(); e = expr(); if (t == TokenKind.Do) { move(); } return(new With(e, stmt(), l, c)); } else if (t == TokenKind.Default) { move(); match(Token.Colon); return(new Default(l, c)); } else if (t == TokenKind.Case) { move(); Case @case = new Case(expr(), l, c); // @ since case is a keyword match(Token.Colon); return(@case); } else if (t == TokenKind.Switch) { move(); e = expr(); match(Token.OpeningCurlyBrace); List <Statement> lst = new List <Statement>(); while (t != TokenKind.ClosingCurlyBrace && t != TokenKind.Eof) { lst.Add(stmt()); while (t == TokenKind.Semicolon) { move(); } } match(Token.ClosingCurlyBrace); return(new Switch(e, lst.ToArray(), l, c)); } else if (t == TokenKind.Identifier) { if (peek().t == TokenKind.OpeningParenthesis) { string str = next.lexeme; if (!Context.Resources.FunctionExists(str)) { error(Error.UnknownFunction, str); } move(); move(); List <Expression> exprs = new List <Expression>(); if (t != TokenKind.ClosingParenthesis && t != TokenKind.Eof) { exprs.Add(expr()); } while (t == TokenKind.Comma) { move(); exprs.Add(expr()); } match(Token.ClosingParenthesis); IFunction f = Context.Resources.GetFunction(str); if ((f.Argc != -1 && exprs.Count != f.Argc) || exprs.Count > 16) { error(Error.WrongArgumentNumber); } return(new CallStatement(f, exprs.ToArray(), l, c)); } else { return(assign()); } } else { return(assign()); } }