算符优先分析+属性文法 简单计算器的实现

写在前面

这是本人编译原理的课程作业,仅提供参考作用,不建议直接拷贝作为作业进行提交,如果文章或者代码中出现错误,欢迎指正

参考文章

编译原理——算符优先语法分析

构造简单的算符优先文法

G(E)
E-> E+T|E-T|T
T-> T*F|T/F|F
F-> (E)|i

因为使用规约的方式,所以不用考虑左递归产生的影响

实现步骤

  1. 计算出各个非终结符的FIRSTVT和LASTVT
  2. 根据FIRSTVT和LASTVT构造优先关系表
  3. 根据优先关系表进行移进归约

计算各个非终结符的FIRSTVT和LASTVT集合

FIRSTVT

如果存在文法 A->aB... 或者 A->Ba... 则 a ∈ FIRSTVT(A)
如果存在文法 A->B... 则FIRSTVT(B) ∈ FIRSTVT(A)
所以文法中G(E)中的所有非终结符的FIRSTVT为

FIRSTVT(E) = {+,-,*,/,(,i}
FIRSTVT(T) = {*,/,(,i}
FIRSTVT(F) = {(,i}

LASTVT

如果存在文法 A->...aB 或者 A->...a 则 a ∈ LASTVT(A)
如果存在文法 a ∈ LASTVT(B) 且 A->...B 则 a ∈ LASTVT(A)
所以文法中G(E)中的所有非终结符的LASTVT为

LASTVT(E) = {+,-,*,/,),i}
LASTVT(T) = {*,/,),i}
LASTVT(F) = {),i}

根据FIRSTVT和LASTVT构造优先关系表

+ - * / ( ) i #
+
-
*
/
(
)
i
#

根据算符优先文法的规则构建算符优先文法的代码,就是判断什么时候规约,什么时候移进

注!!!算符优先文法的规约只判断终结符,跳过非终结符进行比较

截屏20200701 08.49.24.png
这里算符优先文法的实现依赖于词法分析的实现,所以这里先贴上词法分析的代码

文件名:lab1.py

'''
@Author: wentaoStudy
@Date: 2020-05-13 10:44:03
@LastEditTime: 2020-06-30 17:57:24
@LastEditors: wentaoStudy
@Email: 2335844083@qq.com
'''

class NormalFunctions:
    def __init__(self , strInput):
        self.ch = ''
        self.strToken = ""
        self.strInput = strInput
        self.index = 0
        # self.reserve = ["const", "var", "procedure", "call", "begin", "end", "if", "then", "while", "do", "odd", ".", ",", "=", ";", ":=", "#", "<", ">", "+", "-", "*", "/", "(", ")"]
        self.word_reserve = ["begin" , "end" , "if" , "then" , "while" , "do" , "const" , "var" , "call" , "procedure"]
        self.compute_reserve = ["+" , "-" , "*" , "/" , "odd" , "=" , "<>" , "<" , ">" , "<=" , ">=" , ":=" ]
        self.boder_reserve = ["(" , ")" , "," , "." , ";"]
        self.Id = []
        self.Const = []

    def GetChar(self):
        if self.index < len(self.strInput):
            self.ch = self.strInput[self.index]
            self.index += 1
        else: 
            self.ch = ''
            self.index += 1
    
    def GetBC(self):
        while(self.ch == " "):
            self.GetChar()
    
    def Concat(self):
        self.strToken += self.ch

    def IsLetter(self):
        Char = self.ch
        if((Char>='a' and Char<='z') or( Char>='A' and Char<='Z')):
            return True
        else:
            return False

    def IsDigit(self):
        try:
            int(self.ch)
            return True
        except:
            return False

    def Reserve(self):
        try:
            index = self.reserve.index(self.strToken)
            return index + 1
        except:
            return 0
    
    def Word_Reserve(self):
        try:
            index = self.word_reserve.index(self.strToken)
            return index + 1
        except:
            return 0

    def Compute_Reserve(self):
        try:
            index = self.compute_reserve.index(self.strToken)
            return index + 1
        except:
            return 0

    def Boder_Reserve(self):
        try:
            index = self.boder_reserve.index(self.strToken)
            return index + 1
        except:
            return 0

    def Retract(self):
        # if self.index > 0 and self.index < len(self.strInput):
        if self.index > 0:
            self.index -= 1
    
    def InsertId(self):
        self.Id.append(self.strToken)
        return len(self.Id)

    def InsertConst(self):
        self.Concat.append(self.strToken)
        return len(self.Id)

    #实现类内自己编译
    def Self_Compile(self):
        while(self.index < len(self.strInput)):
            self.Compile_Str()
            self.strToken = ""
    
    def Compile_Str(self):
        self.GetChar()
        self.GetBC()
        if(self.IsLetter()):
            while((self.IsLetter() or self.IsDigit()) ):
                self.Concat() 
                self.GetChar()
            self.Retract()
            # self.Retract()
            word_code = self.Word_Reserve()
            compute_code = self.Compute_Reserve()
            if word_code == 0 and compute_code == 0:
                value = self.InsertId()
                print("< 标识符" , self.strToken , "-"  ">")
            else :
                if word_code > 0 :
                    print("< 保留字" , self.strToken , word_code , ">")
                if compute_code > 0:
                    print("< 算符" , self.strToken , compute_code , ">")
        elif(self.IsDigit()):
            while(self.IsDigit()):
                self.Concat() 
                self.GetChar()
            self.Retract()
            # self.Retract()
            value = self.InsertId()
            print("< 常数"  ,self.strToken , value ,  ">")
        else:
            #这里描述界符和运算符
            self.Concat()
            compute_code = self.Compute_Reserve()
            boder_code = self.Boder_Reserve()
            if compute_code == 0 and boder_code == 0: 
                self.GetChar()
                self.Concat()
                if self.Compute_Reserve() > 0:
                    print("< 算符" , self.strToken , self.Compute_Reserve() , ">")
                else:
                    self.Retract()
                    #异常处理
                    pass
            elif boder_code > 0:
                print("< 界符" , self.strToken , self.Boder_Reserve() , ">")
            elif compute_code > 0:
                if compute_code > 6:
                    self.GetChar()
                    self.Concat()
                    if self.Compute_Reserve() > 0:
                        print("< 算符" , self.strToken , self.Compute_Reserve() , ">")
                    else:
                        self.Retract()
                        #异常处理
                        pass
                else:
                    print("< 算符" , self.strToken , self.Compute_Reserve() , ">")
            else:
                self.Retract()
                #异常处理
                pass

#进行测试的代码
#strInput = "1*i+1 )("
#func = NormalFunctions(strInput)
#func.Self_Compile()

算符优先文法+属性文法实现简单的4则计算器

文件名:lab3.py

'''
@Author: wentaoStudy
@Date: 2020-06-29 08:47:51
@LastEditTime: 2020-06-30 18:07:25
@LastEditors: wentaoStudy
@Email: 2335844083@qq.com
'''
from lab1 import NormalFunctions

PRT = [
    ['>','>','<','<','<','>','<','>'],
    ['>','>','<','<','<','>','<','>'],
    ['>','>','>','>','<','>','<','>'],
    ['>','>','>','>','<','>','<','>'],
    ['<','<','<','<','<','=','<',' '],
    ['>','>','>','>',' ','>',' ','>'],
    ['>','>','>','>',' ','>',' ','>'],
    ['<','<','<','<','<',' ','>','=']
]

Terminators = ['+','-','*','/','(',')','i','#']

# G(E)
# E-> E+T|E-T|T
# T-> T*F|T/F|F
# F-> (E)|i

rules = {
    "N":["N+N" , "N-N" , "N*N" , "N/N" , "(N)" , "i"]
}

from enum import Enum
class proprity_type(Enum):
    ntm = 1
    tm = 2

class property():
    def __init__(self , i_type , i_name , i_val):
        self.i_type = i_type
        self.i_name = i_name
        self.i_val = i_val
    

NTM = ["N"] 
TM = ["(" , ")" , "+" , "-" , "*" , "/" , "i"]

class move_into_reduction_proprity():

    def if_number(self , str):
        rt = False
        try:
            int(str)
            rt = True
        except:
            rt = False
        return rt

    def tindex(self , char):
        return Terminators.index(char)

    def __init__(self , input_str):
        self.input_list = []

        #调用词法分析
        self.nf = NormalFunctions(input_str)
        while(self.nf.index < len(self.nf.strInput)):
            self.nf.Compile_Str()
            self.input_list.append(self.nf.strToken)
            self.nf.strToken = ""
        
        print(self.input_list)
        
        self.reduction_stack = []
        self.proprity_stack = []
        self.proprity_stack.append(property(proprity_type.tm , "#" , "#"))
        for i in self.input_list:
            if i in NTM:
                self.proprity_stack.append(property(proprity_type.ntm , i , 0))  
            elif self.if_number(i):
                self.proprity_stack.append(property(proprity_type.tm , "i" , int(i))) 
            elif i in TM:
                self.proprity_stack.append(property(proprity_type.tm , i , i))
            else:
                print("类型错误")
        self.proprity_stack.append(property(proprity_type.tm , "#" , "#"))
        self.input_list = self.proprity_stack[1:]
        self.reduction_stack = []
        self.reduction_stack.append((self.proprity_stack[0]))
                
    def move_into(self):
        if len(self.input_list )!= 0:
            self.reduction_stack.append(self.input_list[0])
            self.input_list.pop(0)
    
    def self_reduction(self , left ,  right):
        tempstr = ""
        for i in range(left , right+1):
            tempstr += self.reduction_stack[i].i_name
        temp_val = 0
        if tempstr == "i":
            temp_val = int(self.reduction_stack[left].i_val)
        elif tempstr == "N+N":
            val1 = self.reduction_stack[left].i_val
            val2 = self.reduction_stack[left+2].i_val
            temp_val = val1 + val2
        elif tempstr == "N-N":
            val1 = self.reduction_stack[left].i_val
            val2 = self.reduction_stack[left+2].i_val
            temp_val = val1 - val2
        elif tempstr == "N*N":
            val1 = self.reduction_stack[left].i_val
            val2 = self.reduction_stack[left+2].i_val
            temp_val = val1 * val2
        elif tempstr == "N/N":
            val1 = self.reduction_stack[left].i_val
            val2 = self.reduction_stack[left+2].i_val
            temp_val = val1 / val2
        elif tempstr == "(N)":
            temp_val = self.reduction_stack[left+1].i_val
        print(tempstr + " -> N")
        for i in range(left , right+1).__reversed__():
            self.reduction_stack.pop(i)
        self.reduction_stack.append(property(proprity_type.ntm , "N" , temp_val))

    def judge_can_reduction(self , left , right):
        tempstr = ""
        for i in range(left , right+1):
            tempstr += self.reduction_stack[i].i_name
        if tempstr in rules["N"]:
            return True
        else:
            return False

    def lmp_d(self):
        l = 0 
        r = 0
        lr_list = ["#"]
        lasti = 0
        for i , value in enumerate(self.reduction_stack):
            if value.i_name in TM:
                lr_list.append(value.i_name)
                row = self.tindex(lr_list[len(lr_list) - 2])
                col = self.tindex(lr_list[len(lr_list) - 1])
                if PRT[row][col] == "<":
                    l = lasti 
                elif PRT[row][col] == ">":
                    r = i - 1
                lasti = i
        if self.input_list[0].i_name in Terminators:
            row = self.tindex(lr_list[len(lr_list) - 1])
            col = self.tindex(self.input_list[0].i_name)
            if PRT[row][col] == ">":
                r = len(self.reduction_stack) - 1
        if r > 0:
            if self.judge_can_reduction(l+1 , r):
                self.self_reduction(l+1 , r)
                self.lmp_d()
            else:
                print("不可归约")

    def statue(self):
        while(len(self.input_list) != 0):
            if(self.input_list[0].i_name == "#"):
                print("归约结束")
                break
            self.move_into()
            self.lmp_d()
        for i in self.reduction_stack:
            print(i.i_name , i.i_val)
        if len(self.reduction_stack) != 2:
            print("归约错误")
        # print(self.reduction_stack)
mir = move_into_reduction_proprity("(3*(1+2)*100)")
mir.statue()

运行结果
截屏20200630 00.07.09.png

posted @ 2020-07-16 16:35  wentaoStudy  阅读(419)  评论(0)    收藏  举报