/// <summary> /// This function analyzes a token and either: /// 1. Makes a SINGLE reduction and pushes a complete Reduction object on the _stack /// 2. Accepts the token and shifts /// 3. Errors and places the expected symbol indexes in the Tokens list /// The Token is assumed to be valid and WILL be checked /// If an action is performed that requires controlt to be returned to the user, the function returns true. /// The Message parameter is then set to the type of action. /// </summary> /// <param name="nextToken"></param> /// <returns></returns> private ParseResult ParseLALR(Token nextToken) { ParseResult result = default(ParseResult); LRAction parseAction = _lrStates[_currentLALR][(nextToken.Parent)]; // Work - shift or reduce if ((parseAction != null)) { _haveReduction = false; //Will be set true if a reduction is made //'Debug.WriteLine("Action: " & ParseAction.Text) switch (parseAction.Type) { case LRActionType.Accept: _haveReduction = true; result = ParseResult.Accept; break; case LRActionType.Shift: _currentLALR = parseAction.Value; nextToken.State = (short)_currentLALR; _stack.Push(nextToken); result = ParseResult.Shift; break; case LRActionType.Reduce: //Produce a reduction - remove as many tokens as members in the rule & push a nonterminal token Production prod = _productionTable[parseAction.Value]; //======== Create Reduction Token head; int n; if (TrimReductions && prod.ContainsOneNonTerminal()) { //The current rule only consists of a single nonterminal and can be trimmed from the //parse tree. Usually we create a new Reduction, assign it to the Data property //of Head and push it on the _stack. However, in this case, the Data property of the //Head will be assigned the Data property of the reduced token (i.e. the only one //on the _stack). //In this case, to save code, the value popped of the _stack is changed into the head. head = _stack.Pop(); head.Parent = prod.RuleNonterminal; result = ParseResult.ReduceEliminated; //Build a Reduction } else { _haveReduction = true; var newReduction = new Reduction(prod.Handle.Count); newReduction.ParentRule = prod; for (n = prod.Handle.Count - 1; n >= 0; n += -1) { newReduction[n] = _stack.Pop(); } head = new Token(prod.RuleNonterminal, newReduction); //bool IsFirst; //if (_stack.Count == 0) //{ // IsFirst = true; //} //else //{ // IsFirst = false; //} //newReduction.EndNoise = _lastNoise; result = ParseResult.ReduceNormal; } //========== Goto short index = _stack.Peek().State; //========= If n is -1 here, then we have an Internal Table Error!!!! n = _lrStates[index].IndexOf(prod.RuleNonterminal); if (n != -1) { _currentLALR = _lrStates[index][n].Value; head.State = (short)_currentLALR; _stack.Push(head); } else { result = ParseResult.InternalError; } break; } } else { //=== Syntax Error! Fill Expected Tokens _expectedSymbols.Clear(); //.Count - 1 foreach (LRAction action in _lrStates[_currentLALR]) { switch (action.Symbol.Type) { case SymbolType.Terminal: case SymbolType.End: case SymbolType.GroupStart: case SymbolType.GroupEnd: _expectedSymbols.Add(action.Symbol); break; } } result = ParseResult.SyntaxError; } return(result); }
/// <summary> /// Loads parse tables from the specified BinaryReader. Only EGT (version 5.0) is supported. /// </summary> /// <param name="reader"></param> /// <returns></returns> public bool LoadCompiledGrammar(BinaryReader reader) { var egt = new EGTReader(); try { egt.Open(reader); Restart(); while (!egt.EndOfFile()) { egt.GetNextRecord(); var recordType = (EGTRecord)egt.RetrieveByte(); if (recordType == EGTRecord.Property) { //Index, Name, ValueExpression int index = egt.RetrieveInt16(); egt.RetrieveString(); //Just discard _grammar.SetValue(index, egt.RetrieveString()); } else if (recordType == EGTRecord.TableCounts) { //Symbol, CharacterSet, Rule, DFA, LALR _symbolTable = new SymbolList(egt.RetrieveInt16()); _charSetTable = new CharacterSetList(egt.RetrieveInt16()); _productionTable = new ProductionList(egt.RetrieveInt16()); _dfa = new FAStateList(egt.RetrieveInt16()); _lrStates = new LRStateList(egt.RetrieveInt16()); _groupTable = new GroupList(egt.RetrieveInt16()); } else if (recordType == EGTRecord.InitialStates) { //DFA, LALR _dfa.InitialState = (short)egt.RetrieveInt16(); _lrStates.InitialState = (short)egt.RetrieveInt16(); } else if (recordType == EGTRecord.Symbol) { //#, Name, Kind int index = egt.RetrieveInt16(); string name = egt.RetrieveString(); var type = (SymbolType)egt.RetrieveInt16(); _symbolTable[index] = new Symbol(name, type, (short)index); } else if (recordType == EGTRecord.Group) { //#, Name, Container#, Start#, End#, Tokenized, Open Ended, Reserved, Count, (Nested Group #...) var group = new Group(); int index = egt.RetrieveInt16(); group.Name = egt.RetrieveString(); group.Container = SymbolTable[egt.RetrieveInt16()]; group.Start = SymbolTable[egt.RetrieveInt16()]; group.End = SymbolTable[egt.RetrieveInt16()]; group.Advance = (Group.AdvanceMode)egt.RetrieveInt16(); group.Ending = (Group.EndingMode)egt.RetrieveInt16(); egt.RetrieveEntry(); //Reserved int count = egt.RetrieveInt16(); for (int n = 0; n < count; n++) { group.Nesting.Add(egt.RetrieveInt16()); } //=== Link back group.Container.Group = group; group.Start.Group = group; group.End.Group = group; _groupTable[index] = group; } else if (recordType == EGTRecord.CharRanges) { //#, Total Sets, RESERVED, (Start#, End# ...) int index = egt.RetrieveInt16(); egt.RetrieveInt16(); egt.RetrieveInt16(); egt.RetrieveEntry(); _charSetTable[index] = new CharacterSet(); while (!egt.RecordComplete()) { _charSetTable[index].Add(new CharacterRange((ushort)egt.RetrieveInt16(), (ushort)egt.RetrieveInt16())); } } else if (recordType == EGTRecord.Production) { //#, ID#, Reserved, (Symbol#, ...) int index = egt.RetrieveInt16(); int headIndex = egt.RetrieveInt16(); egt.RetrieveEntry(); _productionTable[index] = new Production(_symbolTable[headIndex], (short)index); while (!(egt.RecordComplete())) { int symbolIndex = egt.RetrieveInt16(); _productionTable[index].Handle.Add(_symbolTable[symbolIndex]); } } else if (recordType == EGTRecord.DfaState) { //#, Accept?, Accept#, Reserved (CharSet#, Target#, Reserved)... int index = egt.RetrieveInt16(); bool accept = egt.RetrieveBoolean(); int acceptIndex = egt.RetrieveInt16(); egt.RetrieveEntry(); if (accept) { _dfa[index] = new FAState(_symbolTable[acceptIndex]); } else { _dfa[index] = new FAState(); } //(Edge chars, Target#, Reserved)... while (!egt.RecordComplete()) { int setIndex = egt.RetrieveInt16(); int target = egt.RetrieveInt16(); egt.RetrieveEntry(); _dfa[index].Edges.Add(new FAEdge(_charSetTable[setIndex], target)); } } else if (recordType == EGTRecord.LrState) { //#, Reserved (Symbol#, Action, Target#, Reserved)... int index = egt.RetrieveInt16(); egt.RetrieveEntry(); _lrStates[index] = new LRState(); //(Symbol#, Action, Target#, Reserved)... while (!(egt.RecordComplete())) { int symbolIndex = egt.RetrieveInt16(); int action = egt.RetrieveInt16(); int target = egt.RetrieveInt16(); egt.RetrieveEntry(); _lrStates[index].Add(new LRAction(_symbolTable[symbolIndex], (LRActionType)action, (short)target)); } } else { throw new EngineException("File Error. A record of type '" + recordType + "' was read. This is not a valid code."); } } } catch (EngineException) { throw; } catch (Exception ex) { throw new EngineException("Error while loading tables.", ex); } _areTablesLoaded = true; return(true); }