    private Expr orExpr() {
      /*  
        OrExpr ::= AndExpr [ "or" AndExpr ]
      */
      
      Expr left, right;
      left = andExpr();
      if ( lexer.token == Symbol.OU) {
        lexer.nextToken();
        right = andExpr();
          // add semantic analysis
        left = new CompositeExpr(left, Symbol.OR, right);
      }
      return left;
    }

    
    private Expr andExpr() {
      /*
        AndExpr ::= RelExpr [ "and" RelExpr ]
      */
      Expr left, right;
      left = relExpr();
      if ( lexer.token == Symbol.E) {
        lexer.nextToken();
        right = relExpr();
          // add semantic analysis
        left = new CompositeExpr( left, Symbol.AND, right );
      }
      return left;
    }

    private Expr relExpr() {
      /*
        RelExpr ::= AddExpr [ RelOp AddExpr ]
      */
      Expr left, right;
      left = addExpr();
      int op = lexer.token;
      if ( op == Symbol.EQ || op == Symbol.NEQ || op == Symbol.LE || op == Symbol.LT ||
           op == Symbol.GE || op == Symbol.GT  ) {
         lexer.nextToken();
         right = addExpr();
           // add semantic analysis
         left = new CompositeExpr( left, op, right );
       }
       return left;
    }

    
    private Expr addExpr() {
      /*
        AddExpr ::= MultExpr { AddOp MultExpr }
        
      */
      int op;
      Expr left, right;
      left = multExpr();
      while ( (op = lexer.token) == Symbol.PLUS ||
              op == Symbol.MINUS ) {
        lexer.nextToken();
        right = multExpr();
          // add semantic analysis
        left = new CompositeExpr( left, op, right );
      }
      return left;
    }
       
       
    private Expr multExpr() {
     /*
        MultExpr ::= SimpleExpr { MultOp SimpleExpr }
     */    
       Expr left, right;
       left = simpleExpr();
       int op;
       while ( (op = lexer.token) == Symbol.MULT ||
               op == Symbol.DIV || op == Symbol.REMAINDER ) {
          lexer.nextToken();
          right = simpleExpr();
            // add semantic analysis
          left = new CompositeExpr( left, op, right );
       }
       return left;
    }
           
    private Expr simpleExpr() {
      /*
        SimpleExpr ::= Number |  "true" | "false" | Character 
           | '(' Expr ')' | "not" SimpleExpr | Variable 
      */
      
      Expr e;
      
        // note we test the lexer.token to decide which production to use
      switch ( lexer.token ) {
         case Symbol.NUMBER :
            return number();
         case Symbol.VERDADEIRO:
           lexer.nextToken();
           return BooleanExpr.True;
         case Symbol.FALSO :
           lexer.nextToken();
           return BooleanExpr.False;
         case Symbol.LEFTPAR :
           lexer.nextToken();
           e = orExpr();
           if ( lexer.token != Symbol.RIGHTPAR ) {
             error.show(") expected");
           }
           else
             lexer.nextToken();
           return new ParenthesisExpr(e);
         case Symbol.NAO :
           lexer.nextToken();
           e = orExpr();
             // add semantic analysis
           return new UnaryExpr( e, Symbol.NOT );
         case Symbol.PLUS :
           lexer.nextToken();
           e = orExpr();
             // add semantic analysis
           return new UnaryExpr( e, Symbol.PLUS );
         case Symbol.MINUS :
           lexer.nextToken();
           e = orExpr();
             // add semantic analysis
           return new UnaryExpr( e, Symbol.MINUS );
         default :
             // an identifier
           if ( lexer.token != Symbol.IDENT ) 
             error.show("Identifier expected");
           else {
             String name = (String ) lexer.getStringValue();
             Variable v = symbolTable.get(name);
             // add semantic analysis
             lexer.nextToken();
             return new VariableExpr(v);
           }
      }
            
    }
    
    
    private NumberExpr number() {
        
        NumberExpr e = null;
        
          // the number value is stored in lexer.getToken().value as an object of Integer.
          // Method intValue returns that value as an value of type int.
        int value = lexer.getNumberValue();
        lexer.nextToken();
        return new NumberExpr( value );
    }
    
    
