public void SetPrecedence(IPrecedenceGroup precedenceGroup) { _production.SetPrecedence(precedenceGroup); }
private void SetActionTable(short[,] table, int state, int tokenNumber, short value) { // This is an error condition, find out what sort of exception it is short oldValue = table[state, tokenNumber]; if ((oldValue != value) && (oldValue != short.MinValue)) { try { if (oldValue < 0 && value < 0) // Both values are reduce. Throw a reduce reduce conflict. This is not solveable. NOTE: Bison takes the first rule (here 'oldValue') { throw new ReduceReduceConflictException <T>("Grammar contains a reduce reduce conflict"); } int shiftTokenNumber = tokenNumber; int reduceRuleNumber; short shiftValue; short reduceValue; if (oldValue < 0) { // The old value was a reduce, the new must be a shift shiftValue = value; reduceValue = oldValue; reduceRuleNumber = -(oldValue + 1); } else { // TODO: Unsure if this is a real case. The only testcases that end up here are retarded tests which are cyclic in nature. // TODO: These cases always fail later on anyway due to conflicts. // The old value was a shift, the new value must be a reduce shiftValue = oldValue; reduceValue = value; reduceRuleNumber = -(value + 1); } // Check if these tokens have declared precedences and associativity // If they do, we might be able to act on this. Terminal <T> shiftingTerminal = grammar.AllSymbols.OfType <Terminal <T> >().First(f => f.TokenNumber == shiftTokenNumber); IPrecedenceGroup shiftPrecedence = grammar.GetPrecedence(shiftingTerminal); IProductionRule <T> productionRule = reductionRules[reduceRuleNumber].Item1; // If the rule has a context dependent precedence, use that. Otherwise use the reduce precedence of the last terminal symbol in the production rules precedence IPrecedenceGroup reducePrecedence = productionRule.ContextPrecedence ?? grammar.GetPrecedence(productionRule.Symbols.Reverse().OfType <ITerminal <T> >().FirstOrDefault()); // If either rule has no precedence this is not a legal course of action. // TODO: In bison this is apparently cool, it prefers to shift in this case. I don't know why, but this seems like a dangerous course of action to me. if (shiftPrecedence == null || reducePrecedence == null) { throw new ShiftReduceConflictException <T>("Grammar contains a shift reduce conflict") { ShiftSymbol = shiftingTerminal, ReduceSymbol = productionRule.ResultSymbol, } } ; if (shiftPrecedence.Precedence < reducePrecedence.Precedence) { table[state, tokenNumber] = reduceValue; // Precedence of reduce is higher, choose to reduce } else if (shiftPrecedence.Precedence > reducePrecedence.Precedence) { table[state, tokenNumber] = shiftValue; // Shift precedence is higher. Shift } // Both tokens are in the same precedence group! It's now up to the associativity // The two tokens CANNOT have different associativity, due to how the configuration works which throws up if you try to multiple-define the precedence else if (shiftPrecedence.Associativity == AssociativityDirection.Left) { table[state, tokenNumber] = reduceValue; // Prefer reducing } else if (shiftPrecedence.Associativity == AssociativityDirection.Right) { table[state, tokenNumber] = shiftValue; // Prefer shifting } else // if (shiftPrecedence.Associativity == AssociativityDirection.NonAssociative) <- this is implied { throw new ShiftReduceConflictException <T>("Grammar contains a shift reduce conflict (Nonassociative)") { ShiftSymbol = shiftingTerminal, ReduceSymbol = productionRule.ResultSymbol, } }; // Unresolveable } catch (AmbiguousGrammarException ex) { // Fill in more information on the error and rethrow the error ex.StateNumber = state; ex.TokenNumber = tokenNumber; ex.PreviousValue = oldValue; ex.NewValue = value; throw; } } else { table[state, tokenNumber] = value; } }
public void SetPrecedence(IPrecedenceGroup precedenceGroup) => ContextPrecedence = precedenceGroup;