《编译原理》简单算数表达式语法分析器设计

  1. 简单算数表达式语法分析器设计

【问题描述】

1.设计一个表达式语法分析器,要求表达式支持任意标识符和常数;

2.编写代码并上机调试运行通过。

【输入形式】

简单算数表达式

【输出形式】

正确/错误

【样例输入】

xx+y10*(33*a+0.7)-b/523e-2
xx+y10*(33*a+0.7)-b*/523e-2

【样例输出】

True
False

import re

# Token types
class TokenType:
    ID, NUM, FLOAT, SCIENTIFIC, PLUS, MINUS, MUL, DIV, LPAREN, RPAREN, END, INVALID, NONTERM_E, NONTERM_T, NONTERM_F = range(15)

# Token class
class Token:
    def __init__(self, type_, lexeme):
        self.type = type_
        self.lexeme = lexeme

# LR(1) parsing table
lr1_table = {
    (0, TokenType.ID): ('S', 5), (0, TokenType.NUM): ('S', 6), (0, TokenType.FLOAT): ('S', 17), (0, TokenType.SCIENTIFIC): ('S', 18), (0, TokenType.LPAREN): ('S', 4),
    (0, TokenType.NONTERM_E): ('G', 1), (0, TokenType.NONTERM_T): ('G', 2), (0, TokenType.NONTERM_F): ('G', 3),
    (1, TokenType.PLUS): ('S', 7), (1, TokenType.MINUS): ('S', 8), (1, TokenType.END): ('A', -1),
    (2, TokenType.PLUS): ('R', 3), (2, TokenType.MINUS): ('R', 3), (2, TokenType.MUL): ('S', 9), (2, TokenType.DIV): ('S', 10), (2, TokenType.RPAREN): ('R', 3), (2, TokenType.END): ('R', 3),
    (3, TokenType.PLUS): ('R', 6), (3, TokenType.MINUS): ('R', 6), (3, TokenType.MUL): ('R', 6), (3, TokenType.DIV): ('R', 6), (3, TokenType.RPAREN): ('R', 6), (3, TokenType.END): ('R', 6),
    (4, TokenType.ID): ('S', 5), (4, TokenType.NUM): ('S', 6), (4, TokenType.FLOAT): ('S', 17), (4, TokenType.SCIENTIFIC): ('S', 18), (4, TokenType.LPAREN): ('S', 4),
    (4, TokenType.NONTERM_E): ('G', 11), (4, TokenType.NONTERM_T): ('G', 2), (4, TokenType.NONTERM_F): ('G', 3),
    (5, TokenType.PLUS): ('R', 8), (5, TokenType.MINUS): ('R', 8), (5, TokenType.MUL): ('R', 8), (5, TokenType.DIV): ('R', 8), (5, TokenType.RPAREN): ('R', 8), (5, TokenType.END): ('R', 8),
    (6, TokenType.PLUS): ('R', 9), (6, TokenType.MINUS): ('R', 9), (6, TokenType.MUL): ('R', 9), (6, TokenType.DIV): ('R', 9), (6, TokenType.RPAREN): ('R', 9), (6, TokenType.END): ('R', 9),
    (7, TokenType.ID): ('S', 5), (7, TokenType.NUM): ('S', 6), (7, TokenType.FLOAT): ('S', 17), (7, TokenType.SCIENTIFIC): ('S', 18), (7, TokenType.LPAREN): ('S', 4),
    (7, TokenType.NONTERM_T): ('G', 12), (7, TokenType.NONTERM_F): ('G', 3),
    (8, TokenType.ID): ('S', 5), (8, TokenType.NUM): ('S', 6), (8, TokenType.FLOAT): ('S', 17), (8, TokenType.SCIENTIFIC): ('S', 18), (8, TokenType.LPAREN): ('S', 4),
    (8, TokenType.NONTERM_T): ('G', 13), (8, TokenType.NONTERM_F): ('G', 3),
    (9, TokenType.ID): ('S', 5), (9, TokenType.NUM): ('S', 6), (9, TokenType.FLOAT): ('S', 17), (9, TokenType.SCIENTIFIC): ('S', 18), (9, TokenType.LPAREN): ('S', 4),
    (9, TokenType.NONTERM_F): ('G', 14),
    (10, TokenType.ID): ('S', 5), (10, TokenType.NUM): ('S', 6), (10, TokenType.FLOAT): ('S', 17), (10, TokenType.SCIENTIFIC): ('S', 18), (10, TokenType.LPAREN): ('S', 4),
    (10, TokenType.NONTERM_F): ('G', 15),
    (11, TokenType.PLUS): ('S', 7), (11, TokenType.MINUS): ('S', 8), (11, TokenType.RPAREN): ('S', 16),
    (12, TokenType.PLUS): ('R', 1), (12, TokenType.MINUS): ('R', 1), (12, TokenType.MUL): ('S', 9), (12, TokenType.DIV): ('S', 10), (12, TokenType.RPAREN): ('R', 1), (12, TokenType.END): ('R', 1),
    (13, TokenType.PLUS): ('R', 2), (13, TokenType.MINUS): ('R', 2), (13, TokenType.MUL): ('S', 9), (13, TokenType.DIV): ('S', 10), (13, TokenType.RPAREN): ('R', 2), (13, TokenType.END): ('R', 2),
    (14, TokenType.PLUS): ('R', 4), (14, TokenType.MINUS): ('R', 4), (14, TokenType.MUL): ('R', 4), (14, TokenType.DIV): ('R', 4), (14, TokenType.RPAREN): ('R', 4), (14, TokenType.END): ('R', 4),
    (15, TokenType.PLUS): ('R', 5), (15, TokenType.MINUS): ('R', 5), (15, TokenType.MUL): ('R', 5), (15, TokenType.DIV): ('R', 5), (15, TokenType.RPAREN): ('R', 5), (15, TokenType.END): ('R', 5),
    (16, TokenType.PLUS): ('R', 7), (16, TokenType.MINUS): ('R', 7), (16, TokenType.MUL): ('R', 7), (16, TokenType.DIV): ('R', 7), (16, TokenType.RPAREN): ('R', 7), (16, TokenType.END): ('R', 7),
    (17, TokenType.PLUS): ('R', 10), (17, TokenType.MINUS): ('R', 10), (17, TokenType.MUL): ('R', 10), (17, TokenType.DIV): ('R', 10), (17, TokenType.RPAREN): ('R', 10), (17, TokenType.END): ('R', 10),
    (18, TokenType.PLUS): ('R', 11), (18, TokenType.MINUS): ('R', 11), (18, TokenType.MUL): ('R', 11), (18, TokenType.DIV): ('R', 11), (18, TokenType.RPAREN): ('R', 11), (18, TokenType.END): ('R', 11),
}

# Reduce rules
reduce_rules = {
    1: (3, TokenType.NONTERM_E),  # E -> E + T
    2: (3, TokenType.NONTERM_E),  # E -> E - T
    3: (1, TokenType.NONTERM_E),  # E -> T
    4: (3, TokenType.NONTERM_T),  # T -> T * F
    5: (3, TokenType.NONTERM_T),  # T -> T / F
    6: (1, TokenType.NONTERM_T),  # T -> F
    7: (3, TokenType.NONTERM_F),  # F -> ( E )
    8: (1, TokenType.NONTERM_F),  # F -> id
    9: (1, TokenType.NONTERM_F),  # F -> num
    10: (1, TokenType.NONTERM_F), # F -> float
    11: (1, TokenType.NONTERM_F)  # F -> scientific
}

# Lexical analysis
def get_next_token(input_str):
    token_specification = [
        ('ID',          r'[a-zA-Z][a-zA-Z0-9]*'),
        ('FLOAT',       r'\d+\.\d+([eE][-+]?\d+)?'),
        ('SCIENTIFIC',  r'\d+([eE][-+]?\d+)'),
        ('NUM',         r'\d+'),
        ('PLUS',        r'\+'),
        ('MINUS',       r'-'),
        ('MUL',         r'\*'),
        ('DIV',         r'/'),
        ('LPAREN',      r'\('),
        ('RPAREN',      r'\)'),
        ('SKIP',        r'[ \t\n]+'),
        ('INVALID',     r'.')
    ]
    tok_regex = '|'.join('(?P<%s>%s)' % pair for pair in token_specification)
    for mo in re.finditer(tok_regex, input_str):
        kind = mo.lastgroup
        value = mo.group()
        if kind == 'ID':
            yield Token(TokenType.ID, value)
        elif kind == 'FLOAT':
            yield Token(TokenType.FLOAT, value)
        elif kind == 'SCIENTIFIC':
            yield Token(TokenType.SCIENTIFIC, value)
        elif kind == 'NUM':
            yield Token(TokenType.NUM, value)
        elif kind == 'PLUS':
            yield Token(TokenType.PLUS, value)
        elif kind == 'MINUS':
            yield Token(TokenType.MINUS, value)
        elif kind == 'MUL':
            yield Token(TokenType.MUL, value)
        elif kind == 'DIV':
            yield Token(TokenType.DIV, value)
        elif kind == 'LPAREN':
            yield Token(TokenType.LPAREN, value)
        elif kind == 'RPAREN':
            yield Token(TokenType.RPAREN, value)
        elif kind == 'SKIP':
            continue
        else:
            yield Token(TokenType.INVALID, value)
    yield Token(TokenType.END, '')

# Parsing function
def parse(input_str):
    tokens = get_next_token(input_str)
    stack = [0]
    symbol_stack = []
    current_token = next(tokens)

    while True:
        current_state = stack[-1]
        action = lr1_table.get((current_state, current_token.type))

        if action is None:
            return False

        act, next_state = action
        if act == 'S':
            stack.append(next_state)
            symbol_stack.append(current_token.type)
            current_token = next(tokens)
        elif act == 'R':
            rule_num = next_state
            pop_count, non_terminal = reduce_rules[rule_num]
            for _ in range(pop_count):
                stack.pop()
                symbol_stack.pop()
            stack.append(lr1_table.get((stack[-1], non_terminal))[1])
            symbol_stack.append(non_terminal)
        elif act == 'A':
            return True

# Main function
if __name__ == "__main__":
    input_str = input().strip()
    if parse(input_str):
        print("True")
    else:
        print("False")

  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
毕业论文引言 随着计算机技术的发展与普及,计算机已经成为各行业最基本的工具之一,迅速进入千家万户。因此,掌握计算机应用的基本技能成为新世纪人才不可缺少的基本素质之一。为使计算机能正常工作, 除了构成计算机各个组成部分的物理设备外, 一般说来, 还必须要有指挥计算机“做什么”和“如何做”的“程序”。程序及其有关文档构成计算机软件, 其中用以书写计算机软件的语言称为计算机程序设计语言。 1 计算机程序设计语言简介 计算机程序设计语言是计算机可以识别的语言,用于描述解决问题的方法,供计算机阅读和执行,通常简称为编程语言,是一组用来定义计算机程序的语法规则。它是一种被标准化的交流技巧,用来向计算机发出指令。一种计算机语言让程序员能够准确地定义计算机所需要使用的数据,并精确地定义在不同情况下所应当采取的行动。使用程序设计语言往往使程序员能够比使用机器语言更准确地表达他们所想表达的目的。对那些从事计算机科学的人来说,懂得程序设计语言是十分重要的,因为所有的程序都需要程序设计语言才能完成,而计算机的工作是用程序来控制的,离开了程序,计算机将一事无成。 2 开发背景及意义 现有计算器不能计算表达式,这是一个缺陷,为此,开发了一个能直接计算表达式的计算器,这为计算提高了更大的方便,可以大幅度提高计算效率。 第二章 第三章 第一节 递归下降法的描述 3.1.1实现思想 它的主要原理是,对每个非终极符按其产生式结构构造相应语法分析子程序,其中终极符产生匹配命令,而非终极符则产生过程调用命令。因为文法递归相应子程序也递归,所以称这种方法为递归子程序下降法或递归下降法。其中子程序的结构与产生式结构几乎是一致的。文法中每个非终结符对应一个递归过程(子程序),每个过程的功能是识别由该非终结符推出的串,当某非终结符的产生式有多个候选式时能够按LL(1)形式可唯一地确定选择某个候选式进行推导。 3.1.2算法的特点 递归下降法是语法分析中最易懂的一种方法。递归下降法要满足的条件:假设A的全部产生式为Aα1|α2|……|αn ,则必须满足如下条件才能保证可以唯一的选择合适的产生式 predict(Aαi)∩predict(Aαj)=Φ,当i≠j. 3.1.3构造递归下降语法分析程序 采用了递归子程序方法进行语法分析,对文法中的每个非终极符号按其产生式结构产生相应的语法分析子程序,完成相应的识别任务。其中终结符产生匹配命令,非终结符则产生调用命令。每次进入子程序之前都预先读入一个单词。因为使用了递归下降方法,所以程序结构和层次清晰明了,易于手工实现,且时空效率较高。实际的语法分析工作,从调用总程序的分析子程序开始,根据产生式进行递归调用各个分析子程序。 第二节
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值