Example fragment of C:
int i; float j; float f (int i) {int k; float r; k= i*j; r= k; return r;}
After lexical analysis - corresponding lexemes and namelist:
(int, -) int (id, -> i in namelist) float (;, -) f (float, -) i (id, -> j in namelist) j (;, -) k etc. r
After syntactic analysis - corresponding parse tree:
program | decl--------var | [int, *->i] | decl--------var | [float, *->j] | decl--------func--------+----------------------+ [float, *->f] decl-------param exp--------[=] | [int,*->i] | [*->k] [*] | | [*->i] [*->j] decl-------var | | [int,*->k] exp--------[=] | | [*->r] [*->k] decl-------var | [float,*->r] return-----[*->r](as in lexemes, identifiers are pointers to entries in the namelist.)
After semantic analysis - enhanced parse tree:
program[2 vars] | decl--func----+ [*->f] exp--------[I,=] | [F,->I] | [I,*->k] [F,*] | [I->F] | [I,*->i] [F,*->j] | exp--------[F,=] | [I->F] | [F,*->r] [I,*->k] | return-----[F,*->r](identifiers have become pointers to property entries.) (F short for float, I for int)
Possible dictionary for example C program:
int [type | int] <--I float [type | float] <--F f [func | global | ? | 1 param | 2 vars | *->F] i [param | local | 1 | *->I] [var | global | 1 | *->I] j [var | global | 2 | *->F] k [var | local | 1 | *->I] r [var | local | 2 | *->F]