示例#1
0
        public static void EmitTable(Context ctx, StreamReader r, StreamWriter w, bool makeHeaders, string filePath)
        {
            var lineno = 1;

            Template.Transfer(ctx.Name, r, w, ref lineno);

            /* Generate the include code, if any */
            Template.Write(w, ctx, ctx.Include, ref lineno, filePath);
            if (makeHeaders)
            {
                // TODO: get headerfile
                var filePathH = filePath;
                w.WriteLine(ref lineno, "#include \"{0}\"", filePathH);
            }
            Template.Transfer(ctx.Name, r, w, ref lineno);

            /* Generate #defines for all tokens */
            if (makeHeaders)
            {
                w.WriteLine(ref lineno, "#if INTERFACE");
                var prefix = (ctx.TokenPrefix ?? string.Empty);
                for (var i = 1; i < ctx.Terminals; i++)
                {
                    w.WriteLine(ref lineno, "#define {0}{1,-30} {2,2}", prefix, ctx.Symbols[i].Name, i);
                }
                w.WriteLine(ref lineno, "#endif");
            }
            Template.Transfer(ctx.Name, r, w, ref lineno);

            /* Generate the defines */
            w.WriteLine(ref lineno, "#define YYCODETYPE {0}", GetMinimumSizeType(0, ctx.Symbols.Length));
            w.WriteLine(ref lineno, "#define YYNOCODE {0}", ctx.Symbols.Length);
            w.WriteLine(ref lineno, "#define YYACTIONTYPE {0}", GetMinimumSizeType(0, ctx.States + ctx.Rules + 5));
            if (ctx.Wildcard != null)
            {
                w.WriteLine(ref lineno, "#define YYWILDCARD {0}", ctx.Wildcard.ID);
            }
            EmitStackUnion(w, ctx, ref lineno, makeHeaders);
            w.WriteLine(ref lineno, "#ifndef YYSTACKDEPTH");
            if (ctx.StackSize != null)
            {
                w.WriteLine(ref lineno, "#define YYSTACKDEPTH {0}", ctx.StackSize);
            }
            else
            {
                w.WriteLine(ref lineno, "#define YYSTACKDEPTH 100");
            }
            w.WriteLine(ref lineno, "#endif");
            if (makeHeaders)
            {
                w.WriteLine(ref lineno, "#if INTERFACE");
            }
            var name = (ctx.Name ?? "Parse");

            if (!string.IsNullOrEmpty(ctx.ExtraArg))
            {
                var i = ctx.ExtraArg.Length;
                while (i >= 1 && char.IsWhiteSpace(ctx.ExtraArg[i - 1]))
                {
                    i--;
                }
                while (i >= 1 && (char.IsLetterOrDigit(ctx.ExtraArg[i - 1]) || ctx.ExtraArg[i - 1] == '_'))
                {
                    i--;
                }
                w.WriteLine(ref lineno, "#define {0}ARG_SDECL {1};", name, ctx.ExtraArg);
                w.WriteLine(ref lineno, "#define {0}ARG_PDECL ,{1}", name, ctx.ExtraArg);
                w.WriteLine(ref lineno, "#define {0}ARG_FETCH {1} = yypParser.{2}", name, ctx.ExtraArg, ctx.ExtraArg.Substring(i));
                w.WriteLine(ref lineno, "#define {0}ARG_STORE yypParser.{1} = {2}", name, ctx.ExtraArg.Substring(i), ctx.ExtraArg.Substring(i));
            }
            else
            {
                w.WriteLine(ref lineno, "#define {0}ARG_SDECL", name);
                w.WriteLine(ref lineno, "#define {0}ARG_PDECL", name);
                w.WriteLine(ref lineno, "#define {0}ARG_FETCH", name);
                w.WriteLine(ref lineno, "#define {0}ARG_STORE", name);
            }
            if (makeHeaders)
            {
                w.WriteLine(ref lineno, "#endif");
            }
            w.WriteLine(ref lineno, "#define YYNSTATE {0}", ctx.States);
            w.WriteLine(ref lineno, "#define YYNRULE {0}", ctx.Rules);
            if (ctx.ErrorSymbol.Uses > 0)
            {
                w.WriteLine(ref lineno, "#define YYERRORSYMBOL {0}", ctx.ErrorSymbol.ID);
                w.WriteLine(ref lineno, "#define YYERRSYMDT yy{0}", ctx.ErrorSymbol.DataTypeID);
            }
            if (ctx.HasFallback)
            {
                w.WriteLine(ref lineno, "#define YYFALLBACK 1");
            }
            Template.Transfer(ctx.Name, r, w, ref lineno);

            int maxTokenOffset;
            int minTokenOffset;
            int maxNonTerminalOffset;
            int minNonTerminalOffset;
            var actionTable = EmitterActionTable.Make(ctx, out maxTokenOffset, out minTokenOffset, out maxNonTerminalOffset, out minNonTerminalOffset);

            /* Output the yy_action table */
            var n = actionTable.Size;

            w.WriteLine(ref lineno, "#define YY_ACTTAB_COUNT ({0})", n);
            w.WriteLine(ref lineno, "static const YYACTIONTYPE yy_action[] = {");
            for (int i = 0, j = 0; i < n; i++)
            {
                var action = actionTable.GetAction(i);
                if (action < 0)
                {
                    action = ctx.States + ctx.Rules + 2;
                }
                if (j == 0)
                {
                    w.Write(" /* {0,5} */ ", i);
                }
                w.Write(" {0,4},", action);
                if (j == 9 || i == n - 1)
                {
                    w.WriteLine(ref lineno);
                    j = 0;
                }
                else
                {
                    j++;
                }
            }
            w.WriteLine(ref lineno, "};");

            /* Output the yy_lookahead table */
            w.WriteLine(ref lineno, "static const YYCODETYPE yy_lookahead[] = {");
            for (int i = 0, j = 0; i < n; i++)
            {
                var lookahead = actionTable.GetLookahead(i);
                if (lookahead < 0)
                {
                    lookahead = ctx.Symbols.Length - 1;
                }
                if (j == 0)
                {
                    w.Write(" /* {0,5} */ ", i);
                }
                w.Write(" {0,4},", lookahead);
                if (j == 9 || i == n - 1)
                {
                    w.WriteLine(ref lineno);
                    j = 0;
                }
                else
                {
                    j++;
                }
            }
            w.WriteLine(ref lineno, "};");

            /* Output the yy_shift_ofst[] table */
            w.WriteLine(ref lineno, "#define YY_SHIFT_USE_DFLT ({0})", minTokenOffset - 1);
            n = ctx.States;
            while (n > 0 && ctx.Sorted[n - 1].TokenOffset == State.NO_OFFSET)
            {
                n--;
            }
            w.WriteLine(ref lineno, "#define YY_SHIFT_COUNT ({0})", n - 1);
            w.WriteLine(ref lineno, "#define YY_SHIFT_MIN   ({0})", minTokenOffset);
            w.WriteLine(ref lineno, "#define YY_SHIFT_MAX   ({0})", maxTokenOffset);
            w.WriteLine(ref lineno, "static const {0} yy_shift_ofst[] = {{", GetMinimumSizeType(minTokenOffset - 1, maxTokenOffset));
            for (int i = 0, j = 0; i < n; i++)
            {
                var state  = ctx.Sorted[i];
                var offset = state.TokenOffset;
                if (offset == State.NO_OFFSET)
                {
                    offset = minTokenOffset - 1;
                }
                if (j == 0)
                {
                    w.Write(" /* {0,5} */ ", i);
                }
                w.Write(" {0,4},", offset);
                if (j == 9 || i == n - 1)
                {
                    w.WriteLine(ref lineno);
                    j = 0;
                }
                else
                {
                    j++;
                }
            }
            w.WriteLine(ref lineno, "};");

            /* Output the yy_reduce_ofst[] table */
            w.WriteLine(ref lineno, "#define YY_REDUCE_USE_DFLT ({0})", minNonTerminalOffset - 1);
            n = ctx.States;
            while (n > 0 && ctx.Sorted[n - 1].NonTerminalOffset == State.NO_OFFSET)
            {
                n--;
            }
            w.WriteLine(ref lineno, "#define YY_REDUCE_COUNT ({0})", n - 1);
            w.WriteLine(ref lineno, "#define YY_REDUCE_MIN   ({0})", minNonTerminalOffset);
            w.WriteLine(ref lineno, "#define YY_REDUCE_MAX   ({0})", maxNonTerminalOffset);
            w.WriteLine(ref lineno, "static const {0} yy_reduce_ofst[] = {{", GetMinimumSizeType(minNonTerminalOffset - 1, maxNonTerminalOffset));
            for (int i = 0, j = 0; i < n; i++)
            {
                var state  = ctx.Sorted[i];
                var offset = state.NonTerminalOffset;
                if (offset == State.NO_OFFSET)
                {
                    offset = minNonTerminalOffset - 1;
                }
                if (j == 0)
                {
                    w.Write(" /* {0,5} */ ", i);
                }
                w.Write(" {0,4},", offset);
                if (j == 9 || i == n - 1)
                {
                    w.WriteLine(ref lineno);
                    j = 0;
                }
                else
                {
                    j++;
                }
            }
            w.WriteLine(ref lineno, "};");

            /* Output the default action table */
            w.WriteLine(ref lineno, "static const YYACTIONTYPE yy_default[] = {");
            n = ctx.States;
            for (int i = 0, j = 0; i < n; i++)
            {
                var state = ctx.Sorted[i];
                if (j == 0)
                {
                    w.Write(" /* {0,5} */ ", i);
                }
                w.Write(" {0,4},", state.Default);
                if (j == 9 || i == n - 1)
                {
                    w.WriteLine(ref lineno);
                    j = 0;
                }
                else
                {
                    j++;
                }
            }
            w.WriteLine(ref lineno, "};");
            Template.Transfer(ctx.Name, r, w, ref lineno);

            /* Generate the table of fallback tokens. */
            if (ctx.HasFallback)
            {
                var mx = ctx.Terminals - 1;
                while (mx > 0 && ctx.Symbols[mx].Fallback == null)
                {
                    mx--;
                }
                for (var i = 0; i <= mx; i++)
                {
                    var symbol = ctx.Symbols[i];
                    if (symbol.Fallback == null)
                    {
                        w.WriteLine(ref lineno, "    0,  /* {0,10} => nothing */", symbol.Name);
                    }
                    else
                    {
                        w.WriteLine(ref lineno, "  {0,3},  /* {1,10} => {2} */", symbol.Fallback.ID, symbol.Name, symbol.Fallback.Name);
                    }
                }
            }
            Template.Transfer(ctx.Name, r, w, ref lineno);

            /* Generate a table containing the symbolic name of every symbol */
            var i_ = 0;

            for (i_ = 0; i_ < ctx.Symbols.Length - 1; i_++)
            {
                w.Write("  {0,-15}", string.Format("\"{0}\",", ctx.Symbols[i_].Name));
                if ((i_ & 3) == 3)
                {
                    w.WriteLine(ref lineno);
                }
            }
            if ((i_ & 3) != 0)
            {
                w.WriteLine(ref lineno);
            }
            Template.Transfer(ctx.Name, r, w, ref lineno);

            /* Generate a table containing a text string that describes every rule in the rule set of the grammar.  This information is used when tracing REDUCE actions. */
            i_ = 0;
            for (var rule = ctx.Rule; rule != null; rule = rule.Next, i_++)
            {
                Debug.Assert(rule.ID == i_);
                w.Write(" /* {0,3} */ \"", i_);
                WriteRuleText(w, rule);
                w.WriteLine(ref lineno, "\",");
            }
            Template.Transfer(ctx.Name, r, w, ref lineno);

            /* Generate code which executes every time a symbol is popped from the stack while processing errors or while destroying the parser.  (In other words, generate the %destructor actions) */
            if (ctx.TokenDestructor != null)
            {
                var once = true;
                for (var i = 0; i < ctx.Symbols.Length - 1; i++)
                {
                    var symbol = ctx.Symbols[i];
                    if (symbol == null || symbol.Type != SymbolType.Terminal)
                    {
                        continue;
                    }
                    if (once)
                    {
                        w.WriteLine(ref lineno, "      /* TERMINAL Destructor */");
                        once = false;
                    }
                    w.WriteLine(ref lineno, "    case {0}: /* {1} */", symbol.ID, symbol.Name);
                }
                var i2 = 0;
                for (; i2 < (ctx.Symbols.Length - 1) && (ctx.Symbols[i2].Type != SymbolType.Terminal); i2++)
                {
                    ;
                }
                if (i2 < ctx.Symbols.Length - 1)
                {
                    EmitDestructor(w, ctx.Symbols[i2], ctx, ref lineno, filePath);
                    w.WriteLine(ref lineno, "      break;");
                }
            }
            if (ctx.DefaultDestructor != null)
            {
                var dflt_sp = (Symbol)null;
                var once    = true;
                for (var i = 0; i < ctx.Symbols.Length - 1; i++)
                {
                    var symbol = ctx.Symbols[i];
                    if (symbol == null || symbol.Type == SymbolType.Terminal || symbol.ID <= 0 || symbol.Destructor != null)
                    {
                        continue;
                    }
                    if (once)
                    {
                        w.WriteLine(ref lineno, "      /* Default NON-TERMINAL Destructor */");
                        once = false;
                    }
                    w.WriteLine(ref lineno, "    case {0}: /* {1} */", symbol.ID, symbol.Name);
                    dflt_sp = symbol;
                }
                if (dflt_sp != null)
                {
                    EmitDestructor(w, dflt_sp, ctx, ref lineno, filePath);
                }
                w.WriteLine(ref lineno, "      break;");
            }
            for (var i = 0; i < ctx.Symbols.Length - 1; i++)
            {
                var symbol = ctx.Symbols[i];
                if (symbol == null || symbol.Type == SymbolType.Terminal || symbol.Destructor == null)
                {
                    continue;
                }
                w.WriteLine(ref lineno, "    case {0}: /* {1} */", symbol.ID, symbol.Name);
                /* Combine duplicate destructors into a single case */
                for (var j = i + 1; j < ctx.Symbols.Length - 1; j++)
                {
                    var symbol2 = ctx.Symbols[j];
                    if (symbol2 != null && symbol2.Type != SymbolType.Terminal && symbol2.Destructor != null && symbol2.DataTypeID == symbol.DataTypeID && symbol.Destructor == symbol2.Destructor)
                    {
                        w.WriteLine(ref lineno, "    case {0}: /* {1} */", symbol2.ID, symbol2.Name);
                        symbol2.Destructor = null;
                    }
                }
                EmitDestructor(w, ctx.Symbols[i], ctx, ref lineno, filePath);
                w.WriteLine(ref lineno, "      break;");
            }
            Template.Transfer(ctx.Name, r, w, ref lineno);

            /* Generate code which executes whenever the parser stack overflows */
            Template.Write(w, ctx, ctx.StackOverflow, ref lineno, filePath);
            Template.Transfer(ctx.Name, r, w, ref lineno);

            /* Generate the table of rule information
            ** Note: This code depends on the fact that rules are number sequentually beginning with 0. */
            for (var rule = ctx.Rule; rule != null; rule = rule.Next)
            {
                w.WriteLine(ref lineno, "  {{ {0}, {1} }},", rule.LHSymbol.ID, rule.RHSymbols.Length);
            }
            Template.Transfer(ctx.Name, r, w, ref lineno);

            /* Generate code which execution during each REDUCE action */
            for (var rule = ctx.Rule; rule != null; rule = rule.Next)
            {
                TranslateRuleCode(ctx, rule);
            }
            /* First output rules other than the default: rule */
            for (var rule = ctx.Rule; rule != null; rule = rule.Next)
            {
                if (rule.Code == null)
                {
                    continue;
                }
                if (rule.Code[0] == '\n' && rule.Code.Length == 1)
                {
                    continue;                                                /* Will be default: */
                }
                w.Write("      case {0}: /* ", rule.ID);
                WriteRuleText(w, rule);
                w.WriteLine(ref lineno, " */");
                for (var rule2 = rule.Next; rule2 != null; rule2 = rule2.Next)
                {
                    if (rule2.Code == rule.Code)
                    {
                        w.Write("      case {0}: /* ", rule2.ID);
                        WriteRuleText(w, rule2);
                        w.WriteLine(ref lineno, " */ yytestcase(yyruleno=={0});", rule2.ID);
                        rule2.Code = null;
                    }
                }
                EmitRuleCode(w, rule, ctx, ref lineno, filePath);
                w.WriteLine(ref lineno, "        break;");
                rule.Code = null;
            }
            /* Finally, output the default: rule.  We choose as the default: all empty actions. */
            w.WriteLine(ref lineno, "      default:");
            for (var rule = ctx.Rule; rule != null; rule = rule.Next)
            {
                if (rule.Code == null)
                {
                    continue;
                }
                Debug.Assert(rule.Code[0] == '\n' && rule.Code.Length == 1);
                w.Write("      /* ({0}) ", rule.ID);
                WriteRuleText(w, rule);
                w.WriteLine(ref lineno, " */ yytestcase(yyruleno=={0});", rule.ID);
            }
            w.WriteLine(ref lineno, "        break;");
            Template.Transfer(ctx.Name, r, w, ref lineno);

            /* Generate code which executes if a parse fails */
            Template.Write(w, ctx, ctx.ParseFailure, ref lineno, filePath);
            Template.Transfer(ctx.Name, r, w, ref lineno);

            /* Generate code which executes when a syntax error occurs */
            Template.Write(w, ctx, ctx.SyntaxError, ref lineno, filePath);
            Template.Transfer(ctx.Name, r, w, ref lineno);

            /* Generate code which executes when the parser accepts its input */
            Template.Write(w, ctx, ctx.ParseAccept, ref lineno, filePath);
            Template.Transfer(ctx.Name, r, w, ref lineno);

            /* Append any addition code the user desires */
            Template.Write(w, ctx, ctx.ExtraCode, ref lineno, filePath);
        }
示例#2
0
        /* Generate the action table and its associates:
        **
        **  yy_action[]        A single table containing all actions.
        **  yy_lookahead[]     A table containing the lookahead for each entry in
        **                     yy_action.  Used to detect hash collisions.
        **  yy_shift_ofst[]    For each state, the offset into yy_action for
        **                     shifting terminals.
        **  yy_reduce_ofst[]   For each state, the offset into yy_action for
        **                     shifting non-terminals after a reduce.
        **  yy_default[]       Default action for each state.
        */
        public static EmitterActionTable Make(Context ctx, out int maxTokenOffset, out int minTokenOffset, out int maxNonTerminalOffset, out int minNonTerminalOffset)
        {
            /* Compute the actions on all states and count them up */
            var ax = new AX[ctx.States * 2];

            for (var i = 0; i < ctx.States; i++)
            {
                var state = ctx.Sorted[i];
                ax[i * 2] = new AX {
                    State = state, Token = true, Actions = state.TokenActions
                };
                ax[i * 2 + 1] = new AX {
                    State = state, Token = false, Actions = state.NonTerminalActions
                };
            }
            maxTokenOffset       = minTokenOffset = 0;
            maxNonTerminalOffset = minNonTerminalOffset = 0;
            /* Compute the action table.  In order to try to keep the size of the action table to a minimum, the heuristic of placing the largest action sets first is used. */
            for (var i = 0; i < ctx.States * 2; i++)
            {
                ax[i].iOrder = i;
            }
            Array.Sort(ax, _keyComparer);
            var actionTable = new EmitterActionTable();

            for (var i = 0; i < ctx.States * 2 && ax[i].Actions > 0; i++)
            {
                var state = ax[i].State;
                if (ax[i].Token)
                {
                    foreach (var action in state.Actions)
                    {
                        if (action.Symbol.ID >= ctx.Terminals)
                        {
                            continue;
                        }
                        var actionID = action.ComputeID(ctx);
                        if (actionID < 0)
                        {
                            continue;
                        }
                        actionTable.Action(action.Symbol.ID, actionID);
                    }
                    state.TokenOffset = actionTable.Insert();
                    if (state.TokenOffset < minTokenOffset)
                    {
                        minTokenOffset = state.TokenOffset;
                    }
                    if (state.TokenOffset > maxTokenOffset)
                    {
                        maxTokenOffset = state.TokenOffset;
                    }
                }
                else
                {
                    foreach (var action in state.Actions)
                    {
                        if (action.Symbol.ID < ctx.Terminals)
                        {
                            continue;
                        }
                        if (action.Symbol.ID == ctx.Symbols.Length - 1)
                        {
                            continue;
                        }
                        var actionID = action.ComputeID(ctx);
                        if (actionID < 0)
                        {
                            continue;
                        }
                        actionTable.Action(action.Symbol.ID, actionID);
                    }
                    state.NonTerminalOffset = actionTable.Insert();
                    if (state.NonTerminalOffset < minNonTerminalOffset)
                    {
                        minNonTerminalOffset = state.NonTerminalOffset;
                    }
                    if (state.NonTerminalOffset > maxNonTerminalOffset)
                    {
                        maxNonTerminalOffset = state.NonTerminalOffset;
                    }
                }
            }
            ax = null;
            return(actionTable);
        }