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;
}
We start with just the built-in names, at level 0.
| char |
|
| int |
|
Global declarations are at level 1.
int i;
| char |
|
| int |
|
| i |
|
int count = 0;
| char |
|
| int |
|
| i |
|
| count |
|
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 (global variable).
char * fred (char c, int i)
{
| char |
|
|
| int |
|
|
| i |
|
|
| count |
|
|
| fred |
|
|
| c |
|
static int mark = 0;
| char |
|
|
| int |
|
|
| i |
|
|
| count |
|
|
| fred |
|
|
| c |
|
|
| mark |
|
char * result = (char *) malloc (i + 2);
| char |
|
|
| int |
|
|
| i |
|
|
| count |
|
|
| fred |
|
|
| c |
|
|
| mark |
|
|
| result |
|
|
| malloc |
|
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.
The inner block starts a new level, level 3.
{
int k;
| char |
|
|
| int |
|
|
| i |
|
|
| count |
|
|
| fred |
|
|
| c |
|
|
| mark |
|
|
| result |
|
|
| malloc |
|
|
| k |
|
for (k = 0; k < i; k++)
result [k] = c;
}
| char |
|
|
| int |
|
|
| i |
|
|
| count |
|
|
| fred |
|
|
| c |
|
|
| mark |
|
|
| result |
|
|
| malloc |
|
|
| 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 |
|
| int |
|
| i |
|
| count |
|
| fred |
|
|
|
|
|
|
|
| c | |
| mark | |
| result | |
| malloc |
|
| 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 |
|
||
| int |
|
||
| i |
|
||
| count |
|
||
| fred |
|
|
|
| c | |||
| mark | |||
| result | |||
| malloc |
|
||
| k | |||
| main |
|
char * string;
| char |
|
||
| int |
|
||
| i |
|
||
| count |
|
||
| fred |
|
|
|
| c | |||
| mark | |||
| result | |||
| malloc |
|
||
| k | |||
| main |
|
||
| string |
|
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 |
|
||
| int |
|
||
| i |
|
||
| count |
|
||
| fred |
|
|
|
| c | |||
| mark | |||
| result | |||
| malloc |
|
||
| k | |||
| main |
|
||
| string |
|
||
| printf |
|
string = fred ('b', i);
printf ("%s, %d, %d\n", string, string [i+1], count);
return 0;
}
| char |
|
||
| int |
|
||
| i |
|
||
| count |
|
||
| fred |
|
|
|
| c | |||
| mark | |||
| result | |||
| malloc |
|
||
| k | |||
| main |
|
||
| string | |||
| printf |
|
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