用于定义数学运算符符的语法称为运算符语法或运算符优先级语法。这样的语法有一个局限性,即没有任何产品的右侧有一个空的(空产品)或两个相邻的非末尾。
例子 –
这是一个运算符语法的示例:
E->E+E/E*E/id
但是,下面给出的语法不是运算符语法,因为两个非终结点彼此相邻:
S->SAS/a
A->bSb/b
不过,我们可以将其转换为运算符语法:
S->SbSbS/SbS/a
A->bSb/b
运算符优先级解析器–
运算符优先级解析器是一种自下而上的解析器,用于解释运算符语法。该解析器仅用于运算符语法。除运算符优先级解析器外,任何解析器均不允许歧义语法。
有两种方法可确定一对终端之间应保持何种优先级关系:
- 使用常规的关联性和运算符的优先级。
- 选择运算符优先级关系的第二种方法是,首先为语言构造一个明确的语法,该语法在其解析树中反映正确的关联性和优先级。
该解析器依赖于以下三个优先级关系: ⋖,≐,⋗
a⋖b这意味着“相对于b的屈服优先”。
a⋗b这表示“优先于” b。
a≐b这意味着“与…具有相同的优先级”。
图–语法E-> E + E / E * E / id的运算符优先级关系表
id和id之间没有任何关系,因为将不会比较id并且两个变量不能并排。该表还有一个缺点–如果我们有n个运算符,则表的大小将为n * n,复杂度将为0(n 2 )。为了减小表的大小,我们使用运算符函数 table 。
运算符优先级解析器通常不将优先级表与关系存储在一起;而是以一种特殊的方式实现它们。运算符优先级解析器使用优先级函数将终端符号映射到整数,并且符号之间的优先级关系通过数值比较来实现。解析表可以由两个优先级函数f和g编码,这两个优先级函数将终端符号映射为整数。我们选择f和g使得:
- 当a的优先级高于b时f(a)
- 只要a和b的优先级相同,则f(a)= g(b)
- 当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
$此处为空值,运算符语法中也不允许使用$。
好处 –
- 它可以很容易地手工建造。
- 实现这种类型的解析很简单。
缺点–
- 像负号(-)这样的令牌很难处理,它具有两个不同的优先级(取决于它是一元还是二进制)。
- 它仅适用于一小类语法。