【编译原理】First集和Follow集

LL(1)语法的功能

回退会导致分析器的效率问题。

如果我们能够预测每个步骤中每个产品的正确选择,这将是避免的。

预测分析处理:

  1. 从开始符号开始,根据最左边的非终端符号A和输入符号“a”,选择正确的产生式。
  2. 所选产品必须是唯一的,以确保分析的正确性。
  3. 如何选择正确的产生式?

S-语法(Korenjak&Hopcroft,1966)

要使预测处理正常工作,必须遵循以下步骤:

  1. 每个产生式右测必须以终结符开始。
  2. 对于相同的非终结符,每个候选产生式的第一个终结符必须不同。

所以,我们可以根据输入符号选择一个产生式(不会产生冲突)。

ε产生式(右部为空符号串的产生式)是不包含在内的。

语法的应用受到限制。

First集合和FOLLOW集合的作用

First集合的定义:该规则派生出的字符串的第一个终结符集合。
Follow集合的定义:该规则派生的字符串后面可以立即出现的终结符集合。

规则的一个例子

就编程语言的编译器而言,我们有一个用于IF语句的规则:

  1. if_statement => IF Boolean_expression THEN statement;
  2. 我们期望FIRST集至少包含IF token。
  3. 如果IF语句后面可以跟任何编程语句,那么FOLLOW集将由所有可以启动任何编程语句的tokens组成。例如,IF,WHILE等。

First集合

我们首先为任何由终端和非终端组成的字符串a定义集合FIRST(a)

这是派生自a的字符串的第一个(即最左边)终结符的所有终结符的集合。

也称为 Left Terminal Set

Follow集合

例子:
Z -> XY
Y -> start_y Q
语法告诉我们X后面紧跟着Y。
Y以token start_y开始,所以start_y是X的追随者。

First集合举例

meal → first_course second_course dessert;
这个产生式法则告诉我们,一顿饭由第一道菜、第二道菜和甜点组成。

first_course → SOUP | SALAD | ε;
ε是一个表示什么都没有的特殊符号
换句话说,用餐者可能会选择跳过第一道菜
这意味着我们的语法包含一个空结果

second_course →CHICKEN | FISH | BEEF | LAMB
所以一顿饭可以是汤和鸡肉,也可以只是鸡肉

FIRST(first_course) = {SOUP , SALAD, ε };
FIRST(second_course) = {CHICKEN, FISH, BEEF,LAMB};

因为first_course生成规则可以生成空的,这意味着我们在处理meal时可能看到的第一个终结符实际上属于first_course后面的规则,即second_course。

所以我们必须将second_course的集合(并集)添加到first_course的集合中。

FIRST(meal)=FIRST(first_course) U FIRST(second_course)={SOUP , SALAD} U {CHICKEN,FISH,BEEF,LAMB}={SOUP , SALAD, CHICKEN,FISH,BEEF,LAMB};

Follow集合举例

meal →first_course second_course dessert;
first_course →SOUP|SALAD| ε;
second_course →CHICKEN|FISH|BEEF|LAMB;

FIRST(second_course) = {CHICKEN,FISH,BEEF,LAMB};

first_course后面是什么? The FIRST(second_course)!

So, FOLLOW(first_course)= {chicken, fish, beef, lamb};

FIRST集和FOLLOW集的构造

如果X可以生成空字符串,FIRST(XY)不仅仅是FIRST(X),它是FIRST(X) U FIRST(Y);

这是因为FIRST(X)可能是{ε}(空集合),因此我们必须考虑什么是Y的FIRST集合;

为了构造FIRST(α),其中α→X1 X2…Xn (假设简单的BNF格式):
如果X1是终结符,则将其加入FIRST(α)
如果X1是非终结符,语法规则为X1→β,则将FIRST(X1)加入FIRST(α)
如果X1可以生成空字符串,如果X1可以生成空字符串,那么考虑可以开始X2的终结符,依此类推

FOLLOW集的构造I

night_out →meal drink;
drink →BEER|WINE|VODKA;

FOLLOW(meal) = {BEER, WINE, VODKA};

After we’ve had a meal, we go for a drink
What can follow a meal?
寻找meal在右手边的产生式
看看后面是什么

FOLLOW集合的构造II

为某些非终结符X构造FOLLOW(X):
把EOF放在FOLLOW(distinguished symbol)中。

如果有一个产生式 Y -> α X β, 将FIRST(β)添加到FOLLOW(X)

如果有一个产生式 Y -> α X, 或Y -> α X β 并且 β⇒ ε, 将FOLLOW(Y)添加到FOLLOW(X)。

区分符号是语法的“根”,即对于源文本,它可能是程序。

First算法的一个更简单的表述

语法中没有空

First(A)其中A->X1X2…XN

  1. 如果X1是终结符,把它加到FIRST(A)中。
  2. 如果X1是具有语法规则的非终结符,则将FIRST(X1)添加到FIRST(a)。

所以我们依次考虑每个非终结符。

Follow算法的一个更简单表述

Follow集

  1. 初始化FOLLOW set为{}
  2. 把EOF放在FOLLOW(distinguished symbol)中
  3. 如果Y→AXB,将FIRST(B)加入FOLLOW(X)中
  4. 如果Y→ZXc,将“c"加入FOLLOW(X)中
  5. 如果Y→AXB,将FOLLOW(B)加入FOLLOW(Y)中
  6. 继续执行,直到对下面的集合没有进一步的更改

再谈Follow算法

为了生成下面的集合,我们必须查看生成规则的右侧。

我们将其视为一个有序的项列表,其中项要么是终结符,要么是非终结符。

对于每一个非终结符的出现,我们都要看它后面的内容。

如果它是一个终结符,我们将它添加到下面的集合中。
如果它是一个非终结符,我们将该非终结符的FIRST集合添加到接下来的集合中。

如果它是一个非终结符,则将LHS(右手边)的FOLLOW集添加到该非终结符的FOLLOW集中。

Thanks to Dr. John: Some contents are from their slides.

  • 2
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值