Dictionary

Snap-shots of the dictionary at various points during the semantic analysis of the example program.
char		type    0   1 byte
int		type    0   4 bytes
We start with just the built-in names, at level 0.

int i;

char		type    0   1 byte
int		type    0   4 bytes
i		var     1   1   int
Global declarations are at level 1.

int count = 0;

char		type    0   1 byte
int		type    0   4 bytes
i		var     1   1   int
count		var     1   2   int   0
char * fred (char c, int i) {
char		type    0   1 byte
int		type    0   4 bytes
i		param   2   2   int		var     1   1   int
count		var     1   2   int   0
fred		fun     1   ?   char*
c		param   2   1   char
Declarations within functions are (initially) at level 2.
The eventual position of fred in the compiled code is currently unknown.
The new declaration for i, as a parameter, temporarily overrides the previous declaration as a global variable.

static int mark = 0;

char		type    0   1 byte
int		type    0   4 bytes
i		param   2   2   int		var     1   1   int
count		var     1   2   int   0
fred		fun     1   ?   char*
c		param   2   1   char
mark		var     2   1   static int   0
char * result = (char *) malloc (i + 2);
char		type    0   1 byte
int		type    0   4 bytes
i		param   2   2   int		var     1   1   int
count		var     1   2   int   0
fred		fun     1   ?   char*
c		param   2   1   char
mark		var     2   1   static int   0
result		var     2   2   char*
malloc  	fun?	1?  ?   ?
We don't have a declaration for malloc, so we have to try to construct something for it.

count += i;

At this point, for example, when we look up i, we find information describing it as a parameter of fred, rather than a global variable.
Also, when we look up count, we discover that it is a variable, so it can be assigned to, and it and i are integers, so we know what sort of addition to perform.

{ int k;

char		type    0   1 byte
int		type    0   4 bytes
i		param   2   2   int		var     1   1   int
count		var     1   2   int   0
fred		fun     1   ?   char*
c		param   2   1   char
mark		var     2   1   static int   0
result		var     2   2   char*
malloc  	fun?	1?  ?   ?
k		var     3   1   int
The inner block starts a new level, level 3.

for (k = 0; k < i; k++) result [k] = c; }

char		type    0   1 byte
int		type    0   4 bytes
i		param   2   2   int		var     1   1   int
count		var     1   2   int   0
fred		fun     1   ?   char*
c		param   2   1   char
mark		var     2   1   static int   0
result		var     2   2   char*
malloc  	fun?	1?  ?   ?
k
As we exit level 3, the variable k is no longer visible, so we detach the corresponding property from the namelist. However, we retain the namelist entry for k, as it may occur again lower down.

result [i++] = 0; result [i] = ++mark; return result; }

char		type    0   1 byte
int		type    0   4 bytes
i		var     1   1   int
count		var     1   2   int   0
fred		fun     1   ?   char*
		param   2   1   char
		param   2   2   int
c
mark
result
malloc  	fun?	1?  ?   ?
k
As we exit level 2, we discard the declarations made inside it (c, i, mark, result). In particular, we have to reconnect i to its original declaration as a global variable. We don't completely discard the entries for the parameters, as we need them to check calls to fred lower down.

int main (void) {

char		type    0   1 byte
int		type    0   4 bytes
i		var     1   1   int
count		var     1   2   int   0
fred		fun     1   ?   char*
		param   2   1   char
		param   2   2   int
c
mark
result
malloc  	fun?	1?  ?   ?
k
main		fun     1   ?   int
char * string;
char		type    0   1 byte
int		type    0   4 bytes
i		var     1   1   int
count		var     1   2   int   0
fred		fun     1   ?   char*
		param   2   1   char
		param   2   2   int
c
mark
result
malloc  	fun?	1?  ?   ?
k
main		fun     1   ?   int
string		var     2   1   char*
i = 5;

At this point, for example, when we look up i, we find information describing it as a global variable, rather than a parameter of fred.

string = fred ('a', i); printf ("%s, %d, %d\n", string, string [i+1], count);

char		type    0   1 byte
int		type    0   4 bytes
i		var     1   1   int
count		var     1   2   int   0
fred		fun     1   ?   char*
		param   2   1   char
		param   2   2   int
c
mark
result
malloc  	fun?	1?  ?   ?
k
main		fun     1   ?   int
string		var     2   1   char*
printf  	fun?	1?  ?   ?
string = fred ('b', i); printf ("%s, %d, %d\n", string, string [i+1], count); return 0; }
char		type    0   1 byte
int		type    0   4 bytes
i		var     1   1   int
count		var     1   2   int   0
fred		fun     1   ?   char*
		param   2   1   char
		param   2   2   int
c
mark
result
malloc  	fun?	1?  ?   ?
k
main		fun     1   ?   int
string
printf  	fun?	1?  ?   ?