next up previous contents
Next: CS2111: Design and Implementation Up: CS2111: Design and Implementation Previous: Example run of yacc   Contents

Subsections

A larger example illustrating the Phases of Compilation

Example C program


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;
}

Dictionary


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?  ?   ?

Parse Tree


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


next up previous contents
Next: CS2111: Design and Implementation Up: CS2111: Design and Implementation Previous: Example run of yacc   Contents
Pete Jinks
1999-09-30