• 一个简单的语义分析算法:单步算法——Python实现


      以前 曾经有一个人教会我一件事

      要学会相信一些看似不可能的事

     当你真的相信的时候

     或许 没有什么事情是不可能的

    ——《秦时明月•与子同归》

      在编译原理的众多书籍中,陈述了很多生成语法树的经典算法,它们大多是基于递归的方式进行工作的。在本文中,将与大家分享一种基于迭代方式的、易于理解的语法树生成算法,由于其一次成功迭代仅生成一个语法“树枝”的处理特点,可称之为单步算法。

      我们将通过对中缀表达式的语法树生成实验进行算法细节的初步阐述与验证。

      第一阶段:简单模型

      我们第一阶段的中缀表达式语法规定如下:

    expr   ->  expr addop term | term
    addop  ->  + | -
    term   ->  term mulop factor | factor
    mulop  ->  * | / | %
    factor ->  var | num | function

      该语法的等价描述:

    运算符优先级:(从高到低)
    ——————————————————————————
    * / % 二元操作符 - + 二元操作符 —————————————————————————— 参与运算的可以是:
    —————————————————————————— num:常数 var:变量 function:函数
    expr:表达式
    ——————————————————————————

      对于这种简单的中缀表达式,我们的算法处理过程如下:(先大概看一遍处理过程,不要阻塞在这儿)

    #例子1:
    90-565*235/31+6756+45/312-321%12 90-A/31+6756+45/312-321%12 90-A+6756+45/312-321%12 A+6756+45/312-321%12 A+45/312-321%12 A+A-321%12 A-321%12 A-A A

       为了接下来讨论方便,我们做一些类似正则表达式的符号约定:

    # ^ 行首锚定
    # $ 行尾锚定
    # ... 与正则的(.*)意义相同,表示任意多字符
    # A 参与运算的单位 可以是num、var、function或者expr
    # 下面便是我们算法的合并规则
    ^A-A$ ^A-A+...
    ^A-A-... ^A+A$ ^A+A-...
    ^A+A+... ...A*A... ...A/A... ...A%A...

      算法处理过程:

      下面我们故意给中缀表达式加入一语法错误,看一看处理过程:

      如果语法正确,是不可能上图情况的,所以,如果出现上图情况,可断定所给中缀表达式中有语法错误出现。

      下面我们给出此算法的Python实现代码:

     1 # 数据结构
     2 """
     3 list structure :
     4 - + * / % ( ) @var @num @expr @func
     5 
     6 ["-",None]
     7 ["+",None]
     8 ["*",None]
     9 ["/",None]
    10 ["%",None]
    11 ["(",None]
    12 [")",None]
    13 ["@var","varName"]
    14 ["@num","num_string"]
    15 ["@expr","-"|"+"|"*"|"/"|"%",listPtr,...]
    16 ["@func","funcName",listPtr1,...]
    17 
    18 """
    19 
    20 ''' 31 + 8 * 9 '''
    21 listToParse=[ ['@num','31'] , ['+',None] , ['@num','8'] , ['*',None] , ['@num','9'] ]

      运算符'-'规则:

     1 ########### return value :
     2 ############# 0  parsed some expresions
     3 ############# 1  done nothing but no errors happene
     4 def module_minus(lis,i):
     5 
     6     # left i right are both indexes :)    
     7     left=i-1
     8     right=i+1
     9 
    10     # process: ^A-A$
    11     if i==1 and len(lis)==3:
    12         if lis[left][0]=="@var"  or lis[left][0]=="@num" or 
    13            lis[left][0]=="@expr" or lis[left][0]=="@func" :
    14             if lis[right][0]=="@var"  or lis[right][0]=="@num" or 
    15                lis[right][0]=="@expr" or lis[right][0]=="@func" :
    16                 leftPtr=lis[left]
    17                 rightPtr=lis[right]
    18                 del lis[left:left+3]
    19                 lis.insert(left,["@expr","-",leftPtr,rightPtr])
    20                 return 0
    21     # process: ^A-A+... | ^A-A-...
    22     if i==1 and len(lis)>3:
    23         if lis[left][0]=="@var"  or lis[left][0]=="@num" or 
    24            lis[left][0]=="@expr" or lis[left][0]=="@func" :
    25             if lis[right][0]=="@var"  or lis[right][0]=="@num" or 
    26                lis[right][0]=="@expr" or lis[right][0]=="@func" :
    27                 if lis[right+1][0] in "-+" :
    28                     leftPtr=lis[left]
    29                     rightPtr=lis[right]
    30                     del lis[left:left+3]
    31                     lis.insert(left,["@expr","-",leftPtr,rightPtr])
    32                     return 0
    33                 
    34     return 1

      运算符'+'规则:

     1 ########### return value :
     2 ############# 0  parsed some expresions
     3 ############# 1  done nothing but no errors happene
     4 def module_plus(lis,i):
     5 
     6     # left i right are both indexes :)    
     7     left=i-1
     8     right=i+1
     9 
    10     # process ^A+A$
    11     if i==1 and len(lis)==3:
    12         if lis[left][0]=="@var"  or lis[left][0]=="@num" or 
    13            lis[left][0]=="@expr" or lis[left][0]=="@func" :
    14             if lis[right][0]=="@var"  or lis[right][0]=="@num" or 
    15                lis[right][0]=="@expr" or lis[right][0]=="@func" :
    16                 leftPtr=lis[left]
    17                 rightPtr=lis[right]
    18                 del lis[left:left+3]
    19                 lis.insert(left,["@expr","+",leftPtr,rightPtr])
    20                 return 0
    21     # process ^A+A-... | ^A+A+...
    22     if i==1 and len(lis)>3:
    23         if lis[left][0]=="@var"  or lis[left][0]=="@num" or 
    24            lis[left][0]=="@expr" or lis[left][0]=="@func" :
    25             if lis[right][0]=="@var"  or lis[right][0]=="@num" or 
    26                lis[right][0]=="@expr" or lis[right][0]=="@func" :
    27                 if lis[right+1][0] in "-+" :
    28                     leftPtr=lis[left]
    29                     rightPtr=lis[right]
    30                     del lis[left:left+3]
    31                     lis.insert(left,["@expr","+",leftPtr,rightPtr])
    32                     return 0
    33 
    34     return 1

      运算符'*'规则:

     1 ########### return value :
     2 ############# 0  parsed some expresions
     3 ############# 1  done nothing but no errors happene
     4 def module_multiply(lis,i):
     5 
     6     # left i right are both indexes :)    
     7     left=i-1
     8     right=i+1
     9     
    10     # i is not at head and end
    11     # process ...A*A...
    12     if i<len(lis)-1 and i>0 :
    13         if lis[left][0]=="@var"  or lis[left][0]=="@num" or 
    14            lis[left][0]=="@expr" or lis[left][0]=="@func" :
    15             if lis[right][0]=="@var"  or lis[right][0]=="@num" or 
    16                lis[right][0]=="@expr" or lis[right][0]=="@func" :
    17                 leftPtr=lis[left]
    18                 rightPtr=lis[right]
    19                 del lis[left:left+3]
    20                 lis.insert(left,["@expr","*",leftPtr,rightPtr])
    21                 return 0
    22     return 1

      运算符'/'规则:

     1 ########### return value :
     2 ############# 0  parsed some expresions
     3 ############# 1  done nothing but no errors happene
     4 def module_division(lis,i):
     5 
     6     # left i right are both indexes :)    
     7     left=i-1
     8     right=i+1
     9     
    10     # i is not at head and end
    11     # process ...A/A...
    12     if i<len(lis)-1 and i>0 :
    13         if lis[left][0]=="@var"  or lis[left][0]=="@num" or 
    14            lis[left][0]=="@expr" or lis[left][0]=="@func" :
    15             if lis[right][0]=="@var"  or lis[right][0]=="@num" or 
    16                lis[right][0]=="@expr" or lis[right][0]=="@func" :
    17                 leftPtr=lis[left]
    18                 rightPtr=lis[right]
    19                 del lis[left:left+3]
    20                 lis.insert(left,["@expr","/",leftPtr,rightPtr])
    21                 return 0
    22     return 1     

      运算符'%'规则:

     1 ########### return value :
     2 ############# 0  parsed some expresions
     3 ############# 1  done nothing but no errors happene
     4 def module_mod(lis,i):
     5 
     6     # left i right are both indexes :)    
     7     left=i-1
     8     right=i+1
     9     
    10     # i is not at head and end
    11     # process ...A%A...
    12     if i<len(lis)-1 and i>0 :
    13         if lis[left][0]=="@var"  or lis[left][0]=="@num" or 
    14            lis[left][0]=="@expr" or lis[left][0]=="@func" :
    15             if lis[right][0]=="@var"  or lis[right][0]=="@num" or 
    16                lis[right][0]=="@expr" or lis[right][0]=="@func" :
    17                 leftPtr=lis[left]
    18                 rightPtr=lis[right]
    19                 del lis[left:left+3]
    20                 lis.insert(left,["@expr","%",leftPtr,rightPtr])
    21                 return 0
    22     return 1     

      语义分析函数:

     1 ########### return value :
     2 ############# 0  parsed sucessfully
     3 ############# 1  syntax error
     4 ############# 2  list is null :(
     5 def parse_simple_expr(lis):
     6     while 1:
     7         if len(lis)==0 :
     8             return 2
     9         if len(lis)==1 :
    10             if lis[0][0]=="@var"  or lis[0][0]=="@num" or 
    11                lis[0][0]=="@expr" or lis[0][0]=="@func" :
    12                 return 0
    13             else:
    14                 return 1
    15         if len(lis)==2 :
    16             return 1
    17         i=0
    18         while 1:
    19             if i<0 or i>=len(lis):
    20                 return 1
    21             if lis[i][0] in "-+*/%":
    22                 if lis[i][0]=="-":
    23                     if module_minus(lis,i)==0:
    24                         break
    25                     else:
    26                         i=i+1
    27                         continue
    28                 elif lis[i][0]=="+":
    29                     if module_plus(lis,i)==0:
    30                         break
    31                     else:
    32                         i=i+1
    33                         continue
    34                 elif lis[i][0]=="*":
    35                     if module_multiply(lis,i)==0:
    36                         break
    37                     else:
    38                         i=i+1
    39                         continue
    40                 elif lis[i][0]=="/":
    41                     if module_division(lis,i)==0:
    42                         break
    43                     else:
    44                         i=i+1
    45                         continue
    46                 elif lis[i][0]=="%":
    47                     if module_mod(lis,i)==0:
    48                         break
    49                     else:
    50                         i=i+1
    51                         continue
    52                 else :
    53                     return 1
    54             else:
    55                 i=i+1
    56             
    57     return 0

       实验结果:

      第二阶段:为我们的中缀表达式加入括号 :)

      新的文法规则如下:

    expr   -> expr addop term | term
    addop  -> + | -
    term   -> term mulop factor | factor
    mulop  -> * | / | %
    factor -> ( expr )| var | num | function

      算法处理大概过程:

      寻找出表达式中第一对'('')'位置的方法:

     1 ########### return value :[intStatusCode,indexOf'(',indexOf')']
     2 ############# intStatusCode
     3 ############# 0  sucessfully
     4 ############# 1  no parenthesis matched
     5 ############# 2  list is null :(
     6 def module_parenthesis_place(lis):
     7     length=len(lis)
     8     err=0
     9     x=0
    10     y=0
    11     
    12     if length==0:
    13         return [2,None,None]
    14     
    15     try:
    16         x=lis.index([")",None])
    17     except:
    18         err=1
    19     lis.reverse()
    20     try:
    21         y=lis.index(["(",None],length-x-1)
    22     except:
    23         err=1
    24     lis.reverse()
    25     y=length-y-1
    26     
    27     if err==1:
    28         return [1,None,None]
    29     else:
    30         return [0,y,x]

      处理包含有'('')'功能的中缀表达式的方法:

    ########### return value :
    ############# 0  parsed sucessfully
    ############# 1  syntax error
    ############# 2  list is null :(
    def parse_parenthesis_expr(lis):
        while 1:
            if len(lis)==0 :
                return 2
            if len(lis)==1 :
                if lis[0][0]=="@var"  or lis[0][0]=="@num" or 
                   lis[0][0]=="@expr" or lis[0][0]=="@func" :
                    return 0
                else:
                    return 1
            if len(lis)==2 :
                return 1
            place=module_parenthesis_place(lis)
            if place[0]==0:
                mirror=lis[(place[1]+1):place[2]]
                if parse_simple_expr(mirror)==0:
                    del lis[place[1]:(place[2]+1)]
                    lis.insert(place[1],mirror[0])
                else:
                    return 1
            else:
                return parse_simple_expr(lis)
            
        return 0

       实验结果:

      附录:

        在接下来的文章中,将会逐步增加其他的语义分析功能,如参与表达式运算的函数、条件语句的语法树生成等。

        如有问题或者建议,欢迎留言讨论 :)   

  • 相关阅读:
    Android Studio 打包生成apk
    找水王
    关于搜狗输入法的用户体验评价
    c语言函数的嵌套使用和矩阵运算
    人月神话阅读笔记02
    第一阶段冲刺意见评论汇总
    高校表白App-团队冲刺第十天
    高校表白App-团队冲刺第九天
    高校表白App-团队冲刺第八天
    人月神话阅读笔记01
  • 原文地址:https://www.cnblogs.com/SwordTao/p/3647434.html
Copyright © 2020-2023  润新知