编译原理课程测试第一套卷(附解析)
1.(20分)写出字母表  = {a, b}上语言L = {w | wa的个数是偶数}的正规式,并画出接受该语言的最简DFA。
2.(15分)考虑下面的表达式文法,它包括数组访问、加和赋值:
        E  E[E] | E + E | E = E | (E) | id
该文法是二义的。请写一个接受同样语言的LR(1)文法,其优先级从高到低依次是数组访问、加和赋值,并且加运算是左结合,赋值是右结合。
3.(10分)下面是产生字母表  = { 0, 1, 2}上数字串的一个文法:
        S  D S D | 2
        D  0 | 1
写一个语法制导定义,它打印一个句子是否为回文数(一个数字串,从左向右读和从右向左读都一样时,称它为回文数)。
4.(10分)教材上7.2.1节的翻译方案
P             {offset := 0}
              D
D D ; D
D id : T        { enter(id.name, T.type, offset); offset := offset + T.width }
T   integer        {T.type := integer;  T.width := 4 }
T  real            {T.type := real; T.width := 8 }
使用了变量offset。请重写该翻译方案,它完成同样的事情,但只使用文法符号的属性,而不使用变量。
5.(5分)一个C语言程序如下:
        void fun(struct {int x; double r;} val) { 
}
        main()
        {
            struct {int x; double r;} val;
            fun(val);
        }
该程序在X86/Linux机器上的用cc命令编译时,报告的错误信息如下:
        1: warning: structure defined inside parms
        1: warning: anonymous struct declared inside parameter list
        1: warning: its scope is only this definition or declaration,
        1: warning: which is probably not what you want.
        7: incompatible type for argument 1 of ‘fun’ 
请问,报告最后一行的错误的原因是什么?如何修改程序,使得编译时不再出现这个错误信息。
6.(10分)一个C语言程序如下:
        typedef struct _a{
                short  i;
                short  j;
                short  k;
        }a;
        typedef struct _b{
                long  i;
一个完整的c语言程序                short  k;
        }b;
        main()
        {
                printf("Size of short, long, a and b = %d,%d,%d,%d\n",
                                sizeof(short), sizeof(long),sizeof(a),sizeof(b));
        }
    该程序在X86/Linux机器上的运行结果如下:
        Size of short, long, a and b = 2, 4, 6, 8
已知short类型和long类型分别对齐到2的倍数和4的倍数。试问,为什么类型b的size会等于8?
7.(15分)一个C语言程序如下:
int fact(i)
int i;
{
            if(i==0)
                return 1;
            else
                return i*fact(i-1);
}
main()
{
            printf("%d\n", fact(5));
            printf("%d\n", fact(5,10,15));
            printf("%d\n", fact(5.0));
            printf("%d\n", fact());
}
该程序在X86/Linux机器上的运行结果如下:
120
120
1
Segmentation fault (core dumped)
    请解释下面问题:
  第二个fact调用:结果为什么没有受参数过多的影响?
  第三个fact调用:为什么用浮点数5.0作为参数时结果变成1?
  第四个fact调用:为什么没有提供参数时会出现Segmentation fault?
8.(5分)C语言的赋值操作并非仅对简单类型而言,例如若有类型声明long a[100], b[100];,则赋值a=b是允许的。同样,若ab是同一类型的两个结构,则赋值a=b也是允许的。
    用教材上第七章所给出的三地址语句,我们能否为这种赋值产生中间代码?若你持肯定态度,请你给出对应这种赋值的中间代码序列;否则请你为这种赋值设计一种三地址语句。你所选用或设计的三地址语句要便于目标代码的生成。
9.(5分)一个C程序的三个文件的内容如下:
head.h:
short int a = 10;
file1.c:
#include "head.h"
main()
{
}
file2.c:
#include "head.h"
X86/Linux机器上的编译命令如下:
cc file1.c file2.c
编译结果报错的主要信息如下:
multiple definition of ‘a’
试分析为什么会报这样的错误。
10.(5分)按照教材上介绍的方法,把下面C++语言的函数翻译成C的函数。
void zoom (GraphicalObj &obj, double zoom_factor, Point ¢er) {
anslate ( center.x, center.y);    // 将中心点移至原点(0, 0)
                obj.scale (zoom_factor);              // 缩放
}
编译原理课程测试第一套卷参考答案
1.语言L的正规式是:
        (a b*a | b)* b*(a b*a b*)*
接受该语言的最简DFA是:
2.        E  T = E | T
        T  T + F | F
        F  F[E] | (E) | id
3.        S    S                print(S.val)
S  D1 S1 D2        S.val =    (D1.val = D2.val) and S1.val
S  2                S.val = true
        D  0                D.val = 0
D  1                D.val = 1
4.文法符号D的属性offset1是继承属性,代表在分析D前原来使用的变量offset的大小;属性offset2是综合属性,代表在分析D后原来使用的变量offset的大小。P的属性offset是综合
属性,记录该过程所分配的空间
        P     {D.offset1 := 0} D {P.offset := D.offset2 }
D     {D1.offset1 := D.offset1 }D1 ;
{D2.offset1 := D1.offset2 }D2 {D.offset2 := D2.offset2 }
D id : T {enter ( id.name, T.type, D.offset1); 
D.offset2 := D.offset1 + T.width }
T   integer {T.type := integer;  T.width := 4 }
T  real    {T.type := real; T.width := 8 }
5C语言对所有的类型都采用结构等价,唯有结构类型例外,采用名字等价。这里的类型不相容是因为两个val不是名字等价的。
    要消除这个错误,包括所有的警告,程序修改如下:
struct s{
int x;
double r;
};
        void fun(struct s val) { 
}
        main()
        {
            struct s val;
            fun(val);
        }
6.一个数组的size等于数组元素的size乘以数组元素的个数,这是一个原则。
对于结构类型b来说,它的一个变量只需6个字节就够了。如果声明结构类型b的一个数组,有两种可能:
(a)结构类型b的size 是6,数组元素之间空两个字节,以保证每个数组元素的地址都是4的倍数(因为第一个域i的类型是long,要求对齐到4的倍数)。
(b)结构类型b的size 是8,以保证它作为数组元素的类型时,数组元素之间不用再考虑对齐问题。
方法(a)违反了我们一开始提到的原则,因此只能取方法(b)。
7.    (1)参数表达式逆序计算并进栈,fact能够取到第一个参数。
    (2)参数5.0转换成双精度数进栈,占8个字节。它低地址的4个字节看成整数时正好是0。
    (3)由于没有提供参数,fact把老ebp(控制链)(main的活动记录中保存的ebp)当
成参数,它一定是一个很大的整数,使得活动记录栈溢出。
8.教材上的中间代码有形如x := y的复写语句,用它就可以了。但是生成目标代码时,必须考虑xy的类型。若xy不是简单类型,则应该根据它们类型的size,产生一连串的值传送指令。
9.由于file1.c和file2.c两个文件都包含文件head.h,而head.h中有short int a = 10,因此该程序有两个a的强符号定义。
10.按照教材上介绍的方法,函数的翻译结果如下:
void zoom (GraphicalObj &obj, double zoom_factor, Point ¢er) {
obj.vptr[0] (obj, center.x, center.y);    // 将中心点移至原点(0, 0)
                obj.vptr[1] (obj, zoom_factor);        // 缩放
}

版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。