Пример #1
0
        /*
         * Encodes the handle-finding FSA as a LR parse table.
         *
         *
         *
         *  The parse table.
         */
        protected Tuple <ActionAndGoTo, List <Conflict> > BuildParseTable(Automaton automaton, Grammar grammar)
        {
            int             conflictsMode = grammar.ConflictsMode;
            List <Conflict> conflicts     = new List <Conflict>();
            Dictionary <int, Dictionary <string, bool> > errors = new Dictionary <int, Dictionary <string, bool> >();
            // initialize the table
            ActionAndGoTo table = new ActionAndGoTo();

            foreach (var kvp in automaton.TransitionTable)
            {
                var num         = kvp.Key;
                var transitions = kvp.Value;
                foreach (var kvp2 in transitions)
                {
                    var trigger     = kvp2.Key;
                    var destination = kvp2.Value;
                    if (!grammar.HasNonterminal(trigger))
                    {
                        // terminal implies shift
                        table.AddAction(num, trigger, destination);
                    }
                    else
                    {
                        // nonterminal goes in the goto table
                        table.AddGoTo(num, trigger, destination);
                    }
                }
            }

            foreach (var kvp in automaton.States)
            {
                var num   = kvp.Key;
                var state = kvp.Value;
                Dictionary <string, int> actionDictionary = table.Action.GetOrAdd(num, () => new Dictionary <string, int>());

                foreach (var item in state.Items)
                {
                    if (item.IsReduceItem)
                    {
                        int ruleNumber = item.Rule.Number;
                        foreach (var token in item.Lookahead)
                        {
                            Dictionary <string, bool> errorsOfNum;
                            if (errors.TryGetValue(num, out errorsOfNum) && errorsOfNum.ContainsKey(token))
                            {
                                // there was a previous conflict resolved as an error
                                // entry for this token.
                                continue;
                            }

                            int instruction;
                            if (actionDictionary.TryGetValue(token, out instruction))
                            {
                                // conflict
                                if (instruction > 0)
                                {
                                    if ((conflictsMode & Grammar.OPERATORS) == Grammar.OPERATORS)
                                    {
                                        if (grammar.HasOperator(token))
                                        {
                                            Dictionary <string, int> operatorInfo   = grammar.GetOperatorInfo(token);
                                            Nullable <int>           rulePrecedence = item.Rule.Precedence;
                                            // unless the rule has given precedence
                                            if (rulePrecedence == null)
                                            {
                                                foreach (string c in item.Rule.Components.Reverse())
                                                {
                                                    // try to extract it from the rightmost terminal
                                                    if (grammar.HasOperator(c))
                                                    {
                                                        Dictionary <string, int> ruleOperatorInfo = grammar.GetOperatorInfo(c);
                                                        rulePrecedence = ruleOperatorInfo["prec"];
                                                        break;
                                                    }
                                                }
                                            }

                                            if (rulePrecedence != null)
                                            {
                                                // if we actually have a rule precedence
                                                int tokenPrecedence = operatorInfo["prec"];
                                                if (rulePrecedence > tokenPrecedence)
                                                {
                                                    // if the rule precedence is higher, reduce
                                                    actionDictionary[token] = -ruleNumber;
                                                }

                                                else if (rulePrecedence < tokenPrecedence)
                                                {
                                                    // if the token precedence is higher, shift
                                                    // (i.e. don"t modify the table)
                                                }
                                                else
                                                {
                                                    // precedences are equal, let"s turn to associativity
                                                    int assoc = operatorInfo["assoc"];
                                                    if (assoc == Grammar.RIGHT)
                                                    {
                                                        // if right-associative, shift
                                                        // (i.e. don"t modify the table)
                                                    }

                                                    else if (assoc == Grammar.LEFT)
                                                    {
                                                        // if left-associative, reduce
                                                        actionDictionary[token] = -ruleNumber;
                                                    }

                                                    else if (assoc == Grammar.NONASSOC)
                                                    {
                                                        // the token is nonassociative.
                                                        // this actually means an input error, so
                                                        // remove the shift entry from the table
                                                        // and mark this as an explicit error
                                                        // entry
                                                        actionDictionary.Remove(token);
                                                        errors[num].Add(token, true);
                                                    }
                                                }

                                                continue; // resolved the conflict, phew
                                            }
                                            // we couldn"t calculate the precedence => the conflict was not resolved
                                            // move along.
                                        }
                                    }

                                    // s/r
                                    if ((conflictsMode & Grammar.SHIFT) == Grammar.SHIFT)
                                    {
                                        conflicts.Add(new Conflict(num, token, item.Rule, Grammar.SHIFT));
                                        continue;
                                    }
                                    else
                                    {
                                        throw new ShiftReduceConflictException(num, item.Rule, token, automaton);
                                    }
                                }
                                else
                                {
                                    // r/r
                                    Rule originalRule = grammar.GetRule(-instruction);
                                    Rule newRule      = item.Rule;
                                    if ((conflictsMode & Grammar.LONGER_REDUCE) == Grammar.LONGER_REDUCE)
                                    {
                                        int count1 = originalRule.Components.Length;
                                        int count2 = newRule.Components.Length;
                                        if (count1 > count2)
                                        {
                                            // original rule is longer
                                            Rule[] resolvedRules = new Rule[] { originalRule, newRule };
                                            conflicts.Add(new Conflict(num, token, resolvedRules, Grammar.LONGER_REDUCE));
                                            continue;
                                        }

                                        else if (count2 > count1)
                                        {
                                            // new rule is longer
                                            actionDictionary[token] = -ruleNumber;
                                            Rule[] resolvedRules = new Rule[] { newRule, originalRule };
                                            conflicts.Add(new Conflict(num, token, resolvedRules, Grammar.LONGER_REDUCE));
                                            continue;
                                        }
                                    }

                                    if ((conflictsMode & Grammar.EARLIER_REDUCE) == Grammar.EARLIER_REDUCE)
                                    {
                                        if (-instruction < ruleNumber)
                                        {
                                            // original rule was earlier
                                            Rule[] resolvedRules = new Rule[] { originalRule, newRule };
                                            conflicts.Add(new Conflict(num, token, resolvedRules, Grammar.EARLIER_REDUCE));
                                            continue;
                                        }
                                        else
                                        {
                                            // new rule was earlier
                                            actionDictionary[token] = -ruleNumber;
                                            //WTM:  Change:  In PHP, this resolvedRules declaration was below the conflicts.Add statement, but this else statement was never reached anyway as far as I can tell.
                                            Rule[] resolvedRules = new Rule[] { newRule, originalRule };
                                            conflicts.Add(new Conflict(num, token, resolvedRules, Grammar.EARLIER_REDUCE));
                                            continue;
                                        }
                                    }

                                    // everything failed, throw an exception
                                    throw new ReduceReduceConflictException(num, originalRule, newRule, token, automaton);
                                }
                            }

                            actionDictionary[token] = -ruleNumber;
                        }
                    }
                }
            }

            return(new Tuple <ActionAndGoTo, List <Conflict> >(table, conflicts));
        }
Пример #2
0
 /*
  * Constructor.
  *
  *  The parse table.
  *
  *  An array of conflicts resolved during parse table
  * construction.
  */
 public AnalysisResult(ActionAndGoTo parseTable, Automaton automaton, List <Conflict> conflicts)
 {
     this.ParseTable        = parseTable;
     this.Automaton         = automaton;
     this.ResolvedConflicts = conflicts;
 }