📜  SLR 1解析(1)

📅  最后修改于: 2023-12-03 15:20:09.744000             🧑  作者: Mango

SLR(1)解析

什么是SLR(1)解析

SLR(1)是一种自底向上的语法分析方法,它是 LR(0) 的扩展,具有较强的处理能力和比较高的自动分析效率。SLR(1)的全称是 Simple LR(1),解析器产生状态图,自底向上匹配单词和生产式。若能成功地在最终状态中匹配和识别整个程序,就认为程序语法正确。如果有语法错误则解析将失败。

SLR(1)解析的运作流程

SLR(1)解析的主要运作流程包括以下四个步骤:

  • 分析表的构建(构造DFA)
  • 词法分析
  • 语法分析
  • 语法错误处理
分析表的构建

分析表的构建包括以下几步:

  1. 将文法转换为LR(0)文法
  2. 构造LR(0)分析表
  3. 对于每个状态i,扩展每个非终结符的Follow集,获得增广符的Follow集
  4. 根据增广符的Follow集修改LR(0)分析表,得到SLR分析表
词法分析

在词法分析中,将输入字符串分解成单词,输出相应的符号,编写一个管理输入字符串符号序列的分析器。

语法分析

在语法分析中,根据SLR分析表,按照当前状态和下一个输入单词进行规约或移进操作,以确定下一个状态。每次操作后,更新状态,并调整输入符号序列,直到匹配整个输入符号串。如果分析失败,则会报告语法错误。

语法错误处理

在语法错误处理中,需要根据错误的位置和错误类型进行处理,报告错误并尝试恢复同步。常见的错误处理方法包括丢弃或插入一些单词,跳过到下一个语法符号,或者直接停止解析。

示例代码

下面是一个使用SLR(1)解析进行语法分析的示例代码,例如识别简单的赋值语句:

# 所有终结符
TERMINALS = {'ID', 'NUM', '=', '+'}

# 所有文法产生式
PRODUCTIONS = {
    'E': {'E + T', 'T'},
    'T': {'T * F', 'F'},
    'F': {'( E )', 'ID', 'NUM'},
    'S': {'ID = E'}
}

# 词法分析
def lexer(expression):
    tokens = re.findall('[A-Za-z]+\\d*|[0-9]+|[=+()]', expression)
    return [(t, t) if t in TERMINALS else ('ID', t) for t in tokens]

# 构造文法产生式的闭包
def closure(i, productions):
    items = productions.items()
    closures = {i}
    while True:
        new_items = set()
        for lhs, rhss in items:
            for rhs in rhss:
                for j, t in enumerate(rhs):
                    if (j, t) == (0, lhs):
                        new_items |= {(lhs, rhs[1:])}
                if rhs and rhs[0] == i:
                    new_items |= {(lhs, rhs[1:])}
        if not new_items - closures:
            break
        closures |= new_items
    return frozenset(closures)

# 在两种状态间的转换
def goto(closures, symbol):
    new = set()
    for lhs, rhs in closures:
        if rhs and rhs[0] == symbol:
            new |= {(lhs, rhs[1:])}
    return closure(frozenset(new))

# 构造SLR分析表
def parse_table(terminals, productions):
    states = []
    i = closure({('S_', ('S',))}, productions)
    state_map = {i: 0}
    states.append(i)
    i = 0
    while i < len(states):
        state = states[i]
        i += 1
        for terminal in terminals:
            closure_ = goto(state, terminal)
            if closure_:
                if closure_ not in state_map:
                    states.append(closure_)
                    state_map[closure_] = len(states) - 1
                print('ACTION[%d, %s] = S%d' % (state_map[state], terminal, state_map[closure_]))
            for lhs, rhs in closure_:
                if not rhs:
                    print('ACTION[%d, %s] = R%s' % (state_map[state], lhs, lhs))

# 测试赋值语句的语法分析
def test():
    expression = 'a = b + 300 * 1'
    productions = {}
    for k, v in PRODUCTIONS.items():
        lhs, *rhs = k if k != 'S' else 'S_', *v
        for t in rhs:
            productions.setdefault((lhs, t), []).append((lhs, tuple(t.split())))
    terminals = set(productions.keys()) - set(PRODUCTIONS.keys())
    parse_table(terminals, productions)
    tokens = lexer(expression + '$')
    print(tokens)
    i = 0
    symbol_seq = [t[0] for t in tokens]
    state_seq = [0]
    stack = [None]
    reductions = 0
    while True:
        current_state, symbol = state_seq[-1], symbol_seq[i]
        if (current_state, symbol) not in parse_table:
            print('Syntax error')
            break
        action = parse_table[(current_state, symbol)]
        if action[0] == 'S':
            i += 1
            state_seq.append(action[1])
            stack.append(symbol)
        elif action[0] == 'R':
            lhs, rhs = action[1], productions[action][0][1]
            stack_tokens = stack[-len(rhs):]
            if stack_tokens != list(rhs):
                print('Syntax error')
                break
            stack = stack[:-len(rhs)]
            state_seq = state_seq[:-len(rhs)]
            symbol = lhs
            stack.append(symbol)
            state = state_seq[-1]
            print('ACTION[%d, %s]->R%s' % (state, symbol, lhs))
            reductions += 1
        elif action == ('accept',):
            print('Expression is syntactically correct')
            break
    print(reductions)

if __name__ == '__main__':
    test()

以上是一个使用Python编写的 SLR(1)解析示例代码,实现了从开始构建分析表到语法分析全过程的演示,以及对错误分析和处理的说明。