C slr 35:LR(0)和SLR解析有什么区别 (slr full form in railway)

我正在研究我的编译器概念,但我有点困惑......谷歌搜索让我无处得到一个明确的答案。

SLR 和 LR(0)解析器是同一个吗?如果不是,有什么区别?

266

LR (0) 和 SLR (1) 解析器都是自下而上、定向、解析器。这意味着

解析器尝试反向应用产品,以将输入句子减少回起始符号(自下而上

解析器从左到右扫描输入(方向

解析器试图要应用的减少,而不一定要看到所有的输入(predictive

LR(0)和 SLR(1)都是shift / reduce 解析器,这意味着它们可以通过将输入流的令牌放置在堆栈上来处理输入流的令牌,并且在每个点shifting通过将其推入堆栈或减少将堆栈顶部的某些终端和非终端序列应用到某些非确定的终端符号。可以证明任何语法都

当使用确定性的 shift / reduce 解析器来解析它无法处理的语法时,它会导致shift / reduce 冲突reduce / reduce 冲突,在这种情况下,解析器可能会进入无法确定要采取什么操作的状态。在移位 / 减少冲突中,它无法判断是应该在堆栈中添加另一个符号,还是在堆栈的顶部符号上执行某种

我很抱歉,如果这是一个冗长的阐述,但我们需要这能够解决 LR (0) 和 SLR (1) 解析之间的差异。LR (0) 解析器是一个 shift / reduce 解析器,它使用零令牌的 lookahead 来确定要采取什么行动 (因此是 0)。这意味着在解析器的任何配置中,解析器必须有一个明确的动作来选择-如果它移动一个特定的符号或应用一个特定的

回想一下,这两个可能的 LR 冲突是 shift / reduce 和 reduce / reduce。在这两种情况下,LR(0)自动机都可以采取至少两个动作,并且无法确定要使用哪一个动作。由于至少有一个冲突动作是归约,因此合理的攻击路线是尝试让解析器在执行特定归约时更加小心。更具体地说,让我们假设解析器仅在

在 SLR(1)(“简化的 LR(1)”)中,允许解析器在决定是否应该移动或减少时查看一个前瞻令牌。特别是,当解析器想要尝试减少形式 A → w(对于非终端 A 和字符串 w)时,它会查看下一个输入令牌。如果该令牌可以合法地出现在非终端 A 之后,则在某些推导中,解析器会减少即将到来的令牌。否则,它不会。

LR (0) 和 SLR (1) 之间的唯一区别是这种额外的功能可以帮助您在发生冲突时决定采取什么措施。因此,任何可以由 LR (0) 解析器解析的语法都可以由 SLR (1) 解析器解析。但是,SLR (1) 解析器可以解析比 LR (0) 更多的语法。

但实际上,SLR (1) 仍然是一个相当弱的解析方法。更常见的是,你会看到 LALR (1) (“Lookahead LR (1)”) 解析器在 LR (0) 解析器中试图解决冲突,但它们用于解决冲突的规则比 SLR (1) 中使用的规则要精确得多 (1)。

从历史上看,LALR(1)解析器通常是通过一种不同的方法来构建的,该方法依赖于功能更强大的 LR(1)解析器的下一个 reduce / reduce 冲突,因此您经常会看到 LALR(1)以这种方式进行描述。为了理解这一点,我们需要谈论 LR(1)解析器。在 LR(0)解析器中,解析器通过跟踪它可能在生产过程中的位置来工作。

在 LR(1)解析器中,解析器会在运行时跟踪其他信息。除了跟踪解析器认为正在使用的某种语法 LR之外,它还可以跟踪在每个步骤中可能出现的令牌,而不仅仅是在需要做出决定时,LR(1)解析器会比 LR(0)解析器更强大和更精确()。

最近,一种称为 GLR(0)的新解析算法(“Generalized LR(0)”)在 GLR(0)中得到了很好的实践)。GLR(0)解析器不是试图解决 LR(0)解析器中出现的冲突,而是通过并行尝试所有可能的选项来工作。使用一些巧妙的技巧,可以使其对许多语法非常有效地运行。此外,GLR(0)可以解析任何上下文

如果您有兴趣了解更多信息,今年夏天,我教授了一门入门编译器课程,并花了不到两周的时间讨论解析技术。如果您想更严格地介绍 LR(0),SLR(1)和许多其他强大的解析技术,您可能会喜欢我的有关解析的演讲幻灯片和家庭作业。所有课程资料均可用here on my personal site

希望这有帮助!

2

这是我所学到的。通常 LR (0) 解析器可能有歧义,即表格的一个框 (你为创建解析器而派生) 可以有多个值 (或) 来更好地把它:解析器导致两个具有相同输入的最终状态。所以创建 SLR 解析器是为了消除这种歧义。为了构造它找到所有导致 goto 状态的产品,在左手上找到生产符号的跟随不是 goto 状态,并且只包括

1

在 LR (0) 的解析表中,用于生产的减少规则被放置在所有终端的整行中,而在 SLR 解析表中,用于生产的减少规则仅被放置在减少生产的左手侧的非终端的跟随集合中。

称为 parsing-EMU 的工具对解析非常有帮助,可以生成 first,follow,LR(0)itemset,LALR Evaluation 等,您可以找到它here

1

在上述答案的基础上,自底向上解析器类中各个解析器之间的区别在于它们在生成解析表时是否导致移位 / 减少或减少 / 减少冲突。冲突越少,语法就越强大(LR(0)& lt;SLR(1)& lt;LALR(1)& lt;CLR(1))。

例如,考虑以下表达式语法:

E → E + T

E → T

T → F

T → T * F

F → (E)

F → id

它不是 LR(0),而是 SLR(1)。使用以下代码,我们可以构造 LR0 自动机并构建解析表(我们需要增加语法,使用闭包计算 DFA,计算动作和 goto 集):

from copy import deepcopy
import pandas as pd
def update_items(I, C):
    if len(I) == 0:
         return C
    for nt in C:
         Int = I.get(nt, [])
         for r in C.get(nt, []):
              if not r in Int:
                  Int.append(r)
          I[nt] = Int
     return I
def compute_action_goto(I, I0, sym, NTs): 
    #I0 = deepcopy(I0)
    I1 = {}
    for NT in I:
        C = {}
        for r in I[NT]:
            r = r.copy()
            ix = r.index('.')
            #if ix == len(r)-1: # reduce step
            if ix >= len(r)-1 or r[ix+1] != sym:
                continue
            r[ix:ix+2] = r[ix:ix+2][::-1]    # read the next symbol sym
            C = compute_closure(r, I0, NTs)
            cnt = C.get(NT, [])
            if not r in cnt:
                cnt.append(r)
            C[NT] = cnt
        I1 = update_items(I1, C)
    return I1
def construct_LR0_automaton(G, NTs, Ts):
    I0 = get_start_state(G, NTs, Ts)
    I = deepcopy(I0)
    queue = [0]
    states2items = {0: I}
    items2states = {str(to_str(I)):0}
    p_table = {}
    cur = 0
    while len(queue) > 0:
        id = queue.pop(0)
        I = states[id]
        # compute goto set for non-terminals
        for NT in NTs:
            I1 = compute_action_goto(I, I0, NT, NTs) 
            if len(I1) > 0:
                state = str(to_str(I1))
                if not state in statess:
                    cur += 1
                    queue.append(cur)
                    states2items[cur] = I1
                    items2states[state] = cur
                    p_table[id, NT] = cur
                else:
                    p_table[id, NT] = items2states[state]
        # compute actions for terminals similarly
        # ... ... ...
                    
    return states2items, items2states, p_table
        
states, statess, p_table = construct_LR0_automaton(G, NTs, Ts)

其中语法 G,非终端和终端符号定义如下

G = {}
NTs = ['E', 'T', 'F']
Ts = {'+', '*', '(', ')', 'id'}
G['E'] = [['E', '+', 'T'], ['T']]
G['T'] = [['T', '*', 'F'], ['F']]
G['F'] = [['(', 'E', ')'], ['id']]

这里有几个更有用的功能,我与上面的 LR(0)解析表生成一起实现:

def augment(G, S): # start symbol S
    G[S + '1'] = [[S, '$']]
    NTs.append(S + '1')
    return G, NTs
def compute_closure(r, G, NTs):
    S = {}
    queue = [r]
    seen = []
    while len(queue) > 0:
        r = queue.pop(0)
        seen.append(r)
        ix = r.index('.') + 1
        if ix < len(r) and r[ix] in NTs:
            S[r[ix]] = G[r[ix]]
            for rr in G[r[ix]]:
                if not rr in seen:
                    queue.append(rr)
    return S

下图(展开以查看)显示了使用上述代码为语法构造的 LR0 DFA:

enter image description here

下表显示了作为 pandas 数据帧生成的 LR(0)解析表,请注意,有几个 shift / reduce 冲突,表明语法不是 LR(0)。

enter image description here

SLR (1) 解析器避免了上述 shift / reduce 冲突,方法是仅在下一个输入令牌是正在减少的非终端的 Follow Set 的成员时才减少。所以上面的语法不是 LR (0),而是 SLR (1)。的解析表是由 SLR 生成的:

enter image description here

以下动画显示了如何通过上述 SLR (1) 语法分析输入表达式:

enter image description here

但是,的语法接受形式a^ncb^n, n >= 1的字符串是 LR(0):

A → a A b

A → c

S → A

让我们定义语法如下:

# S --> A 
# A --> a A b | c
G = {}
NTs = ['S', 'A']
Ts = {'a', 'b', 'c'}
G['S'] = [['A']]
G['A'] = [['a', 'A', 'b'], ['c']]

enter image description here

从下图可以看出,生成的解析表没有冲突。

![enter image description here

本站系公益性非盈利分享网址,本文来自用户投稿,不代表边看边学立场,如若转载,请注明出处

(121)
华为云学生服务器:Rackspace(云)服务器上的 Apache服务器
上一篇
文件夹上的chmod775 但不是该文件夹下的所有文件
下一篇

相关推荐

发表评论

登录 后才能评论

评论列表(6条)