// Parse a single Crst type definition. void ParseCrst() { // The next token had better be an identifier (the Crst type name). Token token = NextToken(); if (token.Id != KeywordId.Id) { throw new UnexpectedTokenError(token, KeywordId.Id); } // The Crst instance might already exist in the dictionary (forward references to a Crst type cause // these entries to auto-vivify). But in that case the entry better not be marked as 'Defined' which // would indicate a double declaration. CrstType crst; if (m_crsts.ContainsKey(token.Text)) { crst = m_crsts[token.Text]; if (crst.Defined) { throw new ParseError(String.Format("Duplicate definition for CrstType '{0}'", token.Text), token); } } else { // Otherwise this Crst type hasn't been seen thus far so we allocate a new instance and add it to // the dictionary. crst = new CrstType(token.Text); m_crsts.Add(crst.Name, crst); } // We're defining, not just referencing this type. crst.Defined = true; // Parse any attributes inside this definition (until we see an 'End' token). bool parsingCrst = true; while (parsingCrst) { // Get the next token. Either some attribute keyword or 'End'. token = NextToken(); List <CrstType> list; switch (token.Id) { case KeywordId.AcquiredBefore: // Simply parse the following list of Crst types into the current type's AcquiredBefore list. ParseList(crst.AcquiredBeforeList); break; case KeywordId.AcquiredAfter: // AcquiredAfter is trickier. To make the ranking algorithm's life easier we actually // normalize all rules to the AcquiredBefore form (see LevelCrsts() for the reasoning). So we // capture the list of Crst types that follow the AcquiredAfter keyword and then append the // current type to the AcquiredBefore list of each type found. list = new List <CrstType>(); ParseList(list); foreach (CrstType priorCrst in list) { priorCrst.AcquiredBeforeList.Add(crst); } break; case KeywordId.SameLevelAs: // Parse the following list of Crst types them let the CrstTypeGroup class handle the // resulting updates to the type groups we're currently maintaining. See the comments for the // CrstTypeGroup class for more details. list = new List <CrstType>(); ParseList(list); foreach (CrstType sameLevelCrst in list) { CrstTypeGroup.Join(crst, sameLevelCrst); } break; case KeywordId.Unordered: crst.Level = CrstType.CrstUnordered; break; case KeywordId.End: parsingCrst = false; break; default: throw new UnexpectedTokenError(token, KeywordId.AcquiredBefore, KeywordId.AcquiredAfter, KeywordId.SameLevelAs, KeywordId.Unordered); } } }