- 简单算数表达式语法分析器设计
【问题描述】
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")