1. a) I have tried to show which declaration of an identifier matches each use by using a different indentation for each set of declarations & corresponding uses (this does not match the nesting - e.g. function p's variables are not inside the struct!).
<global
<struct
<1st level inside function p
<2nd level inside function p
static int
i, j, k, a ; static float
b, c ; static struct {int
i, j, k;}
x;
static void p(){int
i, n, d; float
e; for (
n= 1;
n<= 2;
n++){
i=
j;
k++; d=
a+b*c+ e; if
(e) e= d; if
(n== 1){
int i, m, a;
float f;
i=
j; m=
n; f=a*
b+c* d;
p=
x+ f; if
(k< 2)
p();}}}int
main(void){
k= 0;
j= 0;
x. k= 0;
x. j= 0;
p(); return 0;}
b) I have tried to hint at the structure of the parse trees for the statements by the way they are indented below. Each expression would also have a tree structure (which I have added at the end for one of the more complex expressions). I have added the type information (I=int, F=float, with more complex types in [ ]) and type conversions (int_to_float, float_to_int), and indicated semantic errors by [!].
for nI = 1I
nI <= 2I
nI++
{ iI= jI
kI++
dI=float_to_int (((int_float(aI)+(bF*cF))+eF)
if eF
eF= dI
{}
if (nI == 1I)
{ iI= jI
mI= nI
fF= (int_to_float(aI)*bF)+(cF*int_to_float(dI))
p[func!]= x[struct!]+fF
if kI < 2I
p[void(void)]()
{}
}
{}
}
. . .
kI= 0I
jI= 0I
x[struct].kI= 0I
x[struct].jI= 0I
p[void(void)]()
return 0I
e.g. d=float_to_int (((int_float(a)+(b*c))+e) would look something like:
=
d ()
float_to_int +
+ e
() *
int_float a b c
2. I can't draw all the links (e.g. the names in the middle column (int, double, void, long int, r, UU, x, z, s, rr) should be links to the right-hand column entries for those names) but the dictionary should look something like this:
double -> 0: type -> builtin char -> 0: type -> builtin int -> 0: type -> builtin void -> 0: type -> builtin long int-> 0: type -> builtin i -> 2: param -> long int* -> 1: var int j -> 2: param -> long int* -> 1: var int a -> 1: var -> int [10] p -> 1: func void, long int*, long int* red -> 2: const int 0 blue -> 2: const int 1 x -> 2: type -> enum (2?) y -> 2: type -> char z -> 2: type -> x [5] f1 -> 2: field long int r f2 -> 2: field long int r f3 -> 2: field double r f4 -> 2: field double r f5 -> 2: field char r UU -> 2: field r -> union . . . b -> 2: field char UU f6 -> 2: field y UU s -> 2: type r -> 2: type -> struct . . . -> 2: struct tag-> (also points to struct above) xx -> 2: var x zz -> 2: var z ss -> 2: var s rr -> 2: var rr
There are still lots of details here to be resolved (e.g. how exactly is "long int*" held?) but you should be able to see the general ideas.