1. 梳理第二章的内容,写一篇理解与总结。
当我们要描述一种语言时,需要给出这种语言的所有句子,当句子的数目是有限可数时,就要都列出来;当句子
是一个无穷集,也就是无限不可数时,就要给出可以表示它们的结构的描述方法或者说,句子的组成规则。这种
规则就是文法。
从形式上用于描述和规定结构的称为文法(或者说语法)
一、文法的定义:
文法G定义为一个四元组(VN,VT,P,S),其中,
VN为非终结符集合,VT终结符集合;P是产生式结合;S称为识别符或开始符号,也是一个非终结符,至少要在一
条产生式的左边出现。
出现了几个名词,终结符、非终结符、产生式、识别符/开始符号等。下面具体聊聊这些名词和文法的定义。
VN是非终结符集合,非终结符N指的是可以被拆分的字符或串,它采取递归定义:一个非终结符是由终结符和至少
一个非终结符组成的串,相对应的,终结符就是不可拆分的,语言中要用到的字符。所以VN中所存储的是所有的
非终结符,VT中存储的是所有的终结符。
简单点讲:终结符就是推导到终结符时,不可再推导下去;而非终结符可以继续推导下去。
集合P存储的是所有的产生式。那什么是产生式呢?产生式就是推导规则。比方说 a→b 就是一条规则,即一条产
生式,可以通过 a 推导出 b。
对照前面说的非终结符和终结符,就应该可以理解,在产生式左边的只能是非终结符,因为终结符不能再推导下
去。而右边可以有终结符和非终结符。用数学的集合知识表示就是:
产生式的形式是α → β,α称为产生式左部,β称为产生式右部,α属于VN,β∈(VN∪VT)*,α∉ε
最后是S,S是开始符号,也就是最开始的那条产生式左边的非终结符,一切的推导从它开始。比方说
a → b
b → c|d
c → e
其中,a → b就是最开始的产生式,a就是最开始的非终结符,就是S。S是非终结符,所以S∈VN。
二、文法与语言的推导
举个例子:
G(E):
E=> E + T | T
T=>T * F | F
F=>(E)| i
求i*i+i的推导式:
E=>E+T
=>T+T
=>T*F+T
=>F*F+T
=>i*F+T
=>i*i+T
=>i*i+F
=>i*i+i
同理从右往左一个个元素的换算就是右推导了。
三、句型、句子
对于文法G[S]:
如果: S=>a,则a称为G的一个句型,
开始符号是最简单的句型。
如果:a是G[S]的一个句型,且a属于VT,
则a称被称为G[S]的一个句子,
也就是说句子是全部有终结符组成的句型。
四.语法分析树与二义性
我们发现从一个句型到另一个句型的推导过程不是唯一的。例如从E+E->i+i,存在两个推导过程:
E+E->E+i->i+i 最右推导,每个推导过程都是从最右边的非终结符号的替换开始
E+E->i+E->i+i 最左推导,每个推导过程都是从最左边的非终结符号的替换开始
当然为了对句子的结构进行一个确定性的分析,我们一般只考虑最左推导或者最右推导。
前面我们提到过用一种树形的图示来表示这个句型的推导过程,这棵树就被称为”语法分析树“,简称”语法树“。
对于一个文法,如果它的某些句子对应两棵不同的语法树,这个文法就属于“二义性文法”。
注意,文法的二义性和我们通常所说的语言的二义性不同,我们可能有两个不同的文法G1,G2,一个是二义性,
一个是非二义性,但是可能L(G1) = L(G2)。对于程序语言来说,我们常常希望它的文法是非二义性的,但
是,只要我们能够控制和驾驭文法的二义性,文法二义性的存在也不一定是坏事。
现在已经证明了,文法二义性是不可判定的。也就是说不存在一个算法,在有限步骤内算出一个文法是不是二义
性的。我们能做的事儿,就是找一组充分条件来说明非二义性。比如,规定运算符号的优先级和结合性。
2. 尝试写出PL/0 语言的文法。(或者你认为比较好的语言规则)
整数n
标识符i
表达式e
条件语句
赋值语句
复合语句
函数
程序
...
答:
整数n <整数n>::=int <标识符n>=<无符号整数>|<有符号整数>;
标识符i <标识符i>::= <字符类型> <字母|数字>;
表达式e <表达式> ::= [+ | -] <项> { <加法运算符><项>}
条件语句 <表达式>{语句} ;|<表达式>{句子}
赋值语句 <标识符>=<无符号整数>|<有符号整数>;
<复合语句> ::= BEGIN <语句> {;<语句>} END
函数 <数据类型> <标识符>(形式参数...){句子;...}
<程序> ::= <分程序>.
<分程序> ::= [<常量说明部分>] [<变量说明部分>]
[<过程说明部分>] <语句>
...