Sample answers to the imperative languages assignment

The assignment was to explore the capabilities of C to reproduce the block structuring scope rules of Pascal. The table below summarizes the valid and invalid calls among the functions in parts 1, 2 and 3 of the question.

Part 1 Part 2 Part 3

calls -->f1f2f3f4f5
f1YesYesYesNoYes
f2YesYesNoYesNo
f3YesYesYesNoYes
f4YesYesNoYesNo
f5YesYesYesNoYes

Part 1

Only one file is needed. A good solution is:

void f1();
void f2() {...}
void f3() {...}
void f1() {...}

but better is:

void f1();
void f2() {...}
static void f3() {...}
void f1() {...}

since any call to f3 in the body of f2 would be implicitly be declared extern, which then clashes with the static definition.

Part 2

Two files are needed:

file 1:file 2:

extern void f2();
void f1();
static void f3() {...}
void f1() {...}

extern void f1();
void f2();
static void f4() {...}
void f2() {...}

A three file version is not quite as good:

file 1:file 2:file 3:

extern void f2();
extern void f3();
void f1() {...}

extern f1();
void f2();
static void f4() {...}
void f2() {...}

extern void f1();
extern void f2();
void f3() {...}

since the linker will allow both f2 and f4 to call f3, even though it is not declared in file 2.

Part 3

This turned out to be possible, even though an argument can be made that it should be impossible. A three file version is:

file 1:file 2:file 3:

extern void f2();
extern void f3();
void f1() {...}

extern f1();
void f2();
static void f4() {...}
void f2() {...}

extern void f1();
extern void f2();
void f3();
static void f5() {...}
void f3() {...}

The problem here is that f2 and f4 can still call f3 through the linker mechanism with implict definitions. The best solution only has two files:

file 1:file 2:

extern void f2();
static void f3();
void f1() {...}
static void f5() {...}
static void f3() {...}

extern void f1();
void f2();
static void f4() {...}
void f2() {...}

Part 4

To turn the original Pascal into Modula 2, while preserving the valid and invalid calls, separate f2 and f3 in different modules:

definition module M1;
	export f1;
	import f2 from M2;
	procedure f3;	{ so that f1 can call f3 }
end;

implementation module M1;
	procedure f1;
	begin
		...
	end;
	procedure f3;
	begin
		...
	end;
end;

definition module M2;
	export f2;
	import f1 from M1;
end;

implementation module M2;
	procedure f2;
	begin
		...
	end;
end;