CS5031 Exercises 4: Semantics

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.