研究 JLex(5)

2.5)DFA的状态最小化

在CLexGen.userRules()函数中调用CMinimize.min_dfa(),而min_dfa()函数又调用:

   1)CMinimize.minimize()来实现DFA的状态最小化的,其使用的算法是《编译原理》
        龙书算法3.39。
   2)CMinimize.reduce()实现col,row压缩。这在下面2.6)节研究。

函数CMinimize.minimize()具体实现:

    1)调用CMinimize.init_groups()构造初始划分П,其根据终态(m_accept值)划分
为多个组。与书上不同的是,由于实现中有多个rule就有多个终态,每个终态一个组,
所有非终态一个组。每个组有1-N个 CDfa 状态。
    2)foreach(П中的每个组g)
      2.1)如果组g只有一个状态则不用/不能划分了。继续下一个组。
      2.2)取出组g的第一个DFA状态first,和本组中的其它DFA状态x进行比较,
           比较的方法是,为所有可能输入比较转移目标是否在同一个组,如果
           不在同一个组,则将状态x分离到一个新的组new_group中。新的组加入
           到П中。
      2.3)循环直到所有组都无法再划分了。
    3)调用函数fix_dtrans()使用组替代原来的状态,成为新的压缩后的状态,完成 
       minimize。这一步骤相当于书上算法3.39的步骤4)的部分。

这里的代码和书上所述完全相同,只是嵌套了3层循环(时间复杂度O(n**3)),而且
很多集合的运算,所以慢是有可能的。

下面研究 

2.6)状态转换表的列(col)、行(row)压缩。

如上所述CMinimize.reduce()函数负责此任务,其在min_dfa()中被调用。

在前述DFA生成,以及状态最小化之后,实质我们等于有一个dtrans[row][col]
的二维表格,其为状态转换表。实现为Vector<CDTrans> CSpec.m_dtrans_vector,
每个CDTrans表示dtrans的一行,即dtrans[row]。在CDTrans中有成员m_dtrans[],
其相当于dtrans[某一具体row][col]。

所谓列压缩,指二维dtrans[row][col]中,可能有某两列完全相同,则可压缩为
一个列。具体算法并不复杂,这里不详述了。压缩后产生一个小的映射表,其在
产生(emit)lexer程序的时候使用。

所谓行压缩,类似于列压缩,是查找dtrans[row][col]中是否有完全相同的两行,
但发现之后并不是合并/删除该行的状态,而是采用映射row到新row的方式。算法
亦不复杂,不再详述。可参见代码。同样产生一个小的映射表。

以下研究如何产生lexer程序代码(2.7),以及该lexer是如何运作的(driver)。

 

你可能感兴趣的:(研究 JLex(5))