First集Follow集通俗易懂的讲解加实例



文法:

S→ABc
A→a|ε

B→b|ε


First集合求法:

能由非终结符号推出的所有的开头符号或可能的ε,但要求这个开头符号是终结符号。如此题A可以推导出a和ε,所以FIRST(A)={a,ε};同理 FIRST(B)={b,ε};S可以推导出aBc,还可以推导出bc,还可以推导出c,所以FIRST(S)={a,b,c}


Follow集合的求法:
紧跟随其后面的终结符号或#。但文法的识别符号包含#,在求的时候还要考虑到ε。 具体做法是把所有包含你要求的符号的产生式都找出来,再看哪个有用。 Follow(S)={#}

如求A的Follow集   产生式:S→ABc A→a|ε ,但只有S→ABc 有用。跟随在A后年的终结符号是FIRST(B)={b,ε},当FIRST(B)的元素为ε时,跟随在A后的符号就是c,所以 Follow(A)={b,c} 同理Follow(B)={c}


上述如果没看懂的话,下面的讲解也可以作为参考


First
如A->aB | CD
这里面包含了组成First(A)的两种情况:
           以终结符开头,    当然要把这个终结符放到A的First里
           以非终结符开头, 先把C的First放到A的First里
                                        再看如果C的First中有空的话就把D的First放到A的First里,如果D也有空的话往后依次类推
技巧:First一般从下往上找。
           如果要找A的First,我们要找A的定义式,即A在左边的式子,看着他的右边来找。

Follow
S->(L) | aL | LC   
找Follow的三种情况:先在候选式(右边)中找到该非终结符,如L(注意例中只有一个定义,但找Follow要看到所有右边出现该非终结符的)
           如果L的右边是终结符,    那么这个终结符加入L的Follow
           如果L的右边是非终结符, 那么把这个非终结符的First除去空加到L的Follow中
           如果L处在末尾,               那么,'->'左边符号的Follow成为L的Follow
另外要注意的是:
           开始符号的Follow中要加上‘#’        
技巧:Follow一般从上往下找。
           如果要找L的Follow,要从式子的右边找到L,然后来找L的Follow,这与First是不同的。
















  • 49
    点赞
  • 89
    收藏
    觉得还不错? 一键收藏
  • 17
    评论
以下为文法的FirstFollow求解算法代码,其中文法的表示方式采用BNF范式。 ``` # 文法表示方式:BNF范式 grammar = { "<start>": ["<expr>"], "<expr>": ["<term><expr_tail>"], "<expr_tail>": ["+<term><expr_tail>", "-<term><expr_tail>", ""], "<term>": ["<factor><term_tail>"], "<term_tail>": ["*<factor><term_tail>", "/<factor><term_tail>", ""], "<factor>": ["(<expr>)", "<id>", "<num>"], "<id>": ["a", "b", "c"], "<num>": ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"] } # 计算First def calc_first(grammar): first = {} for symbol in grammar: first[symbol] = set() while True: updated = False for symbol in grammar: for production in grammar[symbol]: if production == "": continue first_alpha = set() for alpha in production: if alpha in first: first_alpha |= first[alpha] if alpha not in first: break else: if len(first_alpha - first[symbol]) > 0: updated = True first[symbol] |= first_alpha if not updated: break return first # 计算Follow def calc_follow(grammar, first): follow = {} for symbol in grammar: follow[symbol] = set() follow["<start>"].add("$") while True: updated = False for symbol in grammar: for production in grammar[symbol]: for i, alpha in enumerate(production): if alpha not in grammar: continue follow_alpha = set() for beta in production[i + 1:]: if beta in first: follow_alpha |= first[beta] - {""} if "" not in first[beta]: break else: follow_alpha |= {beta} break else: if len(follow_alpha - follow[alpha]) > 0: updated = True follow[alpha] |= follow_alpha if "" in follow_alpha or i == len(production) - 1: follow[symbol] |= follow[alpha] if "" in follow_alpha: follow[symbol] |= follow[symbol] if not updated: break return follow # 测试 first = calc_first(grammar) print("First set:") for symbol in first: print(f"{symbol} -> {first[symbol]}") follow = calc_follow(grammar, first) print("Follow set:") for symbol in follow: print(f"{symbol} -> {follow[symbol]}") ``` 在上述代码中,`calc_first(grammar)`函数用于计算文法的First,`calc_follow(grammar, first)`函数用于计算文法的Follow。其中,在计算Follow时需要使用到First,因此需要将计算First的结果作为参数传入`calc_follow`函数中。 具体实现中,使用了两个字典`first`和`follow`来分别保存文法的FirstFollow。在计算过程中,首先每个终结符的First初始化为空,每个终结符Follow初始化为$S$符号的Follow($S$为起始符号)。接着,使用循环遍历所有的产生式,根据产生式的右部计算出FirstFollow,并将其入到相应的集合中。在计算First时,需要使用到之前已经计算出的First;在计算Follow时,需要使用到之前已经计算出的Follow和First。在计算过程中,如果发现某个集合发生了更新,则需要重新进行循环,直到所有集合都不再更新为止。 最后,将计算得到的FirstFollow打印出来,用于验证结果的正确性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 17
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值