protected void EndParse()
        {
            var skipping = SkipTypes.Any(); //if we are skipping then we will have some references unresolved

            foreach (var defRef in _deferredReferences /*.Where(dr => !SkipEntities.Contains(dr.ReferenceId))*/)
            {
                if (!TrySetObjectValue(defRef.HostEntity, defRef.ParameterIndex, defRef.ReferenceId, defRef.NestedIndex) && !skipping && !AllowMissingReferences)
                {
                    Logger?.LogWarning("Entity #{0,-5} is referenced but could not be instantiated",
                                       defRef.ReferenceId);
                }
            }
            _deferredReferences.Clear();

            if (_errors.Any)
            {
                Logger?.LogWarning(_errors.Summary);
            }

            _progressStatus?.Invoke(100, "Parsing finished.");
        }
        public XbimP21Scanner(string data, IEnumerable <string> ignoreTypes = null)
        {
            Logger   = XbimLogging.CreateLogger <XbimP21Scanner>();
            _scanner = new Scanner();
            _scanner.SetSource(data, 0);
            _streamSize = data.Length;
            if (ignoreTypes != null)
            {
                SkipTypes = new HashSet <string>(ignoreTypes);
            }
            var entityApproxCount = (int)_streamSize / 50;

            //adjust for skipped entities
            if (SkipTypes.Any())
            {
                //about a 560 entities
                double adjustRatio = 1 - ((double)(SkipTypes.Count)) / 560;
                entityApproxCount = (int)(entityApproxCount * adjustRatio);
            }

            Entities            = new Dictionary <int, IPersist>(entityApproxCount);
            _deferredReferences = new List <DeferredReference>(entityApproxCount / 4); //assume 50% deferred
        }
        public XbimP21Scanner(Stream strm, long streamSize, IEnumerable <string> ignoreTypes = null)
        {
            Logger   = XbimLogging.CreateLogger <XbimP21Scanner>();
            _scanner = new Scanner(strm);
            //_scanner = new Scanner(new XbimScanBuffer(strm));
            if (ignoreTypes != null)
            {
                SkipTypes = new HashSet <string>(ignoreTypes);
            }
            var entityApproxCount = 50000;

            if (streamSize > 0)
            {
                _streamSize       = streamSize;
                entityApproxCount = Convert.ToInt32(_streamSize / 50); //average 50 bytes per entity.
            }
            //adjust for skipped entities
            if (SkipTypes.Any())
            {
                //about a 600 entities
                double adjustRatio = 1.0 - (SkipTypes.Count / 600d);
                if (adjustRatio < 0)
                {
                    adjustRatio = 0;
                }
                entityApproxCount = (int)(entityApproxCount * adjustRatio);
            }

            // make it 4 at least
            if (entityApproxCount < 1)
            {
                entityApproxCount = 4;
            }

            Entities            = new Dictionary <int, IPersist>(entityApproxCount);
            _deferredReferences = new List <DeferredReference>(entityApproxCount / 4); //assume 50% deferred
        }
        public bool Parse(bool onlyHeader = false)
        {
            var skipping       = SkipTypes.Any();
            var eofToken       = (int)Tokens.EOF;
            var tok            = _scanner.yylex();
            int endEntityToken = ';';

            while (tok != eofToken && !Cancel)
            {
                try
                {
                    if (tok >= 63)
                    {
                        Tokens t = (Tokens)tok;
                        switch (t)
                        {
                        case Tokens.HEADER:
                            BeginHeader();
                            break;

                        case Tokens.ENDSEC:
                            if (_inHeader && onlyHeader)
                            {
                                return(true);
                            }
                            EndSec();
                            break;

                        case Tokens.DATA:
                            BeginData();
                            break;

                        case Tokens.ENTITY:
                            NewEntity(_scanner.yylval.strVal /*.AsSpan()*/);
                            break;

                        case Tokens.TYPE:
                            var type = _scanner.yylval.strVal;
                            if (skipping && SkipTypes.Contains(type))
                            {
                                var current = _processStack.Pop();
                                //SkipEntities.Add(current.EntityLabel);
                                while (tok != endEntityToken && tok != eofToken)
                                {
                                    tok = _scanner.yylex();
                                }
                                break;
                            }

                            if (!SetType(type))
                            {
                                // move to the end of entity if we couldn't create it
                                while (tok != endEntityToken && tok != eofToken)
                                {
                                    tok = _scanner.yylex();
                                }
                            }
                            break;

                        case Tokens.INTEGER:
                            SetIntegerValue(_scanner.yylval.strVal);
                            break;

                        case Tokens.FLOAT:
                            SetFloatValue(_scanner.yylval.strVal);
                            break;

                        case Tokens.STRING:
                            SetStringValue(_scanner.yylval.strVal);
                            break;

                        case Tokens.BOOLEAN:
                            SetBooleanValue(_scanner.yylval.strVal);
                            break;

                        case Tokens.IDENTITY:
                            SetObjectValue(_scanner.yylval.strVal /*.AsSpan()*/);
                            break;

                        case Tokens.HEXA:
                            SetHexValue(_scanner.yylval.strVal);
                            break;

                        case Tokens.ENUM:
                            SetEnumValue(_scanner.yylval.strVal);
                            break;

                        case Tokens.NONDEF:
                            SetNonDefinedValue();
                            break;

                        case Tokens.OVERRIDE:
                            SetOverrideValue();
                            break;

                        case Tokens.TEXT:
                        case Tokens.error:
                        case Tokens.ILLEGALCHAR:
                            throw new XbimParserException($"Unexpected scanner token {t.ToString()}, line {_scanner.yylloc.StartLine}, column {_scanner.yylloc.StartColumn}");

                        case Tokens.SCOPE:
                        case Tokens.ENDSCOPE:
                        case Tokens.ISOSTEPSTART:
                        case Tokens.ISOSTEPEND:
                        case Tokens.MISC:
                        case Tokens.EOF:
                        default:
                            break;
                        }
                    }
                    else
                    {
                        char c = (char)tok;
                        switch (c)
                        {
                        case '(':
                            BeginList();
                            break;

                        case ')':
                            EndList();
                            break;

                        case ';':
                            EndEntity();
                            break;

                        case '/':
                        case ',':
                        case '=':
                        default:
                            break;
                        }
                    }

                    // get next token
                    tok = _scanner.yylex();
                }
                //XbimParserException is a reason to terminate execution
                catch (XbimParserException e)
                {
                    Logger?.LogError(LogEventIds.ParserFailure, e, e.Message);
                    return(false);
                }
                //other exceptions might occure but those should just make the parser to wait for the next start of entity
                //and start from there
                catch (Exception e)
                {
                    Logger?.LogError(LogEventIds.FailedEntity, e, e.Message);
                    ErrorCount++;

                    // clear current entity stack to make sure there are no residuals
                    _processStack.Clear();

                    // scan until the beginning of next entity
                    var entityToken = (int)Tokens.ENTITY;
                    while (tok != eofToken && tok != entityToken)
                    {
                        tok = _scanner.yylex();
                    }
                }
            }
            EndParse();
            return(ErrorCount == 0);
        }