protected void ParseProgram()
        {
            string programName = "program";

            if (Accept(Token.KwProgram))
            {
                if (Accept(Token.Identifier))
                {
                    programName = _lexeme;
                }
                else
                {
                    AddErrorAtTokenStart("Expecting program name.");
                }

                Expect(Token.ChrSemicolon);
            }

            _context.Emitter.BeginProgram(programName, _context.Importer.ImportedAssemblies);

            List <Tuple <Variable, FilePosition> > globals = new List <Tuple <Variable, FilePosition> >();

            if (Accept(Token.KwVar))
            {
                ParseVariableList(globals, isArgumentList: false);
                foreach (Tuple <Variable, FilePosition> globalDecl in globals)
                {
                    Variable global = globalDecl.Item1;
                    if (ValidateName(globalDecl.Item2, global.Name, global: true))
                    {
                        Symbol globalSymbol = _symbolTable.Add(global.Name, global.Type, StorageClass.Global);
                        _context.Emitter.DeclareGlobal(globalSymbol);
                    }
                }
            }

            FilePosition blockBegin = _lexer.TokenStartPosition;

            while (!Accept(Token.KwBegin))
            {
                if (Accept(Token.Eof))
                {
                    AddErrorAtLastParsedPosition("Unexpected end of file looking for main block.");
                    return;
                }
                else if (Accept(Token.KwFunction))
                {
                    ParseMethod(isFunction: true);
                }
                else if (Accept(Token.KwProcedure))
                {
                    ParseMethod(isFunction: false);
                }
                else if (Accept(Token.KwVar))
                {
                    AddErrorAtTokenStart("Global variables must be declared before the first function or procedure.");
                    List <Tuple <Variable, FilePosition> > unused = new List <Tuple <Variable, FilePosition> >();
                    ParseVariableList(unused, isArgumentList: false);
                }
                else if (!Accept(Token.ChrSemicolon))
                {
                    AddErrorAtTokenStart("Expecting 'function', 'procedure', or 'begin'.");
                    SkipToNextEnd();
                }

                blockBegin = _lexer.TokenStartPosition;
            }

            // We are now at the main block
            IrisType mainMethod = Procedure.Create(new Variable[0]);
            Symbol   mainSymbol = _symbolTable.OpenMethod("$.main", mainMethod);

            MethodGenerator.BeginMethod(mainSymbol.Name, IrisType.Void, new Variable[0], new Variable[0], true, _context.FilePath);
            MethodGenerator.EmitNonCodeLineInfo(blockBegin.Expand(5 /* Length of "begin" */));

            // Initialize global variables if needed
            foreach (Tuple <Variable, FilePosition> globalDecl in globals)
            {
                InitializeVariableIfNeeded(blockBegin, globalDecl.Item1);
            }

            ParseStatements(Token.KwEnd);

            MethodGenerator.EndMethod();

            Accept(Token.ChrPeriod);
            Expect(Token.Eof);

            _context.Emitter.EndProgram();
        }