免费智能真题库 > 历年试卷 > 软件设计师 > 2015年下半年 软件设计师 上午试卷 综合知识
  第20题      
  知识点:   词法分析   目标代码生成   语法分析   编译器   代码优化   高级语言   语义分析   中间代码   中间代码生成
  关键词:   编译器   词法分析   代码生成   代码优化   高级语言处理程序   解释器   语法分析   语义分析   源程序   中间代码   编译   高级语言   语言   语义        章/节:   计算机软件知识       

 
编译器和解释器是两种基本的高级语言处理程序。编译器高级语言源程序的处理过程可以划分为词法分析语法分析语义分析中间代码生成、代码优化目标代码生成等阶段,其中,(20)并不是每个编译器都必需的,与编译器相比,解释器(21)。
 
 
  A.  词法分析和语法分析
 
  B.  语义分析和中间代码生成
 
  C.  中间代码生成和代码优化
 
  D.  代码优化和目标代码生成
 
 
 

 
  第22题    2012年上半年  
   19%
算术表达式x-(y+c)*8的后缀式是(22) (-、+、*表示算术的减、加、乘运算,运算符的优先级和结合性遵循惯例)。
  第48题    2016年上半年  
   52%
移进—归约分析法是编译程序(或解释程序)对高级语言源程序进行语法分析的一种方法,属于(48)的语法分析方法。
  第22题    2014年上半年  
   35%
编译程序对高级语言源程序进行编译的过程中,要不断收集、记录和使用源程序中一些相关符号的类型和特征等信息,并将其存入 (22) ..
   知识点讲解    
   · 词法分析    · 目标代码生成    · 语法分析    · 编译器    · 代码优化    · 高级语言    · 语义分析    · 中间代码    · 中间代码生成
 
       词法分析
        1)正规表达式和正规集
        对于字母表∑,其上的正规表达式(也称正则表达式,简称正规式)及其表示的正规集可以递归定义如下。
        (1)ε是一个正规式,它表示集合L(ε)={ε}。
        (2)若a是∑上的字符,则a是一个正规式,它所表示的正规集为{a}。
        (3)若正规式rs分别表示正规集L(r)和L(s),则
        ①r|s是正规式,表示集合L(r)∪L(s)。
        ②r.s是正规式,表示集合L(r)L(s)。
        ③r*是正规式,表示集合(L(r))*
        ④(r)是正规式,表示集合L(r)。
        仅由有限次地使用上述3个步骤定义的表达式才是∑上的正规式,其中运算符"|"".""*"分别称为"或""连接"和"闭包"。若两个正规式表示的正规集相同,则认为两者等价。
        2)有限自动机
        有限自动机是一种识别装置的抽象概念,它能够正确地识别正规集。
        (1)确定的有限自动机。
        一个确定的有限自动机(DFA)是个五元组:(S,∑,fs0Z),其中:
        ①S是一个有限集,其每个元素称为一个状态。
        ②∑是一个有限字母表,其每个元素称为一个输入字符。
        ③f是从S×∑→S上的单值部分映像。
        ④s0S是唯一的一个开始状态。
        ⑤Z是非空的终止状态集合。
        一个DFA可以用两种直观的方式表示,即状态转换图和状态转换矩阵。状态转换图简称为转换图,它是一个有向图。DFA中的每个状态对应转换图中的一个节点,DFA中的每个转换函数对应图中的一条有向弧,若转换函数为f(A,a)=Q,则该有向弧从节点A出发,进入节点Q,字符a是弧上的标记。状态转换矩阵可以用一个二维数组M表示,矩阵元素的行下标表示状态,列下标表示输入字符,M[A,a]的值是当前状态为A、输入为a时应转换到的下一状态。在转换矩阵中,一般以第一行的行下标所对应的状态作为初态,而终态则需要特别指出。
        (2)不确定的有限自动机。
        一个不确定的有限自动机(NFA)也是一个五元组,它与确定的有限自动机的区别如下。
        ①f是从S×∑→2S上的映像。对于S中的一个给定状态及输入符号,返回一个状态的集合。
        ②有向弧上的标记可以是ε。
        显然,DFA是NFA的特例。
        实际上,对于每个NFAM,都存在一个DFAN,且L(M)=L(N)。
        对于任何两个有限自动机M1M2,如果L(M1)=L(M2),则称M1M2是等价的。
        3)NFA到DFA的转换
        设NFAN=(S,∑,f,s0Z),与之等价的DFAM=(S',∑,f',q0,Z'),用子集法将非确定的有限自动机确定化的算法步骤如下。
        (1)求出DFAM的初态q0,此时S'仅含初态q0,并且没有标记。
        (2)对于S'中尚未标记的状态qi={si1,si2,…,sim}和sij∈(j=1,2,…,m)进行下述处理。
        ①标记qi
        ②对于每个a∈∑,令T=f(si1,si2,…,sim,a),qj=ε_CLOSURE(T)。
        ③若qi尚不在S'中,则将qj作为一个未加标记的新状态添加到S',并把状态转换函数f'(qi,a)=qj添加到DFAM
        (3)重复步骤(2),直到S'中不再有未标记的状态时为止。
        (4)令Z'={q|qS'且qZ≠?}。
        注:I是NFAN的状态集合的一个子集,其中ε_CLOSURE(I)的定义如下。
        ①状态集I的ε_CLOSURE(I)是一个状态集。
        ②状态集I的所有状态属于ε_CLOSURE(I)。
        ③若sI中,那么从s出发经过任意条ε弧到达的状态s'都属于ε_CLOSURE(I)。
        从NFA转换得到的DFA不一定是最简化的,可以通过等价变换将DFA进行最小化处理。
        4)正规式与有限自动机之间的转换
        (1)对于∑上的NFAM,可以构造一个∑上的正规式R,使得L(R)=L(M)。
        构造过程分以下两步进行。
        ①在M的状态转换图中加两个节点xy
        ②按下图所示的方法逐步消去M中的除xy的所有节点。
        
        状态转换图(消去中间节点)
        (2)对于∑上的每一个正规式R,可以构造一个∑上的NFAM,使得L(M)=L(R)。
        (3)构造过程分两步进行。
        ①对于正规式R,可用如下图所示的拓广状态图表示。
        
        拓广状态图
        ②通过对正规式R进行分裂并加入新的节点,逐步把图转变成每条弧上的标记是∑上的一个字符或ε,转换规则如下图所示。
        
        状态转换图(加入新节点)
        5)词法分析器的构造
        词法分析器的构造过程如下。
        (1)用正规式描述语言中的单词构成规则。
        (2)为每个正规式构造一个NFA,用于识别正规式所表示的正规集。
        (3)将构造出的NFA转换成等价的DFA。
        (4)对DFA进行最小化处理,使其最简。
        (5)根据DFA构造词法分析器。
 
       目标代码生成
        代码生成器以经过语义分析或优化后的中间代码为输入,以特定的机器语言或汇编代码为输出。代码生成主要考虑以下问题,即中间代码形式、目标代码形式、寄存器的分配、计算次序的选择。
 
       语法分析
        语法分析的任务是根据语言的语法规则,分析单词串是否构成短语和句子,同时检查和处理程序中的语法错误。根据产生语法树的方向,语法分析可分为自底向上和自顶向下两类。
        自顶向下的分析是对给定的符号串,试图自顶向下地为其构造一棵语法树,或者说从文法的开始符号出发,为其构造一个最佳推导。
        自底向上的分析是对给定的符号串,试图自底向上地为其构造一棵语法树,或者说从给定的符号串本身出发,试图将其归约为文法的开始符号。
        算符优先文法属于自底向上的分析法,它利用各个算符间的优先关系和结合规则来进行语法分析,特别是用于分析各种表达式。算符优先文法的任何产生式的右部都会出现两个非终结符相邻的情况,且任何一对终结符之间至多只有3种算符关系,即">""<"和"="之一成立。
 
       编译器
        编译阶段要做的工作是用交叉编译或汇编工具处理源代码,产生目标文件。在嵌入式系统中,宿主机和目标机所采用的处理器芯片通常是不一样的。例如,目标机采用的CPU是DragonBall M68x系列或ARM系列,而宿主机采用的是x86系列。因此,为了把宿主机上编写的高级语言程序编译成可以在目标机上运行的二进制代码,就需要用到交叉编译器。
        与普通PC中的C语言编译器不同,嵌入式系统中的C语言编译器要进行专门的优化,以提高编译效率。一般来说,优秀的嵌入式C编译器所生成的代码,其长度和执行时间仅比用汇编语言编写的代码长5%~20%。编译质量的不同,是区别嵌入式C编译器工具的重要指标。因此,硬件厂商往往会针对自己开发的处理器的特性来定制编译器,既提供对高级语言的支持,又能很好地对目标代码进行优化。
        GNU C/C++(gcc)是目前比较常用的一种交叉编译器,它支持非常多的宿主机/目标机组合。宿主机可以是Unix、AIX、Solaris、Windows、Linux等操作系统,目标机可以是x86、Power PC、MIPS、SPARC、Motorola 68K等各种类型的处理器。
        gcc是一个功能强大的工具集合,包含了预处理器、编译器、汇编器、连接器等组件。它在需要时会去调用这些组件来完成编译任务,而输入文件的类型和传递给gcc的参数决定了它将调用哪些组件。对于一般或初级的开发者,它可以提供简单的使用方式,即只给它提供C源码文件,它将完成预处理、编译、汇编、连接等所有工作,最后生成一个可执行文件。而对于中高级开发者,它提供了足够多的参数,可以让开发者全面控制代码的生成,这对于嵌入式系统软件开发来说是非常重要的。
        gcc识别的文件类型主要包括:C语言文件、C++语言文件、预处理后的C文件、预处理后的C++文件、汇编语言文件、目标文件、静态链接库、动态链接库等。以C程序为例,gcc的编译过程主要分为4个阶段:
        (1)预处理阶段,即完成宏定义和include文件展开等工作;
        (2)根据编译参数进行不同程度的优化,编译成汇编代码;
        (3)用汇编器把上一阶段生成的汇编码进一步生成目标代码;
        (4)用连接器把上一阶段生成的目标代码、其他一些相关的系统目标代码以及系统的库函数连接起来,生成最终的可执行代码。
        用户可以通过设定不同的编译参数,让gcc在编译的不同阶段停止下来,这样可以检查编译器在不同阶段的输出结果。
        在gcc的高级用法上,一般希望通过使用编译器达到两个目的:检查出源程序的错误;生成速度快、代码量小的执行程序。这可以通过设置不同的参数来实现,例如,“-Wall”参数可以发现源程序中隐藏的错误;“-O2”参数可以优化程序的执行速度和代码大小;“-g”参数可以对执行程序进行调试。
 
       代码优化
        优化是一个编译器的重要组成部分,由于编译器将源程序翻译成中间代码的工作是机械的、按固定模式进行的,因此,生成的中间代码往往在时间和空间方面的效率较差。当需要生成高效的目标代码时,就必须进行优化。优化过程可以在中间代码生成阶段进行,也可以在目标代码生成阶段进行。由于中间代码不依赖于具体机器,此时所作的优化一般建立在对程序的控制流和数据流分析的基础之上,与具体的机器无关。优化所依据的原则是程序的等价变换规则。例如,在生成X:=Y+Z*60的四元式后,60是编译时已知的常数,把它转换为60.0的工作可以在编译时完成,没有必要生成一个四元式,同时t3仅仅用来将其值传递给idl,也可以化简掉,因此上述的中间代码可转优化成下面的等价代码:
        
        这只是优化工作中的一个简单示例,真正的优化工作要复杂得多。
 
       高级语言
        不论是机器语言还是汇编语言都是面向硬件的具体操作的,语言对机器的过分依赖,要求使用者必须对硬件结构及其工作原理都十分熟悉,非计算机专业人员是难以做到的,对于计算机的推广应用是不利的。计算机事业的发展,促使人们去寻求一些与人类自然语言相接近且能为计算机所接受的语意确定、规则明确、自然直观和通用易学的计算机语言。这种与自然语言相近并为计算机所接受和执行的计算机语言称高级语言。高级语言是面向用户的语言,每一种高级(程序设计)语言,都有自己人为规定的专用符号、英文单词、语法规则和语句结构(书写格式)。高级语言与自然语言(英语)更接近,而与硬件功能相分离(彻底脱离了具体的指令系统),便于广大用户掌握和使用。高级语言的通用性强,兼容性好,便于移植。
        高级语言主要是相对于汇编语言而言,它并不是特指某一种具体的语言,而是包括了很多编程语言。它又可分为面向过程的语言和面向问题的语言,前者在编程时不仅要告诉计算机“做什么”,而且要告诉计算机“怎么做”,如Basic,Pascal, Fortran, C等高级语言。后者只要告诉计算机做什么,如Lisp,Prolog等高级语言,也常称为人工智能语言。
 
       语义分析
        语义分析阶段分析各语法结构的含义,检查源程序是否包含静态语义错误,并收集类型信息供后面的代码生成阶段使用。只有语法和语义都正确的源程序才能翻译成正确的目标代码。
        语义分析的一个主要工作是进行类型分析和检查。程序语言中的一个数据类型一般包含两个方面的内容:类型的载体及其上的运算。例如,整除取余运算符只能对整型数据进行运算,若其运算对象中有浮点数就认为是一种类型不匹配的错误。
        在确认源程序的语法和语义之后,就可对其进行翻译并给出源程序的内部表示。对于声明语句,需要记录所遇到的符号的信息,所以应进行符号表的填查工作。在下图所示的符号表中,每一行存放一个符号的信息。第一行存放标识符X的信息,其类型为real,为它分配的地址是0;第二行存放Y的信息,其类型是real,为它分配的地址是4。因此,在该语言中,为一个real型数据分配的存储空间是4个存储单元。对于可执行语句,则检查结构合理的表达式是否有意义。对id1:=id2+id3*60进行语义分析后的语法树如下图所示,其中增加了一个语义处理节点inttoreal,该运算用于将一个整型数转换为浮点数。
        
        语义分析后的符号表和语法树示意图
 
       中间代码
        从原理上讲,对源程序进行语义分析之后就可以直接生成目标代码,但由于源程序与目标代码的逻辑结构往往差别很大,特别是考虑到具体机器指令系统的特点,要使翻译一次到位很困难,而且用语法制导方式机械生成的目标代码往往是烦琐和低效的,因此有必要设计一种中间代码,将源程序首先翻译成中间代码表示形式,以利于进行与机器无关的优化处理。由于中间代码实际上也起着编译器前端和后端的分水岭作用,所以使用中间代码也有助于提高编译程序的可移植性。常用的中间代码有后缀式、四元式和树等形式。
        (1)后缀式(逆波兰式)。逆波兰式是波兰逻辑学家卢卡西维奇(Lukasiewicz)发明的一种表示表达式的方法。这种表示方式把运算符写在运算对象的后面,例如,把a+b写成ab+,所以也称为后缀式。这种表示法的优点是根据运算对象和算符的出现次序进行计算,不需要使用括号,也便于用栈实现求值。对于表达式x:=(a+b)*(c+d),其后缀式为xab+cd+*:=。
        (2)树形表示。例如,表达式x:=(a+b)*(c+d)的树形表示如下图所示。
        
        表达式的树形表示
        (3)四元式表示。四元式是一种普遍采用的中间代码形式,其组成成分为运算符OP、第一运算对象ARG1、第二运算对象ARG2和运算结果RESULT。其中,运算对象和运算结果有时指用户自定义的变量,有时指编译程序引入的临时变量,RESULT总是一个新引进的临时变量,用来存放运算结果。例如,表达式x:=(a+b)*(c+d)的四元式表示为:
        ①(+,a,b,t1)②(+,c,d,t2)③(*,t1,t2,t3)④(:=,t3,_,x)
 
       中间代码生成
        中间代码生成阶段的工作是根据语义分析的输出生成中间代码。“中间代码”是一种简单且含义明确的记号系统,可以有若干种形式,它们的共同特征是与具体的机器无关。最常用的一种中间代码是与汇编语言的指令非常相似的三地址码,其实现方式常采用四元式。四元式的形式为:
        
        例如,对语句X:=Y+Z*60,可生成以下四元式序列:
        
        其中,t1、t2、t3是编译程序生成的临时变量,用于存放临时的运算结果。
        语义分析和中间代码生成所依据的是语言的语义规则。
   题号导航      2015年下半年 软件设计师 上午试卷 综合知识   本试卷我的完整做题情况  
1 /
2 /
3 /
4 /
5 /
6 /
7 /
8 /
9 /
10 /
11 /
12 /
13 /
14 /
15 /
 
16 /
17 /
18 /
19 /
20 /
21 /
22 /
23 /
24 /
25 /
26 /
27 /
28 /
29 /
30 /
 
31 /
32 /
33 /
34 /
35 /
36 /
37 /
38 /
39 /
40 /
41 /
42 /
43 /
44 /
45 /
 
46 /
47 /
48 /
49 /
50 /
51 /
52 /
53 /
54 /
55 /
56 /
57 /
58 /
59 /
60 /
 
61 /
62 /
63 /
64 /
65 /
66 /
67 /
68 /
69 /
70 /
71 /
72 /
73 /
74 /
75 /
 
第20题    在手机中做本题