int i;
int count = 0;
char * fred (char c, int i)
{
static int mark = 0;
char * result = (char *) malloc (i + 2);
count += i;
{
int k;
for (k = 0; k < i; k++)
result [k] = c;
}
result [i++] = 0;
result [i] = ++mark;
return result;
}
int main (void)
{
char * string;
i = 5;
string = fred ('a', i);
printf ("%s, %d, %d\n", string, string [i+1], count);
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*
c param 2 1 char
param 2 2 int
mark var 2 1 static int 0
result var 2 2 char*
malloc fun? 1? ? ?
k var 3 1 int
main fun 1 ? int
string var 2 1 char*
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 name-list. However, we retain the name-list 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? ? ?
int i
int count 0
char*() fred
() char c
int i
{} st.int mark 0
char* result (char*) malloc + i
2
+= count
i
{} int k
for = k
0
< k
i
post++ k
= [] result
k
c
= [] result
post++ i
0
= [] result
i
pre++ mark
return result
int() main
() void
{} char* string
= i
5
= string
fred 'a'
i
printf "%s, %d, %d\en"
string
[] string
+ i
1
count
= string
fred 'b'
i
printf "%s, %d, %d\en"
string
[] string
+ i
1
count
return 0