【避雷】实验课打分离谱,同学一次性LL1语法分析器及参考我博客的同学分数还比我高,狠狠避雷
【编译原理】基于词法分析器的LL1语法分析器
实验要求
设计一个满足以下要求的⽂法:
(1)识别只包含变量声明语句和执行语句程序段的语法结构合法性;
(2)变量声明中只使用int,char,float 3类基本类型;
(3)变量声明中允许初始化,每一个数据类型可以声明多个变量;
(4)执行语句只包括:表达式语句、if语句、while语句;
(5)可以有多条变量声明语句和执行语句;
(6)没有函数声明,所有语句都在同一 个函数体内。
(7)表达式是以=、+、-、*、/、>、<为运算符,常数、变量标识符为操作数,并带圆括号的式子。
对满足以上要求的文法构造其相应分析表(LL或LR);对于给定输⼊符号串,能检查其是否语法正确;若有错,显示出错语句所在行及简单错误信息。
注意:要求以词法分析的结果,即单词表中的编码为输入内容。
评分标准
①分析表是否是自动生成;
②是否能识别多条语句;
③是否能识别声明语句;
④是否能识别执行语句,包括if、while、表达式语句;
⑤每个错误是否有错误提示,包括错误所在行、错误信息;
⑥错误提示信息是否区分不同类别;
源码
grammarAnalysis.py
import re
# 词法分析
class MyToken:
def __init__(self, MyType, seman, MyStr):
self.MyType = MyType
self.seman = seman
self.MyStr = MyStr
def __str__(self):
s = self.MyStr.replace('\n','')
return "token.class: {:5}\t\tstr: {:10}\tseman:\t{} \t".format(self.MyType, s, self.seman)
# 单词集状态列表
states = ['if', 'else', 'for', 'while', 'break', 'return', 'continue', 'float', 'int', 'char', '标识符',
'正整数、正实数、零', '+', '-',
'*', '/', '%', '>', '>=', '<', '<=', '!=', '==', '!', '&', '|', ',', '=', '[', ']', '(', ')', '{', '}', ';',
'.', '\\', '#']
choiceStatec = [13, 14, 15, 16, 17, 18, 20, 24, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36] # 用于防止while循环中出现多次elif
inputs = [] # 输入的字符
tokens = [] # 单词表
NameL = [] # 名字表
ConstL = [] # 常数表
i = 0
line = 1
# 将文件内容提取到inputs
def codeToInputs(sourceCodes):
for line in sourceCodes:
for char in line:
inputs.append(char)
if char == '#':
return
# 判断是否为字母
def isLetter(char):
pattern = r"[a-zA-Z]"
return bool(re.match(pattern, char))
# 判断是否为数字
def isDigit(char):
pattern = r"[0-9]"
return bool(re.match(pattern, char))
# 普通的字符识别
def isC(char, state):
tokens.append(MyToken(state, "^", char))
def choiceState(char): # 选择单字符对应状态
state = 0
if char in states:
for k in range(len(states)):
if states[k] == char: # 判断单个字符
if char in ['>', '<', '!', '=', '&', '|', '\\'] and inputs[i] in ['=', '&', '|', 'n']: # 如果是双字符
state = 19
else:
state = k + 1
else:
state = 0
return state
def error():
print(f"第{
line}行---未知字符错误")
exit(0)
# 词法分析
def nextToken():
global i
global line
name = ""
char = inputs[i]
i += 1
while char == ' ' or char == '\n' or char == '\t': # 如果是空就跳过
if char == '\n':
line += 1
char = inputs[i]
i += 1
if char == '#':
i -= 1
global state
state = 0
while True:
if state == 0: # 选择
if char == '#':
i -= 1
state = 38
continue
if char == '/' and (inputs[i] == '/' or inputs[i] == '*'): # 注释
state = 42
continue
if choiceState(char) != 0: # 判断后面的单字符,获取状态
state = choiceState(char)
i -= 1
continue
if char == "i":
state = 1
elif char == "e":
state = 2
elif char == 'f':
state = 3
elif char == 'w':
state = 4
elif char == 'b':
state = 5
elif char == 'r':
state = 6
elif char == 'c':
state = 7
elif isDigit(char): # 数字
state = 12
elif isLetter(char): # 字符串
i -= 1
state = 11
else:
error() # 非法字符报错
i -= 1
state = 38
elif state == 1: # if
if inputs[i] == 'f': # 判断第二个是否为f
if isDigit(inputs[i + 1]) or isLetter(inputs[i + 1]): # 标识符
i -= 1
state = 11
else:
m = MyToken(1, "^", "if") # 在单词表和名字表加入
tokens.append(m)
state = 38
elif inputs[i] == 'n': # 判断第二个是否为n
i += 1
if inputs[i] == 't':
if isDigit(inputs[i + 1]) or isLetter(inputs[i + 1]): # 标识符
i -= 2
state = 11
else:
m = MyToken(9, "^", "int") # 在单词表和名字表加入
tokens.append(m)
state = 38
else:
if isDigit(inputs[i]) or isLetter(inputs[i]): # 标识符
i -= 2
state = 11
else:
m = MyToken(11, "^", "in") # 在单词表和名字表加入
tokens.append(m)
state = 38
i -= 1
else: # 以i开头的标识符
i -= 1
state = 11
elif state == 2: # else
if ''.join(inputs[i:i + 3]) == 'lse':
if isDigit(inputs[i + 3]) or isLetter(inputs[i + 3]):
i -= 1
state = 11
else:
m = MyToken(2, "^", "else") # 在单词表和名字表加入
tokens.append(m)
state = 38
i += 2