def write_formula(*args)
    # Check for a cell reference in A1 notation and substitute row and column
    args = row_col_notation(args)

    return -1 if args.size < 3   # Check the number of args

    row, col, formula, format, value = args

    # Check that row and col are valid and store max and min values
    return -2 unless check_dimensions(row, col) == 0

    xf        = xf_record_index(row, col, format)  # The cell format

    # Strip the = sign at the beginning of the formula string
    formula = formula.sub(/^=/, '')

    # Parse the formula using the parser in Formula.pm
    # nakamura add:  to get byte_stream, set second arg TRUE
    # because ruby doesn't have Perl's "wantarray"
    formula = parser.parse_formula(formula, true)

    store_formula_common(row, col, xf, value, formula)
    0
  end
def write_formula(*args)
    # Check for a cell reference in A1 notation and substitute row and column
    args = row_col_notation(args)

    return -1 if args.size < 3   # Check the number of args

    row, col, formula, format, value = args

    # Check that row and col are valid and store max and min values
    return -2 unless check_dimensions(row, col) == 0

    xf        = xf_record_index(row, col, format)  # The cell format

    # Strip the = sign at the beginning of the formula string
    formula = formula.sub(/^=/, '')

    # Parse the formula using the parser in Formula.pm
    # nakamura add:  to get byte_stream, set second arg TRUE
    # because ruby doesn't have Perl's "wantarray"
    formula = parser.parse_formula(formula, true)

    store_formula_common(row, col, xf, value, formula)
    0
  end
:call-seq:
   write_formula(row, col   , formula[, format, value])  -> Fixnum
   write_formula(A1_notation, formula[, format, value])  -> Fixnum

 Write a formula to the specified row and column (zero indexed).

 format is optional.
 value is an optional result of the formula that can be supplied by the
 user.

 Returns  0 : normal termination
         -1 : insufficient number of arguments
         -2 : row or column out of range

 Write a formula or function to the cell specified by row and column:

     worksheet.write_formula(0, 0, '=$B$3 + B4'  )
     worksheet.write_formula(1, 0, '=SIN(PI()/4)')
     worksheet.write_formula(2, 0, '=SUM(B1:B5)' )
     worksheet.write_formula('A4', '=IF(A3>1,"Yes", "No")'   )
     worksheet.write_formula('A5', '=AVERAGE(1, 2, 3, 4)'    )
     worksheet.write_formula('A6', '=DATEVALUE("1-Jan-2001")')

 See the note about "Cell notation". For more information about writing
 Excel formulas see "FORMULAS AND FUNCTIONS IN EXCEL"

 See also the section "Improving performance when working with formulas"
 and the store_formula() and repeat_formula() methods.

 If required, it is also possible to specify the calculated value of the
 formula. This is occasionally necessary when working with non-Excel
 applications that don't calculated the value of the formula. The
 calculated value is added at the end of the argument list:

     worksheet.write('A1', '=2+2', format, 4);

 However, this probably isn't something that will ever need to do. If you
 do use this feature then do so with care.

 =FORMULAS AND FUNCTIONS IN EXCEL

 ==Caveats

 The first thing to note is that there are still some outstanding issues
 with the implementation of formulas and functions:

     1. Writing a formula is much slower than writing the equivalent string.
     2. You cannot use array constants, i.e. {1;2;3}, in functions.
     3. Unary minus isn't supported.
     4. Whitespace is not preserved around operators.
     5. Named ranges are not supported.
     6. Array formulas are not supported.

 However, these constraints will be removed in future versions. They are
 here because of a trade-off between features and time. Also, it is possible
 to work around issue 1 using the store_formula() and repeat_formula()
 methods as described later in this section.

 ==Introduction

 The following is a brief introduction to formulas and functions in Excel
 and WriteExcel.

 A formula is a string that begins with an equals sign:

     '=A1+B1'
     '=AVERAGE(1, 2, 3)'

 The formula can contain numbers, strings, boolean values, cell references,
 cell ranges and functions. Named ranges are not supported. Formulas should
 be written as they appear in Excel, that is cells and functions must be
 in uppercase.

 Cells in Excel are referenced using the A1 notation system where the column
 is designated by a letter and the row by a number. Columns range from A to
 IV i.e. 0 to 255, rows range from 1 to 65536.

 The Excel $ notation in cell references is also supported. This allows you
 to specify whether a row or column is relative or absolute. This only has
 an effect if the cell is copied. The following examples show relative and
 absolute values.

     '=A1'   # Column and row are relative
     '=$A1'  # Column is absolute and row is relative
     '=A$1'  # Column is relative and row is absolute
     '=$A$1' # Column and row are absolute

 Formulas can also refer to cells in other worksheets of the current
 workbook. For example:

     '=Sheet2!A1'
     '=Sheet2!A1:A5'
     '=Sheet2:Sheet3!A1'
     '=Sheet2:Sheet3!A1:A5'
     %q{='Test Data'!A1}
     %q{='Test Data1:Test Data2'!A1}

 The sheet reference and the cell reference are separated by ! the exclamation
 mark symbol. If worksheet names contain spaces, commas o parentheses then
 Excel requires that the name is enclosed in single quotes as shown in the
 last two examples above. In order to avoid using a lot of escape characters
 you can use the quote operator %q{} to protect the quotes. See perlop in
 the main Perl documentation. Only valid sheet names that have been added
 using the add_worksheet() method can be used in formulas. You cannot
 reference external workbooks.

 The following table lists the operators that are available in Excel's
 formulas. The majority of the operators are the same as Perl's,
 differences are indicated:

     Arithmetic operators:
     =====================
     Operator  Meaning                   Example
        +      Addition                  1+2
        -      Subtraction               2-1
        *      Multiplication            2*3
        /      Division                  1/4
        ^      Exponentiation            2^3      # Equivalent to **
        -      Unary minus               -(1+2)   # Not yet supported
        %      Percent (Not modulus)     13%      # Not supported, [1]


     Comparison operators:
     =====================
     Operator  Meaning                   Example
         =     Equal to                  A1 =  B1 # Equivalent to ==
         <>    Not equal to              A1 <> B1 # Equivalent to !=
         >     Greater than              A1 >  B1
         <     Less than                 A1 <  B1
         >=    Greater than or equal to  A1 >= B1
         <=    Less than or equal to     A1 <= B1


     String operator:
     ================
     Operator  Meaning                   Example
         &     Concatenation             "Hello " & "World!" # [2]


     Reference operators:
     ====================
     Operator  Meaning                   Example
         :     Range operator            A1:A4               # [3]
         ,     Union operator            SUM(1, 2+2, B3)     # [4]


     Notes:
     [1]: You can get a percentage with formatting and modulus with MOD().
     [2]: Equivalent to ("Hello " . "World!") in Perl.
     [3]: This range is equivalent to cells A1, A2, A3 and A4.
     [4]: The comma behaves like the list separator in Perl.

 The range and comma operators can have different symbols in non-English
 versions of Excel. These will be supported in a later version of
 WriteExcel. European users of Excel take note:

     worksheet.write('A1', '=SUM(1; 2; 3)')  # Wrong!!
     worksheet.write('A1', '=SUM(1, 2, 3)')  # Okay

 The following table lists all of the core functions supported by Excel 5
 and WriteExcel. Any additional functions that are available through the
 "Analysis ToolPak" or other add-ins are not supported. These functions
 have all been tested to verify that they work.

     ABS           DB            INDIRECT      NORMINV       SLN
     ACOS          DCOUNT        INFO          NORMSDIST     SLOPE
     ACOSH         DCOUNTA       INT           NORMSINV      SMALL
     ADDRESS       DDB           INTERCEPT     NOT           SQRT
     AND           DEGREES       IPMT          NOW           STANDARDIZE
     AREAS         DEVSQ         IRR           NPER          STDEV
     ASIN          DGET          ISBLANK       NPV           STDEVP
     ASINH         DMAX          ISERR         ODD           STEYX
     ATAN          DMIN          ISERROR       OFFSET        SUBSTITUTE
     ATAN2         DOLLAR        ISLOGICAL     OR            SUBTOTAL
     ATANH         DPRODUCT      ISNA          PEARSON       SUM
     AVEDEV        DSTDEV        ISNONTEXT     PERCENTILE    SUMIF
     AVERAGE       DSTDEVP       ISNUMBER      PERCENTRANK   SUMPRODUCT
     BETADIST      DSUM          ISREF         PERMUT        SUMSQ
     BETAINV       DVAR          ISTEXT        PI            SUMX2MY2
     BINOMDIST     DVARP         KURT          PMT           SUMX2PY2
     CALL          ERROR.TYPE    LARGE         POISSON       SUMXMY2
     CEILING       EVEN          LEFT          POWER         SYD
     CELL          EXACT         LEN           PPMT          T
     CHAR          EXP           LINEST        PROB          TAN
     CHIDIST       EXPONDIST     LN            PRODUCT       TANH
     CHIINV        FACT          LOG           PROPER        TDIST
     CHITEST       FALSE         LOG10         PV            TEXT
     CHOOSE        FDIST         LOGEST        QUARTILE      TIME
     CLEAN         FIND          LOGINV        RADIANS       TIMEVALUE
     CODE          FINV          LOGNORMDIST   RAND          TINV
     COLUMN        FISHER        LOOKUP        RANK          TODAY
     COLUMNS       FISHERINV     LOWER         RATE          TRANSPOSE
     COMBIN        FIXED         MATCH         REGISTER.ID   TREND
     CONCATENATE   FLOOR         MAX           REPLACE       TRIM
     CONFIDENCE    FORECAST      MDETERM       REPT          TRIMMEAN
     CORREL        FREQUENCY     MEDIAN        RIGHT         TRUE
     COS           FTEST         MID           ROMAN         TRUNC
     COSH          FV            MIN           ROUND         TTEST
     COUNT         GAMMADIST     MINUTE        ROUNDDOWN     TYPE
     COUNTA        GAMMAINV      MINVERSE      ROUNDUP       UPPER
     COUNTBLANK    GAMMALN       MIRR          ROW           VALUE
     COUNTIF       GEOMEAN       MMULT         ROWS          VAR
     COVAR         GROWTH        MOD           RSQ           VARP
     CRITBINOM     HARMEAN       MODE          SEARCH        VDB
     DATE          HLOOKUP       MONTH         SECOND        VLOOKUP
     DATEVALUE     HOUR          N             SIGN          WEEKDAY
     DAVERAGE      HYPGEOMDIST   NA            SIN           WEIBULL
     DAY           IF            NEGBINOMDIST  SINH          YEAR
     DAYS360       INDEX         NORMDIST      SKEW          ZTEST

 --
 You can also modify the module to support function names in the following
 languages: German, French, Spanish, Portuguese, Dutch, Finnish, Italian
 and Swedish. See the function_locale.pl program in the examples
 directory of the distro.
 ++

 For a general introduction to Excel's formulas and an explanation of
 the syntax of the function refer to the Excel help files or the
 following: http://office.microsoft.com/en-us/assistance/CH062528031033.aspx

 If your formula doesn't work in WriteExcel try the following:

     1. Verify that the formula works in Excel (or Gnumeric or OpenOffice.org).
     2. Ensure that it isn't on the Caveats list shown above.
     3. Ensure that cell references and formula names are in uppercase.
     4. Ensure that you are using ':' as the range operator, A1:A4.
     5. Ensure that you are using ',' as the union operator, SUM(1,2,3).
     6. Ensure that the function is in the above table.

 If you go through steps 1-6 and you still have a problem, mail me.

 ==Improving performance when working with formulas

 Writing a large number of formulas with WriteExcel can be
 slow. This is due to the fact that each formula has to be parsed and
 with the current implementation this is computationally expensive.

 However, in a lot of cases the formulas that you write will be quite
 similar, for example:

     worksheet.write_formula('B1',    '=A1 * 3 + 50',    format)
     worksheet.write_formula('B2',    '=A2 * 3 + 50',    format)
     ...
     ...
     worksheet.write_formula('B99',   '=A999 * 3 + 50',  format)
     worksheet.write_formula('B1000', '=A1000 * 3 + 50', format)

 In this example the cell reference changes in iterations from A1 to A1000.
 The parser treats this variable as a token and arranges it according to
 predefined rules. However, since the parser is oblivious to the value of
 the token, it is essentially performing the same calculation 1000 times.
 This is inefficient.

 The way to avoid this inefficiency and thereby speed up the writing of
 formulas is to parse the formula once and then repeatedly substitute
 similar tokens.

 A formula can be parsed and stored via the store_formula() worksheet
 method. You can then use the repeat_formula() method to substitute
 _pattern_, _replace_ pairs in the stored formula:

     formula = worksheet.store_formula('=A1 * 3 + 50')

     (0...1000).each do |row|
        worksheet.repeat_formula(row, 1, formula, format, 'A1', 'A'.(row +1))
     end

 On an arbitrary test machine this method was 10 times faster than the
 brute force method shown above.
 --
 For more information about how WriteExcel parses and stores formulas see
 the WriteExcel::Formula man page.

 It should be noted however that the overall speed of direct formula
 parsing will be improved in a future version.
 ++