first、follow、select集的计算

本文深入浅出地介绍了自顶向下语法分析中的关键概念:First集、Follow集和Select集的计算方法。First集是指从非终结符推导出的所有串首终结符集合;Follow集是在某句型中紧跟在非终结符后的终结符集合;Select集用于确定预测分析表中的条目。文章提供了易于理解的算法步骤。

在进行语法分析的时候,特别是自顶向下的语法分析,比如LL(1)分析、LL(0)分析,需要求出文法的first集和follow集,进而求出select集,然后根据select集得到预测分析表。但书上给的计算方法过于形式化,相对来说比较抽象,不易理解,所以,下面介绍好理解的计算方法。

first 集

基本定义如下:

first(X): 可以从X推导出的所有串首终结符构成的集合

若 X ->˙ε,则 ε∈first(X)

算法如下:

运用以下规则,直到没有任何终结符或ε可以被加入到任何first集中为止

  1. X如果是一个终结符,则 first(X)={X}
  2. X如果是一个非终结符,且X->Y···Y∈P(k>=1)
    1. 若 Y -/->ε,则first(X)=first(Y)
    2. 若 Y -->ε,Y -/->ε,则 first(X) = first(Y) + first(Y) ,其中包含ε
    3. 若 Y 的前(k-1)个都能推导出 ε,则把 first(Y)··· first(Y) 和 ε 加入到first(X)中
    4. X -->ε,则把 ε 加入到first(X)中

follow 集

定义:

follow(A):可能在某个句型中紧跟在 A后面的 终结符a的集合

如果 A 是某个句型的最右符号,则将结束符 # 加入到 follow(A)中

计算方法:

  1. 将 # 放入follow(S)中,S 是开始符号
  2. 对于 A–>αBβ
    1. ε 不属于 first(β),则 follow(B) = first(β)
    2. εfirst(β),则 follow(B) = first(β) - {ε} + follow(A)
  3. A–>αBfollow(B) = follow(A)

注意:上面说的α,既可以是终结符,也可以是非终结符

select 集

这里先定义α 代表 一个 终结符,大写字母 是 非终结符

  • 对于产生式 A->BC 或 A->B
    • B 推不出 ε,则 select(A->BC) = first(B)
    • B 推出 ε,则 select(A->BC) = [first(B) - {ε}] U follow(A)
  • 对于产生式 A->αB,则 select(A->αB) = {α}
### 计算FIRST FIRST用于确定一个文法符号串的最左终结符合。其计算方法如下: 1. 如果 $ X \in V_T $(即X是终结符),则 $ FIRST(X) = \{X\} $。 2. 如果 $ X \in V_N $(即X是非终结符)且有产生式 $ X \rightarrow a\beta $,其中 $ a \in V_T $,则 $ a \in FIRST(X) $。 3. 如果 $ X \rightarrow \epsilon $,则 $ \epsilon \in FIRST(X) $。 4. 如果 $ X \rightarrow Y_1Y_2...Y_n $,其中 $ Y_i \in V_N $,那么: - 当 $ Y_1 \Rightarrow \epsilon, Y_2 \Rightarrow \epsilon, ..., Y_{i-1} \Rightarrow \epsilon $ 时,则 $ FIRST(Y_1)-\{\epsilon\}, FIRST(Y_2)-\{\epsilon\}, ..., FIRST(Y_{i-1})-\{\epsilon\}, FIRST(Y_i) $ 都应包含在 $ FIRST(X) $ 中。 - 如果所有 $ Y_i \Rightarrow \epsilon $,则 $ FIRST(X) = FIRST(Y_1) \cup FIRST(Y_2) \cup ... \cup FIRST(Y_n) \cup \{\epsilon\} $。 ### 计算FOLLOW FOLLOW用于确定一个非终结符后面可能跟随的终结符合。其计算方法如下: 1. 对于文法的开始符号 $ S $,$ FOLLOW(S) $ 包含 $ \$ $(输入结束标记)。 2. 如果存在产生式 $ A \rightarrow \alpha B \beta $,则 $ FIRST(\beta) - \{\epsilon\} $ 加入到 $ FOLLOW(B) $ 中。 3. 如果存在产生式 $ A \rightarrow \alpha B $ 或者 $ A \rightarrow \alpha B \beta $ 且 $ \beta \Rightarrow \epsilon $,则 $ FOLLOW(A) $ 中的所有元素加入到 $ FOLLOW(B) $ 中。 ### 计算SELECT SELECT用于确定在预测分析表中选择哪一个产生式进行推导。其计算方法如下: 1. 对于每个产生式 $ A \rightarrow \alpha $: - 如果 $ \alpha \not\Rightarrow \epsilon $,则 $ SELECT(A \rightarrow \alpha) = FIRST(\alpha) $。 - 如果 $ \alpha \Rightarrow \epsilon $,则 $ SELECT(A \rightarrow \alpha) = (FIRST(\alpha) - \{\epsilon\}) \cup FOLLOW(A) $。 ### 示例代码 以下是一个简单的Python示例,展示如何手动实现这些合的计算: ```python def compute_first(grammar): first = {} # 初始化first合为空 for non_terminal in grammar: first[non_terminal] = set() changed = True while changed: changed = False for non_terminal, productions in grammar.items(): for production in productions: symbol = production[0] if symbol.islower(): # 终结符 if symbol not in first[non_terminal]: first[non_terminal].add(symbol) changed = True else: # 非终结符 added = False for sym in production: if sym == 'ε': if 'ε' not in first[non_terminal]: first[non_terminal].add('ε') changed = True break if sym in grammar: prev_count = len(first[non_terminal]) first[non_terminal].update(first[sym] - {'ε'}) if 'ε' in first[sym]: if len(first[non_terminal]) != prev_count: changed = True else: break else: if 'ε' not in first[non_terminal]: first[non_terminal].add('ε') changed = True return first def compute_follow(grammar, first): follow = {nt: set() for nt in grammar} follow['S'].add('$') # 假设S是开始符号 changed = True while changed: changed = False for non_terminal, productions in grammar.items(): for production in productions: for i in range(len(production)): symbol = production[i] if symbol.isupper(): # 非终结符 rest = production[i+1:] rest_first = set() for r in rest: if r == 'ε': rest_first.add('ε') elif r.islower(): rest_first.add(r) break else: rest_first.update(first[r]) if 'ε' not in first[r]: break else: rest_first.discard('ε') prev_len = len(follow[symbol]) follow[symbol].update(rest_first) follow[symbol].update(follow[non_terminal]) if len(follow[symbol]) != prev_len: changed = True if 'ε' in rest_first: prev_len = len(follow[symbol]) follow[symbol].update(follow[non_terminal]) if len(follow[symbol]) != prev_len: changed = True return follow def compute_select(grammar, first, follow): select = {} for non_terminal, productions in grammar.items(): for i, production in enumerate(productions): key = f"{non_terminal} -> {''.join(production)}" alpha = production if alpha == ['ε']: select[key] = follow[non_terminal] else: select_set = set() for sym in alpha: select_set.update(first[sym]) if 'ε' not in first[sym]: break else: select_set.discard('ε') select_set.update(follow[non_terminal]) select[key] = select_set return select # 示例文法 grammar = { 'S': [['A', 'a'], ['b']], 'A': [['c', 'd'], ['ε']] } first = compute_first(grammar) follow = compute_follow(grammar, first) select = compute_select(grammar, first, follow) print("First sets:", first) print("Follow sets:", follow) print("Select sets:", select) ``` ###
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值