"The symbol table records information about each symbol name in a program. Historically, names were called symbols, and hence we talk about a symbol table rather than a name table. It is the semantic analysis phase which creates the symbol table because it is not until the semantic analysis phase that enough information is known about a name to describe it."
---Professor Karen Lemone

By adding code to the .jjt file, we can let javacc generate the symbol table when it generates the AST. This job is an important part of semantic analysis.



In the calculator example, there is no variable declaration, and there is no variable in expression. To provide a example of symbol table in here, we will treat the integer as the symbol in our example. Here the symbol table only records the integer value and type. In the real world the symbol table must store a lot of the infomation about symbol, Such as scope,declaration line, reference line......

We add symbol table class STC.java in this example. The following is the new cal.jjt file. We will also print out the AST before we print out the "symbol table". In this cal.jjt file, we put an integer into the symbol table when javacc creates a Number node.


options {
  IGNORE_CASE = false;
  OPTIMIZE_TOKEN_MANAGER = true;
}

PARSER_BEGIN(cal)

import java.io.*;
import java.util.*;

public class cal {

  public static Hashtable ST = new Hashtable();

  public static void main(String[] args) throws ParseException,
                                                FileNotFoundException
  {
    String temp;
    STC    temp2;

    if ( args.length < 1 ) {
      System.out.println("Please pass in the filename for a parameter.");
      System.exit(1);
      }
    cal parser = new cal( new FileInputStream(args[0]) );
    SimpleNode root = parser.calculator();

    root.dump("    ");

    Enumeration t = ST.keys();

     while ( t.hasMoreElements() == true ) {

          temp = (String)t.nextElement();
          temp2 = (STC)ST.get(temp);
          System.out.println(temp);
          if ( temp2.type != null )
            System.out.println(" type = " + temp2.type);
          if ( temp2.value != null )
            System.out.println(" value = " + temp2.value);

    }

    // System.out.println("Parse completed.");
  }



} // end class cal

PARSER_END(cal)

SKIP: /* Whitespace */
 {
   "\t"
 | "\n"
 | "\r"
 | " "
 }

TOKEN:
{
  <LPAREN:    "(">
| <RPAREN:    ")">
| <ADD_OP:    "+" | "-">
| <MULT_OP:   "*" | "/">
| <NUMBER:    (["0"-"9"])+>
}


SimpleNode calculator() :
 {}
 {
   expression() 
   {return jjtThis;}
 }

 void expression() #void:
 {
 Token tok1;
 }
 {
   term() (tok1= term()
   { jjtThis.value=tok1.image; }
   #add_op(2)
   )*
 }

 void term() #void:
 {
 Token tok1;
 }
 {
   factor() (tok1=<MULT_OP> factor()
   {jjtThis.value=tok1.image;}
   #mult_op(2)
   )*


 }

 void factor() #void:
 {}
 {
  (<LPAREN> expression() <RPAREN>
 |number())

 }

 void number() :
 {
 Token tok1;
 }
 {
 tok1=<NUMBER>
  {jjtThis.value=tok1.image;
   ST.put(tok1.image,new STC("Int",tok1.image));
  }
 }

First. we use jjtree to create the cal.jj file.
Second we use javacc to create the cal.java file.
then we use javac to compile cal.java file to create cal.class.
If you run the semantic analyzer on our test.file:

test.txt
6*(11-7)/3+100

We will get the output of our semantic analyzer like this:
    calculator
         add_op(+)
              mult_op(/)
                   mult_op(*)
                        number(6)
                        add_op(-)
                             number(11)
                             number(7)
                   number(3)
              number(100)
6
 type = Int
 value = 6
3
 type = Int
 value = 3
11
 type = Int
 value = 11
100
 type = Int
 value = 100
7
 type = Int
 value = 7