Compiler - lexical analysis

概念:
1. Context-Free Grammar: a). 一个终结符集合。b). 一个非终结符集合。c). 一个产生式集合,产生式左部为一个非终结符,右部为终结符或非终结符序列。d). 一个初始状态。
2. Parse Tree(Concrete Syntax Tree), Abstract Syntax Tree(AST)
文法: list -> list+digit | list-digit | digit; digit -> 0|1|2|3|4|5|6|7|8|9
   
抽象语法树不包含具体的文法信息(或形式)
3. Syntax-Directed Translation
翻译模式: 参考Antlr中的Arbitrary Actions。Syntax-Directed: 文法符号与一个属性集合关联,产生式与一个语义规则集合关联,文法符号(属性集合)和语义规则集合构成Syntax-Directed定义,参考Antlr的Rewrite Rules
4. Nondeterministic finite automata NFA
a). 一个状态的有穷集合S; b). 一个输入符号集合Σ; c). 一个转换函数move,把状态和符号组成的二元组映射到状态集合; d). 状态s0是唯一的初始状态; d). 状态集合F是终止状态集合
5. Deterministic finite automata DFA
DFA是NFA的特例,DFA在任何状态下,对任一输入符号最多只有一个转换
a). 没有一个状态具有ε转换; b). 对每个状态s和输入符号a,最多只有一条标记为a的边离开s

词法分析:
Token与Lexeme区别: Token相当于类型,lexeme相当于不同的实例。例如token为relation,lexeme可能包括<, >, <>, <=, >=等;例如token为id,lexeme可能包括源代码中出现的所有标识符
语法上的运算: 并集 L∪M; 连接 LM; 闭包L*; 正闭包L+。语法树上如果一个节点被标记为连接、或、闭包操作,则该节点分别简称为cat-node, or-node, star-node

1. Transition Diagram及其实现
语法: num->digit+(.digit+)?(E+|-)?digit+)?
状态图:
   
为了实现类似greedy效果,给出了3个状态图,图一匹配12.3E-4的形式,图二匹配12.3这样的形式,图三匹配123这样的形式。如果状态图一匹配失败,尝试继续匹配状态图二...
示例代码:
    
while  ( 1 )
    {
        
switch  (state)
        {
            
case   0 :
                c 
=  NextChar();  // c is lookahead char
                 if  (c  ==  BLANK  ||  c  ==  TAB  ||  c  ==  NEWLINE) 
                    lexeme_beginning
++ // the lexeme pointer (advance beginning of lexeme)
                 else   if  (IsDigit(c)) state  =   1 // only digit char is accepted by state 0
                 else  Fail();
                
break ;
            
case   1 :
                c 
=  NextChar();
                
if  (IsDigit(c)) state  =   1 ;
                
else   if  (c  ==   ' . ' ) state  =   2 ;
                
else   if  (c  ==   ' E ' ) state  =   4 ;
                
else  Fail();
                
break ;
            
//...  case 2--6 here
             case   7 :
                Retract(
1 );  // put the lookahead char back into the input stream
                InstallNum();  // install the matched token into symbol table
                 return  GetToken();  // return the matched token
             case   8 :
                
if  (IsDigit(c)) state  =   9 ;
                
else  Fail();
                
break ;
            
//...  case 9--14 here
             case   15 :
                Retract(
1 );
                InstallNum();
                
return  GetToken();
        }
    }

2. Thompson's Construction 从正则表达式构造NFA
输入: 字母表Σ上的一个正则表达式r
输出: 接受L(r)的NFA N
分析r并将其分解成最基本的子表达式,如果a在r中出现多次,需要为a的每次出现构造NFA
2.1 对ε构造NFA
2.2 对Σ中的每个符号a构造NFA
   
2.3 如果N(s)和N(t)是正则表达式s和t的NFA,则:
  
椭圆中N(s)和N(t)左边部分为开始状态,右边部分为终止状态集合;st的NFA中,N(s)的终止状态与N(t)的开始状态合并
正则表达式(s)的NFA为N(s)本身

例用上面的方法为 r->(a|b)*abb 构造的NFA N(r)为:
   

3. Subset Construction - 从NFA构造DFA
输入: 一个NFA N
输出: 一个接受同样语言的DFA D

ε-closure(T)算法:
    push all states in T onto stack;
    initialize ε
- closure(T) to T;
    
while stack is not empty do   begin
        pop t, the top element, off of stack;
        
for each state u with an edge from t to u labeled ε do
            
if  u is not in ε - closure(T) do   begin
                add u to ε
- closure(T);
                push u onto stack;
            
end
    
end

Subset construction(s0为NFA的初始状态;Dstates为DFA中的状态集合;Dtrans为DFA中的转换规则集合):
    initially, ε - closure(s0) is the only state in Dstates and it is unmarked;
    
while there is an unmarked state T in Dstates do   begin
        mark T;
        
for each input symbol a do   begin
            U :
=  ε - closure(move(T, a));
            
if  U is not in Dstates then
                add U as an unmarked state to Dstates;
            Dtrans[T, a] :
=  U;
        
end
    
end

示例将2.3中构造的NFA转换为DFA:
    A  =  ε - closure({  0  })  =  {  0 , 1 , 2 , 4 , 7  }
    B 
=  ε - closure(move(A, a))  =  ε - closure({  3 , 8  })  =  {  1 , 2 , 4 , 6 , 7 , 8  }; Dtrans[A, a]  =  B;
    C 
=  ε - closure(move(A, b))  =  ε - closure({  4  })  =  {  1 , 2 , 4 , 5 , 6 , 7  }; Dtrans[A, b]  =  C;
    D
'  = ε-closure(move(B, a)) = ε-closure({ 3,8 }) = B; Dtrans[B, a] = B;
    D  =  ε - closure(move(B, b))  =  ε - closure({  5 , 9  })  =  {  1 , 2 , 4 , 5 , 6 , 7 , 9  }; Dtrans[B, b]  =  D;
    继续这一过程,还会得到一个DFA状态以及剩余的转换规则集合
    E 
=  {  1 , 2 , 4 , 5 , 6 , 7 , 10  }; ...
得到的DFA如图:
   

4. 从正则表达式构造DFA
输入: 正则表达式r
输出: 识别L(r)的DFA D
算法: 构造扩展正则表达式(r)#的语法树T; 对T进行深度优先遍历计算函数nullable, firstpos, lastpos和followpos; 用下面的算法计算Dstates和Dtrans
    initially, the only unmarked state in Dstates, where root is the root of the syntax tree for (r)#;
    
while there is an unmarked state T in Dstates do   begin
        mark T;
        
for each input symbol a  do   begin
            let U be the set of positions that are in followpos(p) for some position p in T, such that the symbol at position p is a;
            
if  U is not empty and is not in Dstates then
                add U as an unmarked state to Dstates;
            Dtrans[T, a] :
=  U;
        
end
    
end
在正则表达式r后面添加#符号,目的是使r具有唯一的结束标识; nullable, firstpos, lastpos计算方法:
a). 标记为ε的叶节点n: nullable(n)=true; firstpos(n)=Φ;
b). 标记为位置i的叶节点n: nullable(n)=false; firstpos(n)={i};
c). n=c1 |c2: nullable(n)=nullable(c1) or nullable(c2); firstpos(n)=fistpos(c1)∪firstpos(c2);
d). n=c1●c2: nullable(n)=nullable(c1) and nullable(c2); firstpos(n)= if nullable(c1) then firstpos(c1)∪firstpos(c2) else firstpos(c1);
e). n=(c1) *: nullable(n)=true; firstpos(n)=firstpos(c1);
followpos计算方法:
a). 如果n是cat-node,具有左子节点c1和右子节点c2,并且i是lastpos(c1)中的一个位置,则firstpos(c2)中的所有位置都在followpos(i)中
b). 如果n是star-node,并且i是lastpos(n)中的一个位置,则所有firstpos(n)中的位置都在followpos(i)中

以r -> (a|b)*abb为例,扩展正则表达式(r)#的语法树、firstpos、lastpos和followpos如下图:
       
创建有向图来表示followpos: 节点表示位置; 从i到j的有向边表示j在followpos(i)中
   
根据上面的算法计算DFA:
    firstpos(root) = firstpos( 6 ) = { 1 , 2 , 3 } = A;
    Dtrans[A, a]
= followpos( 1 )∪followpos( 3 ) = { 1 , 2 , 3 , 4 } = B;
    Dtrans[A, b]
= followpos( 2 ) = { 1 , 2 , 3 } = A;
    Dtrans[B, a]
= followpos( 1 )∪followpos( 3 ) = B;
    Dtrans[B, b]
= followpos( 2 )∪followpos( 4 ) = { 1 , 2 , 3 , 5 } = C;
    Dtrans[C, a]
= followpos( 1 )∪followpos( 3 ) = B;
    Dtrans[C, b]
= followpos( 2 )∪followpos( 5 ) = { 1 , 2 , 3 , 6 } = D;
    Dtrans[D, a]
= followpos( 1 )∪followpos( 3 ) = B;
    Dtrans[D, b]
= followpos( 2 ) = A;
构造的DFA图:
   
与图3.1比较,图4.4的DFA少了一个状态

5. 最小化DFA的状态数
理论上每一个正则集都可以由一个状态数最少的DFA识别,这个DFA是唯一的,开始状态为s0,接受状态集为F
输入: DFA M,状态集合为S,输入符号集合为Σ
输出: 一个DFA M',它和M接受同样的语言,且状态数最少
算法:
    a). 使S中每个状态对Σ中的每个输入符号都有转换; 对那些不存在转换的,引入一个"dead state"d,即任何状态对Σ上的任意输入字符都可以转换到d
    b). 构造具有两个组的状态集合的初始划分Ⅱ: 接受状态组F,非接受状态组S
- F
    c). 用下面的方法构造新的划分Ⅱnew
        
for  Ⅱ中的每个组G  do   begin
            当且仅当对任意输入符号a,G中的状态s和t在a上的转换都到达Ⅱ中的同一个组时,才把G化分成一个小组(不符合这个规则的话G必须再拆分);
            用所有新形成的小组集合代替Ⅱnew中的小组集合;
        
end
    d). 如果Ⅱnew
= Ⅱ,令Ⅱfinal = Ⅱ,执行步骤e);否则令Ⅱ = Ⅱnew,重复步骤c)
    e). 为Ⅱfinal构造转换规则集
    f). 移除Ⅱfinal中的"dead state",取消从任何状态到"dead state"的转换规则; 删除从开始状态不可到达的状态;

最小化图3.1的DFA状态数:
    a). A, B, C, D, E对输入字符a, b都有转换,不需要添加 " dead state " ; 初始划分Ⅱ: {A, B, C, D}, {E}
    b). {E}不可再划分,直接加入Ⅱ
new  ; 
         对于输入字符a,A, B, C, D都转换到状态B,符合要求; 
         对于输入字符b,A, B, C转换到的状态都位于本组内,但D将转换到E,因此将D划分出去,将新的分组{A, B, C}和{D}加入Ⅱ
new ;
    c). 继续b)的步骤,得到Ⅱfinal : {A, C}, {B}, {D}, {E},即最小化状态的DFA,与图4.4一样
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值