How to determine maximum stack size of LL(1) parser? I am generating an LL(1) parser generator for LL(1) grammars that have a maximum stack size when executed in the table-driven parser. Specifically, I'm parsing HTTP headers using a parser generated by the LL(1) parser generator.

In case somebody asks, yes, it's possible to parse plaintext HTTP using LL(1) parser, if the parser works together with the lexer, so that the parser automatically turns on and off tokens in the lexer. So, only those tokens that are valid in the context are matched in the deterministic finite automaton (DFA).

The particular grammar I'm using for my tests is this (yes, I know it's possible to fold the first header line incorrectly using the grammar, I'll fix this later):

headerField -&gt; foldstart httpfield
headerField -&gt; httptoken colon optspace httpfield
httpVersion -&gt; httpname slash digit period digit
requestLine -&gt; httptoken onespace uri onespace httpVersion crlf
requestHdrs -&gt; (epsilon)
requestHdrs -&gt; headerField crlf requestHdrs
requestWithHeaders -&gt; requestLine requestHdrs crlf


The start nonterminal is requestWithHeaders. The terminals are:

crlf, onespace, httpname, slash, digit, colon, optspace
httptoken, httpfield, period, uri, foldstart


...so every name that is lowercase only is terminal, and if there are uppercase characters in the middle, it's nonterminal.

Now, if I start using the stack [(endOfFile), requestWithHeaders], the maximum stack size is ever going to be 9 according to my tests. So, this grammar appears to have a maximum stack size.

The question is: how to prove the maximum stack size? I'm looking for an algorithm that terminates and gives me the answer 9 for this grammar. The algorithm need not terminate for a grammar that doesn't have a maximum stack size, so infinite recursion and infinite loops are permitted if the maximum stack size doesn't exist. (I can always limit the amount of CPU time given to the algorithm.)

I already have the code to calculate first-sets and follow-sets, and the code to generate the parser table, and the code to execute the parser using the parser table, so I'm not looking for advice for standard LL(1) parser implementation. I have already tested my parser with valid and invalid HTTP examples, and everything seems to work just fine.

The reason I'd like to determine this maximum stack size is that I want to avoid dynamic memory allocation in the parser. There is no need to allocate memory dynamically for cases where there is an upper bound for the stack size.
OK.  So you have a pushdown automaton, and out of all reachable stack configurations, you want to know the stack depth (length) of the longest such configuration.

I have two answers: a simple, practical answer that might suffice for your specific situation but doesn't scale, and a general answer that will apply more broadly.

Simple answer

Enumerate all possible stack configurations. This should be easy.  Just think of this as a giant graph, with one vertex per reachable stack configuration, and an edge from each such stack configuration to every other configuration that is reachable in a single step.  Now use any graph exploration algorithm, such as DFS, to explore the graph.  Out of all the configurations you visit, keep track of which one had the largest stack depth.

You have 5 nonterminals.  If the maximum stack depth is $9$, there will be at most $5^9$ reachable stack configurations, i.e., about 2 million of them.  It's easy to explore all such configurations and store them all in a simple data structure.

Of course this would not scale to larger cases, as the complexity is exponential.

General solution

The set of reachable stack configurations of a pushdown automaton is regular.  Therefore, you can build a DFA that concisely represents all such reachable stack configurations.  This DFA is not too large (linear in the size of the PDA, I think) and can be built efficiently (in quadratic or cubic time, I think).  Then, you can check whether the DFA has any cycles and the length of the longest path in the DFA, and that will tell you the stack depth of the deepest reachable stack configuration.

This will give you an efficient, polynomial-time algorithm that scales even to large, non-trivial grammars.  The cost is that it takes more work to understand the algorithms and implement them correctly, so I'd try the simple solution above first, and only fall back to this if necessary.