📜  TOC中的运算符语法和优先级解析器

📅  最后修改于: 2021-06-28 06:46:02             🧑  作者: Mango

用于定义数学运算符符的语法称为运算符语法运算符优先级语法。这样的语法有一个局限性,即没有任何产品的右侧有一个空的(空产品)或两个相邻的非末尾。

例子 –
这是一个运算符语法的示例:

E->E+E/E*E/id 

但是,下面给出的语法不是运算符语法,因为两个非终结点彼此相邻:

S->SAS/a
A->bSb/b 

不过,我们可以将其转换为运算符语法:

S->SbSbS/SbS/a
A->bSb/b  

运算符优先级解析器–
运算符优先级解析器是一种自下而上的解析器,用于解释运算符语法。该解析器仅用于运算符语法。除运算符优先级解析器外,任何解析器均不允许歧义语法
有两种方法可确定一对终端之间应保持何种优先级关系:

  1. 使用常规的关联性和运算符的优先级。
  2. 选择运算符优先级关系的第二种方法是,首先为语言构造一个明确的语法,该语法在其解析树中反映正确的关联性和优先级。

该解析器依赖于以下三个优先级关系: ⋖,≐,⋗
a⋖b这意味着“相对于b的屈服优先”。
a⋗b这表示“优先于” b。
a≐b这意味着“与…具有相同的优先级”。


图–语法E-> E + E / E * E / id的运算符优先级关系表

id和id之间没有任何关系,因为将不会比较id并且两个变量不能并排。该表还有一个缺点–如果我们有n个运算符,则表的大小将为n * n,复杂度将为0(n 2 )。为了减小表的大小,我们使用运算符函数 table

运算符优先级解析器通常不将优先级表与关系存储在一起;而是以一种特殊的方式实现它们。运算符优先级解析器使用优先级函数将终端符号映射到整数,并且符号之间的优先级关系通过数值比较来实现。解析表可以由两个优先级函数fg编码,这两个优先级函数将终端符号映射为整数。我们选择f和g使得:

  1. 当a的优先级高于b时f(a)
  2. 只要a和b的优先级相同,则f(a)= g(b)
  3. 当a优先于b时f(a)> g(b)

示例–考虑以下语法:

E -> E + E/E * E/( E )/id   

这是表示优先级函数的有向图:

由于图中没有循环,因此我们可以制作此函数表:

fid -> g* -> f+ ->g+ -> f$
gid -> f* -> g* ->f+ -> g+ ->f$ 

桌子的大小是2n

函数表的一个缺点是,即使关系表中有空白条目,函数表中也有非空白条目。空白条目也称为错误。因此,关系表的错误检测能力大于函数表。

#include
#include
#include
  
// function f to exit from the loop
// if given condition is not true
void f()
{
    printf("Not operator grammar");
    exit(0);
}
  
void main()
{
    char grm[20][20], c;
  
    // Here using flag variable,
    // considering grammar is not operator grammar
    int i, n, j = 2, flag = 0;
  
    // taking number of productions from user
    scanf("%d", &n);
    for (i = 0; i < n; i++)
        scanf("%s", grm[i]);
  
    for (i = 0; i < n; i++) {
        c = grm[i][2];
  
        while (c != '\0') {
  
            if (grm[i][3] == '+' || grm[i][3] == '-'
                || grm[i][3] == '*' || grm[i][3] == '/')
  
                flag = 1;
  
            else {
  
                flag = 0;
                f();
            }
  
            if (c == '$') {
                flag = 0;
                f();
            }
  
            c = grm[i][++j];
        }
    }
  
    if (flag == 1)
        printf("Operator grammar");
}
Input :3
A=A*A
B=AA
A=$

Output : Not operator grammar

Input :2
A=A/A
B=A+A

Output : Operator grammar

$此处为空值,运算符语法中也不允许使用$。

好处 –

  1. 它可以很容易地手工建造。
  2. 实现这种类型的解析很简单。

缺点–

  1. 像负号(-)这样的令牌很难处理,它具有两个不同的优先级(取决于它是一元还是二进制)。
  2. 它仅适用于一小类语法。