The semantic analyzer is the last part of the front end of a compiler. Before the compiler can produce an executable version of the code, it must build up a large base of knowledge about the details encoded in the program. The input to the semantic analyzer phase is the parsed program produced by the parser, Our semantic analyzer creates an abstract syntax tree for the soure code.
To generate the semantic analyer, first, we need to use jjtree to create the .jj file, Then we use this .jj file as the input file to javacc to create the semantic analyzer.



Here is the cal.jjt file.
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.
Finallly. we run our semantic analyzer on our test file. we will get a AST of the expression.

options {
  IGNORE_CASE = false;
  OPTIMIZE_TOKEN_MANAGER = true;
}

PARSER_BEGIN(cal)

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

public class cal {



  public static void main(String[] args) throws ParseException,
                                                FileNotFoundException
  {

    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("     ");


    // 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() <EOF>
   {return jjtThis;}
 }

 void expression() #void:
 {
 Token tok1;
 }
 {
   term() (tok1=<ADD_OP> 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;}
 }


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)


The following is the same AST as the output.