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